diff --git a/BUILD.gn b/BUILD.gn index 4d24b422ba61963da33f9067e4f9810327753ac8..e9b70a860577dac4adaa2b282bf706fa7dd4dc3a 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -76,6 +76,7 @@ group("ark_js_host_linux_tools_packages") { deps += [ "ecmascript/compiler:ark_aot_compiler(${host_toolchain})", "ecmascript/compiler:ark_stub_compiler(${host_toolchain})", + "ecmascript/compiler:libark_jsoptimizer(${host_toolchain})", "ecmascript/pgo_profiler/prof_dump:profdump(${host_toolchain})", ] } @@ -204,7 +205,6 @@ group("ark_runtime_host_unittest") { #"$js_root/test/moduletest:ark_asm_single_step_test", "$js_root/test/deopttest:ark_deopt_test", "$js_root/test/moduletest:ark_asm_test", - "$js_root/test/typeinfer:ark_typeinfer_test", ] if (is_mac) { @@ -280,6 +280,9 @@ config("hiviewdfx_config") { if (enable_hilog) { defines += [ "ENABLE_HILOG" ] } + if (enable_hisysevent) { + defines += [ "ENABLE_HISYSEVENT" ] + } include_dirs = [ "$hilog_root/include" ] } @@ -405,6 +408,10 @@ config("ark_jsruntime_common_config") { ldflags += [ "-flto=thin" ] } + if (use_libfuzzer) { + defines += [ "FUZZ_TEST" ] + } + if (is_debug) { cflags_cc += [ "-O0", @@ -551,6 +558,7 @@ ecma_source = [ "ecmascript/base/array_helper.cpp", "ecmascript/base/atomic_helper.cpp", "ecmascript/base/builtins_base.cpp", + "ecmascript/base/dtoa_helper.cpp", "ecmascript/base/error_helper.cpp", "ecmascript/base/fast_json_stringifier.cpp", "ecmascript/base/json_helper.cpp", @@ -564,6 +572,8 @@ ecma_source = [ "ecmascript/builtins/builtins.cpp", "ecmascript/builtins/builtins_ark_tools.cpp", "ecmascript/builtins/builtins_array.cpp", + "ecmascript/builtins/builtins_shared_array.cpp", + "ecmascript/builtins/builtins_sendable_arraybuffer.cpp", "ecmascript/builtins/builtins_arraybuffer.cpp", "ecmascript/builtins/builtins_async_from_sync_iterator.cpp", "ecmascript/builtins/builtins_async_function.cpp", @@ -598,6 +608,9 @@ ecma_source = [ "ecmascript/builtins/builtins_shared_function.cpp", "ecmascript/builtins/builtins_string_iterator.cpp", "ecmascript/builtins/builtins_shared_object.cpp", + "ecmascript/builtins/builtins_shared_set.cpp", + "ecmascript/builtins/builtins_shared_map.cpp", + "ecmascript/builtins/builtins_shared_typedarray.cpp", "ecmascript/builtins/builtins_symbol.cpp", "ecmascript/builtins/builtins_typedarray.cpp", "ecmascript/builtins/builtins_weak_map.cpp", @@ -722,7 +735,9 @@ ecma_source = [ "ecmascript/js_api/js_api_vector_iterator.cpp", "ecmascript/js_arguments.cpp", "ecmascript/js_array.cpp", + "ecmascript/shared_objects/js_shared_array.cpp", "ecmascript/js_array_iterator.cpp", + "ecmascript/shared_objects/js_shared_array_iterator.cpp", "ecmascript/js_arraybuffer.cpp", "ecmascript/js_async_from_sync_iterator.cpp", "ecmascript/js_async_function.cpp", @@ -739,6 +754,7 @@ ecma_source = [ "ecmascript/js_iterator.cpp", "ecmascript/js_map.cpp", "ecmascript/js_map_iterator.cpp", + "ecmascript/jsnapi_sendable.cpp", "ecmascript/method.cpp", "ecmascript/js_object.cpp", "ecmascript/js_primitive_ref.cpp", @@ -768,6 +784,7 @@ ecma_source = [ "ecmascript/mem/free_object_list.cpp", "ecmascript/mem/free_object_set.cpp", "ecmascript/mem/gc_stats.cpp", + "ecmascript/mem/gc_key_stats.cpp", "ecmascript/mem/heap.cpp", "ecmascript/mem/heap_region_allocator.cpp", "ecmascript/mem/incremental_marker.cpp", @@ -824,6 +841,11 @@ ecma_source = [ "ecmascript/serializer/base_serializer.cpp", "ecmascript/serializer/value_serializer.cpp", "ecmascript/shared_object_factory.cpp", + "ecmascript/shared_objects/js_shared_map.cpp", + "ecmascript/shared_objects/js_shared_map_iterator.cpp", + "ecmascript/shared_objects/js_shared_set.cpp", + "ecmascript/shared_objects/js_shared_set_iterator.cpp", + "ecmascript/shared_objects/js_sendable_arraybuffer.cpp", "ecmascript/stackmap/ark_stackmap_builder.cpp", "ecmascript/stackmap/ark_stackmap_parser.cpp", "ecmascript/stackmap/litecg/litecg_stackmap_type.cpp", @@ -1075,19 +1097,20 @@ ohos_source_set("libark_jsruntime_test_set") { "/system/lib64/${arkcompiler_relative_lib_path}/lib_ark_builtins.d.abc" defines += [ "TARGET_BUILTINS_DTS_PATH=\"${target_builtins_dts_path}\"" ] + deps = [] + external_deps = [] if (defined(is_arkui_x) && is_arkui_x) { - deps = [ + deps += [ "$ark_third_party_root/icu/icu4c:static_icui18n", "$ark_third_party_root/icu/icu4c:static_icuuc", ] } else { - deps = [ - "$ark_third_party_root/icu/icu4c:shared_icui18n", - "$ark_third_party_root/icu/icu4c:shared_icuuc", + external_deps += [ + "icu:shared_icui18n", + "icu:shared_icuuc", ] } - external_deps = [] if (enable_dump_in_faultlog) { external_deps += [ "libuv:uv" ] } @@ -1180,11 +1203,14 @@ ohos_shared_library("libark_jsruntime") { } } - deps = [ - ":libark_jsruntime_static", - sdk_libc_secshared_dep, - ] + deps = [ ":libark_jsruntime_static" ] external_deps = [] + if (defined(is_arkui_x) && is_arkui_x && target_os == "ios") { + deps += [ "$ark_third_party_root/bounds_checking_function:libsec_static" ] + } else { + external_deps += [ "bounds_checking_function:libsec_shared" ] + } + if (!is_arkui_x) { external_deps += [ "runtime_core:libarkfile_static" ] } else { @@ -1192,6 +1218,7 @@ ohos_shared_library("libark_jsruntime") { } all_dependent_configs = [ ":ark_jsruntime_public_config" ] + public_configs = [ ":ark_jsruntime_public_config" ] if (is_ohos && is_standard_system && !is_debug) { version_script = "libark_jsruntime.map" @@ -1224,9 +1251,9 @@ ohos_shared_library("libark_jsruntime") { "$ark_third_party_root/icu/icu4c:static_icuuc", ] } else { - deps += [ - "$ark_third_party_root/icu/icu4c:shared_icui18n", - "$ark_third_party_root/icu/icu4c:shared_icuuc", + external_deps += [ + "icu:shared_icui18n", + "icu:shared_icuuc", ] } innerapi_tags = [ "platformsdk_indirect" ] @@ -1236,14 +1263,15 @@ ohos_shared_library("libark_jsruntime") { ohos_shared_library("libark_jsruntime_test") { stack_protector_ret = false - deps = [ - ":libark_jsruntime_test_set", - "$ark_root/libpandafile:libarkfile_static", - ] - + deps = [ ":libark_jsruntime_test_set" ] + external_deps = [ "runtime_core:libarkfile_static" ] public_configs = [ "$js_root:ark_jsruntime_public_config" ] public_configs += [ ":include_llvm" ] + if (enable_hilog) { + external_deps += [ "hilog:libhilog" ] + } + ldflags = [] if (enable_coverage) { ldflags += [ "--coverage" ] @@ -1257,7 +1285,10 @@ ohos_shared_library("libark_jsruntime_test") { if (!is_mingw && !is_mac) { output_extension = "so" } - subsystem_name = "test" + + # Set the subsystem name + part_name = "ets_runtime" + subsystem_name = "arkcompiler" } ohos_prebuilt_etc("app_aot_enable_list") { diff --git a/bundle.json b/bundle.json index 0990940efbad1b1f45710199e511921d724a6634..ddeefe66cead1c4ccff2be1ad87e4b54b94d572d 100644 --- a/bundle.json +++ b/bundle.json @@ -20,22 +20,26 @@ ], "rom": "20MB", "ram": "~8000KB", + "hisysevent_config": [ + "//arkcompiler/ets_runtime/hisysevent.yaml" + ], "deps": { "components": [ "faultloggerd", "init", "hitrace", "hilog", + "hisysevent", "qos_manager", "runtime_core", "c_utils", "code_signature", "libuv", - "zlib" - ], - "third_party": [ + "zlib", "bounds_checking_function", "icu" + ], + "third_party": [ ] }, "build": { diff --git a/ecmascript/accessor_data.h b/ecmascript/accessor_data.h index 4d9e876e5bf0f6ed2d89a3eede68d7ef8904a934..8889fe571f4abf2adb2ce7d34ddb7757d02186ff 100644 --- a/ecmascript/accessor_data.h +++ b/ecmascript/accessor_data.h @@ -19,6 +19,7 @@ #include "ecmascript/ecma_macros.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_native_pointer.h" +#include "ecmascript/js_object.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/mem/slots.h" #include "ecmascript/mem/visitor.h" diff --git a/ecmascript/base/array_helper.cpp b/ecmascript/base/array_helper.cpp index 67ad96359a718be3a1e05e21bbdf44e8b50f82be..5ca42c09268eb20f8c4d800069252e42ae8a24af 100644 --- a/ecmascript/base/array_helper.cpp +++ b/ecmascript/base/array_helper.cpp @@ -25,6 +25,7 @@ #include "ecmascript/js_tagged_number.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/object_fast_operator-inl.h" +#include "ecmascript/shared_objects/js_shared_array.h" namespace panda::ecmascript::base { int64_t ArrayHelper::GetStartIndex(JSThread *thread, const JSHandle &startIndexHandle, @@ -143,7 +144,7 @@ bool ArrayHelper::IsConcatSpreadable(JSThread *thread, const JSHandleIsArray(thread); + return obj->IsArray(thread) || obj->IsJSSharedArray(); } // must use 'double' as return type, for sort result may double. @@ -250,6 +251,9 @@ int64_t ArrayHelper::GetLength(JSThread *thread, const JSHandle & if (thisHandle->IsJSArray()) { return JSArray::Cast(thisHandle->GetTaggedObject())->GetArrayLength(); } + if (thisHandle->IsJSSharedArray()) { + return JSSharedArray::Cast(thisHandle->GetTaggedObject())->GetArrayLength(); + } if (thisHandle->IsTypedArray()) { return JSHandle::Cast(thisHandle)->GetArrayLength(); } @@ -266,6 +270,9 @@ int64_t ArrayHelper::GetArrayLength(JSThread *thread, const JSHandleIsJSArray()) { return JSArray::Cast(thisHandle->GetTaggedObject())->GetArrayLength(); } + if (thisHandle->IsJSSharedArray()) { + return JSSharedArray::Cast(thisHandle->GetTaggedObject())->GetArrayLength(); + } JSHandle lengthKey = thread->GlobalConstants()->GetHandledLengthString(); JSHandle lenResult = JSTaggedValue::GetProperty(thread, thisHandle, lengthKey).GetValue(); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0); @@ -279,7 +286,7 @@ JSTaggedValue ArrayHelper::FlattenIntoArray(JSThread *thread, const JSHandle &mapperFunctionHandle, const JSHandle &thisArg) { - if (thread->DoAsmStackOverflowCheck()) { + if (thread->DoStackLimitCheck()) { return JSTaggedValue::Exception(); } // 1. Assert: Type(target) is Object. diff --git a/ecmascript/base/array_helper.h b/ecmascript/base/array_helper.h index 7417bbd0cfbb76e00a26b8511a4e4af225957c50..eeffa204ca44ed3043adbcb6286134ac9106b612 100644 --- a/ecmascript/base/array_helper.h +++ b/ecmascript/base/array_helper.h @@ -64,7 +64,7 @@ public: const JSHandle &valueX, const JSHandle &valueY); static double StringSortCompare(JSThread *thread, const JSHandle &valueX, const JSHandle &valueY); - static int64_t GetLength(JSThread *thread, const JSHandle &thisHandle); + static PUBLIC_API int64_t GetLength(JSThread *thread, const JSHandle &thisHandle); static int64_t GetArrayLength(JSThread *thread, const JSHandle &thisHandle); static JSTaggedValue FlattenIntoArray(JSThread *thread, const JSHandle &newArrayHandle, const JSHandle &thisObjVal, const FlattenArgs &args, diff --git a/ecmascript/base/config.h b/ecmascript/base/config.h index cf6614a91998f805c8cae29142aba7afe6b4d6b1..1c87940b40ec831fd401def715ee24c03d771b41 100644 --- a/ecmascript/base/config.h +++ b/ecmascript/base/config.h @@ -93,6 +93,10 @@ namespace panda::ecmascript { #else #define ECMASCRIPT_DISABLE_CONCURRENT_MARKING 0 #endif + +#define ECMASCRIPT_ENABLE_VALUE_SERIALIZER 1 + +#define UNSHARED_CONSTANTPOOL_COUNT 10240 } // namespace panda::ecmascript #endif // ECMASCRIPT_BASE_CONFIG_H diff --git a/ecmascript/base/dtoa_helper.cpp b/ecmascript/base/dtoa_helper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..8750602dd11fa5cbb6eb404a1363cac7ef041737 --- /dev/null +++ b/ecmascript/base/dtoa_helper.cpp @@ -0,0 +1,223 @@ +/* + * 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. + */ + +#include "ecmascript/base/dtoa_helper.h" + +#ifndef UINT64_C2 +#define UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) +#endif +namespace panda::ecmascript::base::dtoa { +DtoaHelper::DiyFp DtoaHelper::GetCachedPowerByIndex(size_t index) +{ + // 10^-348, 10^-340, ..., 10^340 + static const uint64_t kCachedPowers_F[] = { + UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76), + UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea), + UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df), + UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f), + UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c), + UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5), + UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d), + UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637), + UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7), + UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5), + UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b), + UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996), + UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6), + UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8), + UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053), + UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd), + UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94), + UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b), + UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac), + UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3), + UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb), + UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c), + UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000), + UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984), + UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70), + UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245), + UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8), + UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a), + UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea), + UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85), + UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2), + UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3), + UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25), + UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece), + UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5), + UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a), + UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c), + UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a), + UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129), + UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429), + UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d), + UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841), + UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9), + UINT64_C2(0xaf87023b, 0x9bf0ee6b) + }; + static const int16_t kCachedPowers_E[] = { + -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, + -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, + -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, + -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, + -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, + 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, + 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, + 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, + 907, 933, 960, 986, 1013, 1039, 1066 + }; + return DtoaHelper::DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); +} + +void DtoaHelper::GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t distance) +{ + while (rest < distance && delta - rest >= tenKappa && + (rest + tenKappa < distance || distance - rest > rest + tenKappa - distance)) { + buffer[len - 1]--; + rest += tenKappa; + } +} + +int DtoaHelper::CountDecimalDigit32(uint32_t n) +{ + if (n < TEN) { + return 1; // 1: means the decimal digit + } else if (n < TEN2POW) { + return 2; // 2: means the decimal digit + } else if (n < TEN3POW) { + return 3; // 3: means the decimal digit + } else if (n < TEN4POW) { + return 4; // 4: means the decimal digit + } else if (n < TEN5POW) { + return 5; // 5: means the decimal digit + } else if (n < TEN6POW) { + return 6; // 6: means the decimal digit + } else if (n < TEN7POW) { + return 7; // 7: means the decimal digit + } else if (n < TEN8POW) { + return 8; // 8: means the decimal digit + } else { + return 9; // 9: means the decimal digit + } +} + +void DtoaHelper::DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K) +{ + const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); + const DiyFp distance = Mp - W; + uint32_t p1 = static_cast(Mp.f >> -one.e); + uint64_t p2 = Mp.f & (one.f - 1); + int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] + *len = 0; + while (kappa > 0) { + uint32_t d = 0; + switch (kappa) { + case 9: // 9: means the decimal digit + d = p1 / TEN8POW; + p1 %= TEN8POW; + break; + case 8: // 8: means the decimal digit + d = p1 / TEN7POW; + p1 %= TEN7POW; + break; + case 7: // 7: means the decimal digit + d = p1 / TEN6POW; + p1 %= TEN6POW; + break; + case 6: // 6: means the decimal digit + d = p1 / TEN5POW; + p1 %= TEN5POW; + break; + case 5: // 5: means the decimal digit + d = p1 / TEN4POW; + p1 %= TEN4POW; + break; + case 4: // 4: means the decimal digit + d = p1 / TEN3POW; + p1 %= TEN3POW; + break; + case 3: // 3: means the decimal digit + d = p1 / TEN2POW; + p1 %= TEN2POW; + break; + case 2: // 2: means the decimal digit + d = p1 / TEN; + p1 %= TEN; + break; + case 1: // 1: means the decimal digit + d = p1; + p1 = 0; + break; + default:; + } + if (d || *len) { + buffer[(*len)++] = static_cast('0' + static_cast(d)); + } + kappa--; + uint64_t tmp = (static_cast(p1) << -one.e) + p2; + if (tmp <= delta) { + *K += kappa; + GrisuRound(buffer, *len, delta, tmp, POW10[kappa] << -one.e, distance.f); + return; + } + } + + // kappa = 0 + for (;;) { + p2 *= TEN; + delta *= TEN; + char d = static_cast(p2 >> -one.e); + if (d || *len) { + buffer[(*len)++] = static_cast('0' + d); + } + p2 &= one.f - 1; + kappa--; + if (p2 < delta) { + *K += kappa; + int index = -kappa; + GrisuRound(buffer, *len, delta, p2, one.f, distance.f * (index < kIndex ? POW10[index] : 0)); + return; + } + } +} + +// Grisu2 algorithm use the extra capacity of the used integer type to shorten the produced output +void DtoaHelper::Grisu(double value, char *buffer, int *length, int *K) +{ + const DiyFp v(value); + DiyFp mMinus; + DiyFp mPlus; + v.NormalizedBoundaries(&mMinus, &mPlus); + + const DiyFp cached = GetCachedPower(mPlus.e, K); + const DiyFp W = v.Normalize() * cached; + DiyFp wPlus = mPlus * cached; + DiyFp wMinus = mMinus * cached; + wMinus.f++; + wPlus.f--; + DigitGen(W, wPlus, wPlus.f - wMinus.f, buffer, length, K); +} + +void DtoaHelper::Dtoa(double value, char *buffer, int *point, int *length) +{ + // Exceptional case such as NAN, 0.0, negative... are processed in DoubleToEcmaString + // So use Dtoa should avoid Exceptional case. + ASSERT(value > 0); + int k; + Grisu(value, buffer, length, &k); + *point = *length + k; +} +} \ No newline at end of file diff --git a/ecmascript/base/dtoa_helper.h b/ecmascript/base/dtoa_helper.h new file mode 100644 index 0000000000000000000000000000000000000000..76c509f51f4536f52b6c09fd6322dd97d6f54b21 --- /dev/null +++ b/ecmascript/base/dtoa_helper.h @@ -0,0 +1,167 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_BASE_DTOA_HELPER_H +#define ECMASCRIPT_BASE_DTOA_HELPER_H + +#include +#include +#include +#include + +#include "ecmascript/common.h" +namespace panda::ecmascript::base::dtoa { +class DtoaHelper { +public: + static constexpr int CACHED_POWERS_OFFSET = 348; + static constexpr double kD_1_LOG2_10 = 0.30102999566398114; //1 / lg(10) + static constexpr int kQ = -61; + static constexpr int kIndex = 20; + static constexpr int MIN_DECIMAL_EXPONENT = -348; + static constexpr uint64_t POW10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL, + 10000000ULL, 100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL, + 1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL, + 10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL, + 10000000000000000000ULL }; + + static constexpr uint32_t TEN = 10; + static constexpr uint32_t TEN2POW = 100; + static constexpr uint32_t TEN3POW = 1000; + static constexpr uint32_t TEN4POW = 10000; + static constexpr uint32_t TEN5POW = 100000; + static constexpr uint32_t TEN6POW = 1000000; + static constexpr uint32_t TEN7POW = 10000000; + static constexpr uint32_t TEN8POW = 100000000; + + // DiyFp is a floating-point number type, consists of a uint64 significand and one integer exponent. + struct DiyFp { + DiyFp() : f(), e() {} + DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} + + explicit DiyFp(double d) + { + union { + double d; + uint64_t u64; + } u = { d }; + + int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); + uint64_t significand = (u.u64 & kDpSignificandMask); + if (biased_e != 0) { + f = significand + kDpHiddenBit; + e = biased_e - kDpExponentBias; + } else { + f = significand; + e = kDpMinExponent + 1; + } + } + + DiyFp operator - (const DiyFp &rhs) const + { + return DiyFp(f - rhs.f, e); + } + + DiyFp operator*(const DiyFp &rhs) const + { + const uint64_t M32 = 0xFFFFFFFF; + const uint64_t a = f >> 32; + const uint64_t b = f & M32; + const uint64_t c = rhs.f >> 32; + const uint64_t d = rhs.f & M32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + uint64_t tmp = (bd >> kInt32Bits) + (ad & M32) + (bc & M32); + tmp += 1U << kRoundBits; // mult_round + return DiyFp(ac + (ad >> kInt32Bits) + (bc >> kInt32Bits) + (tmp >> kInt32Bits), e + rhs.e + kInt64Bits); + } + + DiyFp Normalize() const + { + DiyFp res = *this; + while (!(res.f & kDpHiddenBit)) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 1); + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1); + return res; + } + + DiyFp NormalizeBoundary() const + { + DiyFp res = *this; + while (!(res.f & (kDpHiddenBit << 1))) { + res.f <<= 1; + res.e--; + } + res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); // 2: parameter + res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); // 2: parameter + return res; + } + + void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const + { + DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); + DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); // 2: parameter + mi.f <<= mi.e - pl.e; + mi.e = pl.e; + *plus = pl; + *minus = mi; + } + + static const int kInt64Bits = 64; + static const int kInt32Bits = 32; + static const int kRoundBits = 31; + static const int kDiySignificandSize = 64; + static const int kDpSignificandSize = 52; + static const int kDpExponentBias = 0x3FF + kDpSignificandSize; + static const int kDpMaxExponent = 0x7FF - kDpExponentBias; + static const int kDpMinExponent = -kDpExponentBias; + static const int kDpDenormalExponent = -kDpExponentBias + 1; + static const uint64_t kDpExponentMask = + (static_cast(0x7FF00000) << 32) | static_cast(0x00000000); + static const uint64_t kDpSignificandMask = + (static_cast(0x000FFFFF) << 32) | static_cast(0xFFFFFFFF); + static const uint64_t kDpHiddenBit = + (static_cast(0x00100000) << 32) | static_cast(0x00000000); + + uint64_t f; + int e; + }; + + static DiyFp GetCachedPower(int e, int *K) + { + // dk must be positive, so can do ceiling in positive + double dk = (kQ - e) * kD_1_LOG2_10 + CACHED_POWERS_OFFSET - 1; + int k = static_cast(dk); + if (dk - k > 0.0) { + k++; + } + unsigned index = static_cast((k >> 3) + 1); // 3: parameter + *K = -(MIN_DECIMAL_EXPONENT + static_cast(index << 3)); // 3: parameter + return GetCachedPowerByIndex(index); + } + + static DiyFp GetCachedPowerByIndex(size_t index); + static void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t distance); + static int CountDecimalDigit32(uint32_t n); + static void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K); + static void Grisu(double value, char* buffer, int* length, int* K); + static void Dtoa(double value, char* buffer, int* point, int* length); +}; +} +#endif \ No newline at end of file diff --git a/ecmascript/base/error_helper.cpp b/ecmascript/base/error_helper.cpp index ceae1d0d45f182b1948a7c4568c37080e065c1b6..67dffbd091d17827cf75a550ccf57679dadbef15 100644 --- a/ecmascript/base/error_helper.cpp +++ b/ecmascript/base/error_helper.cpp @@ -254,10 +254,6 @@ JSHandle ErrorHelper::BuildEcmaStackTrace(JSThread *thread, std::str if (sourceMapcb != nullptr && !data.empty()) { data = sourceMapcb(data.c_str()); } - auto nativeStackcb = ecmaVm->GetNativeStackCallback(); - if (nativeStackcb != nullptr && data.empty()) { - data = nativeStackcb(); - } ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); return factory->NewFromStdString(data); diff --git a/ecmascript/base/json_helper.h b/ecmascript/base/json_helper.h index 7cd093f9c5c82a50df600704058b09af1e2e5e34..281bbdd73da30770e3df8c8ff13c9a863e9211ac 100644 --- a/ecmascript/base/json_helper.h +++ b/ecmascript/base/json_helper.h @@ -24,6 +24,11 @@ namespace panda::ecmascript::base { class JsonHelper { public: + enum class TransformType : uint32_t { + SENDABLE = 1, + NORMAL = 2 + }; + static CString ValueToQuotedString(CString str); static bool IsFastValueToQuotedString(const char *value); diff --git a/ecmascript/base/json_parser.cpp b/ecmascript/base/json_parser.cpp index 0924439d333d1042457c30e05f831922ae589292..33a5f1907756b7c0fe6a656ab391252c4a420071 100644 --- a/ecmascript/base/json_parser.cpp +++ b/ecmascript/base/json_parser.cpp @@ -14,11 +14,13 @@ */ #include "ecmascript/base/json_parser.h" +#include "ecmascript/base/json_helper.h" namespace panda::ecmascript::base { JSHandle Internalize::InternalizeJsonProperty(JSThread *thread, const JSHandle &holder, const JSHandle &name, - const JSHandle &receiver) + const JSHandle &receiver, + TransformType transformType) { JSHandle objHandle(holder); JSHandle val = JSTaggedValue::GetProperty(thread, objHandle, name).GetValue(); @@ -41,7 +43,7 @@ JSHandle Internalize::InternalizeJsonProperty(JSThread *thread, c keyUnknow.Update(JSTaggedValue(i)); keyName.Update(JSTaggedValue::ToString(thread, keyUnknow).GetTaggedValue()); RETURN_HANDLE_IF_ABRUPT_COMPLETION(JSTaggedValue, thread); - RecurseAndApply(thread, obj, keyName, receiver); + RecurseAndApply(thread, obj, keyName, receiver, transformType); } } else { // Let keys be ? EnumerableOwnPropertyNames(val, key). @@ -51,7 +53,7 @@ JSHandle Internalize::InternalizeJsonProperty(JSThread *thread, c JSMutableHandle keyName(thread, JSTaggedValue::Undefined()); for (uint32_t i = 0; i < namesLength; i++) { keyName.Update(ownerNames->Get(i)); - RecurseAndApply(thread, obj, keyName, receiver); + RecurseAndApply(thread, obj, keyName, receiver, transformType); } } } @@ -68,15 +70,17 @@ JSHandle Internalize::InternalizeJsonProperty(JSThread *thread, c } bool Internalize::RecurseAndApply(JSThread *thread, const JSHandle &holder, - const JSHandle &name, const JSHandle &receiver) + const JSHandle &name, const JSHandle &receiver, + TransformType transformType) { STACK_LIMIT_CHECK(thread, false); - JSHandle value = InternalizeJsonProperty(thread, holder, name, receiver); + JSHandle value = InternalizeJsonProperty(thread, holder, name, receiver, transformType); bool changeResult = false; // If newElement is undefined, then Perform ? val.[[Delete]](P). if (value->IsUndefined()) { - changeResult = JSObject::DeleteProperty(thread, holder, name); + SCheckMode sCheckMode = transformType == TransformType::SENDABLE ? SCheckMode::SKIP : SCheckMode::CHECK; + changeResult = JSObject::DeleteProperty(thread, holder, name, sCheckMode); } else { // Perform ? CreateDataProperty(val, P, newElement) changeResult = JSObject::CreateDataProperty(thread, holder, name, value); diff --git a/ecmascript/base/json_parser.h b/ecmascript/base/json_parser.h index 92241535c7e80bd6dda8207c12ca54cd8c31b83b..e44767d921b97d332c47538319b59458f6a98ad5 100644 --- a/ecmascript/base/json_parser.h +++ b/ecmascript/base/json_parser.h @@ -18,6 +18,7 @@ #include +#include "ecmascript/base/json_helper.h" #include "ecmascript/base/json_parser.h" #include "ecmascript/base/builtins_base.h" #include "ecmascript/base/number_helper.h" @@ -30,6 +31,7 @@ #include "ecmascript/js_handle.h" #include "ecmascript/global_env.h" #include "ecmascript/js_tagged_value.h" +#include "ecmascript/message_string.h" #include "ecmascript/object_factory.h" #include "ecmascript/object_fast_operator-inl.h" @@ -68,11 +70,15 @@ struct JsonContinuation { template class JsonParser { protected: + using TransformType = base::JsonHelper::TransformType; using Text = const T *; using ContType = JsonContinuation::ContinuationType; // Instantiation of the class is prohibited JsonParser() = default; - explicit JsonParser(JSThread *thread) : thread_(thread) {} + JsonParser(JSThread *thread, TransformType transformType) + : thread_(thread), transformType_(transformType) + { + } ~JsonParser() = default; NO_COPY_SEMANTIC(JsonParser); NO_MOVE_SEMANTIC(JsonParser); @@ -125,6 +131,13 @@ protected: return *current_ == '}'; } + JSHandle GetSJsonPrototype() + { + JSHandle sObjFunction(thread_->GetEcmaVM()->GetGlobalEnv()->GetSObjectFunction()); + JSHandle jsonPrototype = JSHandle(thread_, sObjFunction->GetFunctionPrototype()); + return jsonPrototype; + } + JSTaggedValue ParseJSONText() { JSHandle parseValue; @@ -142,7 +155,17 @@ protected: switch (token) { case Tokens::OBJECT: if (EmptyObjectCheck()) { - parseValue = JSHandle(factory_->NewJSObject(initialJSObjectClass_)); + if (transformType_ == TransformType::SENDABLE) { + JSHandle sHclass; + JSHandle sJsonPrototype = GetSJsonPrototype(); + JSHandle sLayout = factory_->CreateSLayoutInfo(0); + sHclass = factory_->NewSEcmaHClass(JSSharedObject::SIZE, 0, JSType::JS_SHARED_OBJECT, + JSHandle(sJsonPrototype), + JSHandle(sLayout)); + parseValue = JSHandle(factory_->NewSharedOldSpaceJSObject(sHclass)); + } else { + parseValue = JSHandle(factory_->NewJSObject(initialJSObjectClass_)); + } GetNextNonSpaceChar(); break; } @@ -164,6 +187,11 @@ protected: Advance(); continue; case Tokens::ARRAY: + // sendable array not support now + if (UNLIKELY(transformType_ == TransformType::SENDABLE)) { + THROW_SYNTAX_ERROR_AND_RETURN(thread_, GET_MESSAGE_STRING(SendableArrayForJson), + JSTaggedValue::Exception()); + } if (EmptyArrayCheck()) { parseValue = JSHandle(factory_->NewJSArray(0, initialJSArrayClass_)); GetNextNonSpaceChar(); @@ -246,8 +274,11 @@ protected: Advance(); break; } - - parseValue = CreateJsonObject(continuation, propertyList); + if (UNLIKELY(transformType_ == TransformType::SENDABLE)) { + parseValue = CreateSJsonObject(continuation, propertyList); + } else { + parseValue = CreateJsonObject(continuation, propertyList); + } if (UNLIKELY(*current_ != '}')) { THROW_SYNTAX_ERROR_AND_RETURN(thread_, "Unexpected Object in JSON", JSTaggedValue::Exception()); @@ -296,6 +327,60 @@ protected: return obj; } + JSHandle CreateSJsonObject(JsonContinuation continuation, + std::vector> &propertyList) + { + size_t start = continuation.index_; + size_t size = propertyList.size() - start; + uint32_t fieldNum = size / 2; // 2: key-value pair + JSHandle hclass; + JSHandle layout; + JSHandle jsonPrototype = GetSJsonPrototype(); + if (fieldNum == 0) { + layout = factory_->CreateSLayoutInfo(fieldNum); + hclass = factory_->NewSEcmaHClass(JSSharedObject::SIZE, fieldNum, JSType::JS_SHARED_OBJECT, + JSHandle(jsonPrototype), JSHandle(layout)); + JSHandle obj = factory_->NewSharedOldSpaceJSObject(hclass); + return JSHandle(obj); + } else if (LIKELY(fieldNum <= JSSharedObject::MAX_INLINE)) { + layout = factory_->CreateSLayoutInfo(fieldNum); + JSHandle propertyArray = factory_->NewSTaggedArray(size); + for (size_t i = 0; i < size; i += 2) { // 2: prop name and value + JSHandle keyHandle = propertyList[start + i]; + propertyArray->Set(thread_, i, keyHandle); + propertyArray->Set(thread_, i + 1, JSTaggedValue(int(FieldType::NONE))); + } + hclass = factory_->NewSEcmaHClass(JSSharedObject::SIZE, fieldNum, JSType::JS_SHARED_OBJECT, + JSHandle(jsonPrototype), JSHandle(layout)); + SendableClassDefiner::AddFieldTypeToHClass(thread_, propertyArray, size, layout, hclass); + JSHandle obj = factory_->NewSharedOldSpaceJSObject(hclass); + uint32_t index = 0; + for (size_t i = 0; i < size; i += 2) { // 2: prop name and value + obj->SetPropertyInlinedProps(thread_, index++, propertyList[start + i + 1].GetTaggedValue()); + } + return JSHandle(obj); + } + // build in dict mode + JSMutableHandle dict( + thread_, NameDictionary::CreateInSharedHeap(thread_, NameDictionary::ComputeHashTableSize(fieldNum))); + JSMutableHandle propKey(thread_, JSTaggedValue::Undefined()); + JSMutableHandle propValue(thread_, JSTaggedValue::Undefined()); + // create dict and set key value + for (size_t i = 0; i < size; i += 2) { // 2: prop name and value + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + propKey.Update(propertyList[start + i]); + propValue.Update(propertyList[start + i + 1]); + JSHandle newDict = NameDictionary::PutIfAbsent(thread_, dict, propKey, + propValue, attributes); + dict.Update(newDict); + } + hclass = factory_->NewSEcmaHClassDictMode(JSSharedObject::SIZE, fieldNum, JSType::JS_SHARED_OBJECT, + JSHandle(jsonPrototype)); + JSHandle obj = factory_->NewSharedOldSpaceJSObject(hclass); + obj->SetProperties(thread_, dict); + return JSHandle(obj); + } + JSTaggedValue SetPropertyByValue(const JSHandle &receiver, const JSHandle &key, const JSHandle &value) { @@ -783,6 +868,7 @@ protected: JSThread *thread_ {nullptr}; ObjectFactory *factory_ {nullptr}; GlobalEnv *env_ {nullptr}; + TransformType transformType_ {TransformType::NORMAL}; JSHandle initialJSArrayClass_; JSHandle initialJSObjectClass_; }; @@ -790,7 +876,7 @@ protected: class Utf8JsonParser : public JsonParser { public: Utf8JsonParser() = default; - explicit Utf8JsonParser(JSThread *thread) : JsonParser(thread) {} + Utf8JsonParser(JSThread *thread, TransformType transformType) : JsonParser(thread, transformType) {} ~Utf8JsonParser() = default; NO_COPY_SEMANTIC(Utf8JsonParser); NO_MOVE_SEMANTIC(Utf8JsonParser); @@ -915,7 +1001,7 @@ private: class Utf16JsonParser : public JsonParser { public: Utf16JsonParser() = default; - explicit Utf16JsonParser(JSThread *thread) : JsonParser(thread) {} + Utf16JsonParser(JSThread *thread, TransformType transformType) : JsonParser(thread, transformType) {} ~Utf16JsonParser() = default; NO_COPY_SEMANTIC(Utf16JsonParser); NO_MOVE_SEMANTIC(Utf16JsonParser); @@ -1027,12 +1113,14 @@ private: class Internalize { public: + using TransformType = base::JsonHelper::TransformType; static JSHandle InternalizeJsonProperty(JSThread *thread, const JSHandle &holder, const JSHandle &name, - const JSHandle &receiver); + const JSHandle &receiver, + TransformType transformType); private: static bool RecurseAndApply(JSThread *thread, const JSHandle &holder, const JSHandle &name, - const JSHandle &receiver); + const JSHandle &receiver, TransformType transformType); }; } // namespace panda::ecmascript::base diff --git a/ecmascript/base/number_helper.cpp b/ecmascript/base/number_helper.cpp index 4c208fad009f54a7ac55ffcbb48953c4d1eca970..eaa527c32e9fe1d1f35ba311282aebf8f60db74a 100644 --- a/ecmascript/base/number_helper.cpp +++ b/ecmascript/base/number_helper.cpp @@ -24,6 +24,7 @@ #include #include "ecmascript/base/builtins_base.h" +#include "ecmascript/base/dtoa_helper.h" #include "ecmascript/base/string_helper.h" #include "ecmascript/builtins/builtins_number.h" #include "ecmascript/ecma_string_table.h" @@ -312,12 +313,12 @@ void NumberHelper::CustomEcvtIsFixed(double &valueNumber, int &digits, int *deci while (digits >= MIN_RADIX && buf[digits - 1] == '0') { digits--; } - digitsMax = digits; + digitsMax = static_cast(digits); } else { - digitsMin = digits + 1; + digitsMin = static_cast(digits) + 1; } } - digits = digitsMax; + digits = static_cast(digitsMax); } int NumberHelper::CustomEcvt(double valueNumber, int digits, int *decimalPoint, @@ -437,7 +438,8 @@ void NumberHelper::DoubleToASCIIWithFlag(std::string& buf, double valueNumber, i std::string buf1(JS_DTOA_BUF_SIZE, '\0'); int decimalPoint = 0; int sign = 0; - bool fixed = ((flags & POINT_INDEX) == base::FIXED_FORMAT); + bool fixed = ((static_cast(flags) & POINT_INDEX) == + static_cast(base::FIXED_FORMAT)); int numberMax = fixed ? digits : MAX_DIGITS; int digitNumber = CustomEcvt(valueNumber, digits, &decimalPoint, buf1, fixed, &sign); int number = decimalPoint; @@ -632,61 +634,28 @@ JSHandle NumberHelper::DoubleToEcmaString(const JSThread *thread, do } ASSERT(d > 0); - - // 5. Otherwise, let n, k, and s be integers such that k ≥ 1, 10k−1 ≤ s < 10k, the Number value for s × 10n−k is m, - // and k is as small as possible. If there are multiple possibilities for s, choose the value of s for which s × - // 10n−k is closest in value to m. If there are two such possible values of s, choose the one that is even. Note - // that k is the number of digits in the decimal representation of s and that s is not divisible by 10. - if (0.1 <= d && d < 1) { // 0.1: 10 ** -1 - // Fast path. In this case, n==0, just need to calculate k and s. - std::string resultFast = "0."; - int64_t sFast = 0; - int kFast = 1; - int64_t power = 1; - while (kFast <= DOUBLE_MAX_PRECISION) { - power *= 10; // 10: base 10 - int digitFast = static_cast(d * power) % 10; // 10: base 10 - ASSERT(0 <= digitFast && digitFast <= 9); // 9: single digit max - sFast = sFast * 10 + digitFast; // 10: base 10 - resultFast += (digitFast + '0'); - if (sFast / static_cast(power) == d) { // s * (10 ** -k) - result += resultFast; - return factory->NewFromASCII(result.c_str()); - } - kFast++; - } - } char buffer[JS_DTOA_BUF_SIZE] = {0}; - int n = 0; - int k = GetMinmumDigits(d, &n, buffer); + int n; // decimal point + int k; // length + dtoa::DtoaHelper::Dtoa(d, buffer, &n, &k); //Fast Double To Ascii. std::string base = buffer; if (n > 0 && n <= MAX_DIGITS) { - base.erase(1, 1); if (k <= n) { - // 6. If k ≤ n ≤ 21, return the String consisting of the code units of the k digits of the decimal - // representation of s (in order, with no leading zeroes), followed by n−k occurrences of the code unit - // 0x0030 (DIGIT ZERO). + // 6. If k ≤ n ≤ 21 base += std::string(n - k, '0'); } else { - // 7. If 0 < n ≤ 21, return the String consisting of the code units of the most significant n digits of the - // decimal representation of s, followed by the code unit 0x002E (FULL STOP), followed by the code units of - // the remaining k−n digits of the decimal representation of s. + // 7. If 0 < n ≤ 21 base.insert(n, 1, '.'); } } else if (MIN_DIGITS < n && n <= 0) { - // 8. If −6 < n ≤ 0, return the String consisting of the code unit 0x0030 (DIGIT ZERO), followed by the code - // unit 0x002E (FULL STOP), followed by −n occurrences of the code unit 0x0030 (DIGIT ZERO), followed by the - // code units of the k digits of the decimal representation of s. - base.erase(1, 1); + // 8. If −6 < n ≤ 0 base = std::string("0.") + std::string(-n, '0') + base; } else { - if (k == 1) { - // 9. Otherwise, if k = 1, return the String consisting of the code unit of the single digit of s - base.erase(1, 1); + // 9. & 10. Otherwise + base.erase(1, k - 1); + if (k != 1) { + base += std::string(".") + std::string(buffer + 1); } - // followed by code unit 0x0065 (LATIN SMALL LETTER E), followed by the code unit 0x002B (PLUS SIGN) or the - // code unit 0x002D (HYPHEN-MINUS) according to whether n−1 is positive or negative, followed by the code - // units of the decimal representation of the integer abs(n−1) (with no leading zeroes). base += "e" + (n >= 1 ? std::string("+") : "") + std::to_string(n - 1); } result += base; @@ -1209,7 +1178,7 @@ uint64_t RandomGenerator::XorShift64(uint64_t *pVal) return x * GET_MULTIPLY; } -void RandomGenerator::InitRandom() +void RandomGenerator::InitRandom(JSThread *thread) { struct timeval tv; gettimeofday(&tv, NULL); @@ -1218,6 +1187,7 @@ void RandomGenerator::InitRandom() if (randomState_ == 0) { randomState_ = 1; } + thread->SetRandomStatePtr(&randomState_); } double RandomGenerator::NextDouble() diff --git a/ecmascript/base/number_helper.h b/ecmascript/base/number_helper.h index 00fccaa08f651d4834ef105ec67d64201b9a1ff3..7cf4392bdc85b5c9ad33c468444de084f37460fa 100644 --- a/ecmascript/base/number_helper.h +++ b/ecmascript/base/number_helper.h @@ -141,7 +141,7 @@ public: 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 DoubleInRangeInt32(double d); + static int32_t PUBLIC_API DoubleInRangeInt32(double d); static JSTaggedValue StringToDoubleWithRadix(const uint8_t *start, const uint8_t *end, int radix, bool *negative); static CString IntToString(int number); static CString IntegerToString(double number, int radix); @@ -171,7 +171,7 @@ private: // The value is used in xorshift64* random generator to generate result. class RandomGenerator { public: - static void InitRandom(); + static void InitRandom(JSThread *thread); static double NextDouble(); static int32_t GenerateIdentityHash(); static int32_t Next(int bits); diff --git a/ecmascript/base/path_helper.h b/ecmascript/base/path_helper.h index b768df3085c8e7529a5d3cfcf4b62dc7eee2d844..eb76da8dba2ef35a5754c8a6564e0ed69c401f4a 100644 --- a/ecmascript/base/path_helper.h +++ b/ecmascript/base/path_helper.h @@ -32,6 +32,7 @@ public: static constexpr char DOUBLE_POINT_TAG[] = ".."; static constexpr char DOUBLE_SLASH_TAG[] = "//"; static constexpr char NAME_SPACE_TAG = '@'; + static constexpr char NORMALIZED_OHMURL_TAG = '&'; static constexpr char POINT_STRING_TAG[] = "."; static constexpr char POINT_TAG = '.'; static constexpr char SLASH_TAG = '/'; @@ -52,6 +53,17 @@ public: moduleName.erase(pos, moduleName.size() - pos); } + /* + * Before: moduleName@nameSpace + * After: nameSpace + */ + inline static CString GetHarName(CString &moduleName) + { + size_t pos = moduleName.find(NAME_SPACE_TAG); + ASSERT(pos != CString::npos); + return moduleName.substr(pos); + } + /* * Before: bundleName/moduleName@namespace/moduleName/xxx/xxx * After: moduleName/xxx/xxx diff --git a/ecmascript/base/tests/BUILD.gn b/ecmascript/base/tests/BUILD.gn index 0d366458b1eeae7d364c9e344f1097b783a9c1ff..e1ff70387656a9597ce52bdb88a8f65997abb882 100644 --- a/ecmascript/base/tests/BUILD.gn +++ b/ecmascript/base/tests/BUILD.gn @@ -79,6 +79,7 @@ host_unittest_action("Base_003_Test") { sources = [ # test file + "dtoa_helper_test.cpp", "number_helper_test.cpp", "string_helper_test.cpp", "typed_array_helper_test.cpp", diff --git a/ecmascript/base/tests/dtoa_helper_test.cpp b/ecmascript/base/tests/dtoa_helper_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..97f915c7fc900a2e40e7837a040f35ce03ff5fb9 --- /dev/null +++ b/ecmascript/base/tests/dtoa_helper_test.cpp @@ -0,0 +1,121 @@ +/* + * 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. + */ + +#include "ecmascript/base/dtoa_helper.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; +using namespace panda::ecmascript::base; +using namespace panda::ecmascript::base::dtoa; + +#define TEST_DTOA(d, str, buffer, n, k, e1, e2) \ + DtoaHelper::Dtoa(d, buffer, &(n), &(k)); \ + EXPECT_STREQ(str, buffer); \ + EXPECT_EQ(n, e1); \ + EXPECT_EQ(k, e2) + +namespace panda::test { +class DtoaHelperTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(instance, scope); + } + + EcmaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +protected: + template + inline To MemoryCast(const From &src) noexcept + { + static_assert(sizeof(To) == sizeof(From), "size of the types must be equal"); + To dst; + if (memcpy_s(&dst, sizeof(To), &src, sizeof(From)) != EOK) { + LOG_FULL(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + return dst; + } +}; + +HWTEST_F_L0(DtoaHelperTest, DoubleToAscii) +{ + char buffer1[128] = {}; + int n1; //decimal_point + int k1; //length + TEST_DTOA(1.2345, "12345", buffer1, n1, k1, 1, 5); + + char buffer2[128] = {}; + int n2; + int k2; + TEST_DTOA(1.2345678, "12345678", buffer2, n2, k2, 1, 8); + + char buffer3[128] = {}; + int n3; + int k3; + TEST_DTOA(1e30, "1", buffer3, n3, k3, 31, 1); + + char buffer4[128] = {}; + int n4; + int k4; + TEST_DTOA(79.39773355813419, "7939773355813419", buffer4, n4, k4, 2, 16); + + char buffer5[128] = {}; + int n5; + int k5; + TEST_DTOA(0.0000001, "1", buffer5, n5, k5, -6, 1); + + char buffer6[128] = {}; + int n6; + int k6; + TEST_DTOA(1.234567890123456e30, "1234567890123456", buffer6, n6, k6, 31, 16); + + char buffer7[128] = {}; + int n7; + int k7; + TEST_DTOA(2.225073858507201e-308, "2225073858507201", buffer7, n7, k7, -307, 16); // Max subnormal positive double + + char buffer8[128] = {}; + int n8; + int k8; + TEST_DTOA(2.2250738585072014e-308, "22250738585072014", buffer8, n8, k8, -307, 17); // Min normal positive double + + char buffer9[128] = {}; + int n9; + int k9; + TEST_DTOA(1.7976931348623157e308, "17976931348623157", buffer9, n9, k9, 309, 17); // Max double + + char buffera[128] = {}; + int na; + int ka; + TEST_DTOA(5e-301, "5", buffera, na, ka, -300, 1); +} +} // namespace panda::test diff --git a/ecmascript/base/tests/json_parser_test.cpp b/ecmascript/base/tests/json_parser_test.cpp index 5329b7c535341476c0b61eab982a4bd101bff627..21b986fcc639901e1ef53d24dd7e946e5e180bcd 100644 --- a/ecmascript/base/tests/json_parser_test.cpp +++ b/ecmascript/base/tests/json_parser_test.cpp @@ -14,6 +14,8 @@ */ #include "ecmascript/base/json_parser.h" +#include "ecmascript/base/json_helper.h" +#include "ecmascript/ecma_string.h" #include "ecmascript/tests/test_helper.h" using namespace panda::ecmascript; @@ -22,6 +24,7 @@ using namespace panda::ecmascript::base; namespace panda::test { class JsonParserTest : public testing::Test { public: + using TransformType = base::JsonHelper::TransformType; static void SetUpTestCase() { GTEST_LOG_(INFO) << "SetUpTestCase"; @@ -42,6 +45,79 @@ public: TestHelper::DestroyEcmaVMWithScope(instance, scope); } + void CheckUnsupportedSendableJson(JSHandle &result) const + { + EXPECT_TRUE(result->IsException()); + JSHandle exceptionObj(thread, thread->GetException()); + auto messageValue = + JSTaggedValue::GetProperty(thread, exceptionObj, thread->GlobalConstants()->GetHandledMessageString()) + .GetValue(); + EXPECT_EQ(ConvertToString(EcmaString::Cast(messageValue->GetTaggedObject())), + MessageString::GetMessageString(GET_MESSAGE_STRING_ID(SendableArrayForJson)).c_str()); + } + + bool CheckSendableConstraint(JSTaggedValue value) const + { + if (!value.IsHeapObject()) { + // tagged value always follow sendable constraint. + return true; + } + TaggedObject *obj = value.IsWeak() ? value.GetTaggedWeakRef() : value.GetTaggedObject(); + auto *jsHClass = obj->GetClass(); + if (!jsHClass->IsJSShared()) { + return false; + } + if (jsHClass->IsExtensible()) { + LOG_ECMA(ERROR) << "sendable check failed. obj is extensible"; + value.D(); + return false; + } + if (!CheckSendableProps(value, obj)) { + return false; + } + // trace proto chain + auto proto = jsHClass->GetPrototype(); + if (!proto.IsNull() && !proto.IsJSShared()) { + LOG_ECMA(ERROR) << "sendable check failed. proto is not sendable."; + value.D(); + return false; + } + return true; + } + + bool CheckSendableProps(JSTaggedValue value, TaggedObject *obj) const + { + auto *jsHClass = obj->GetClass(); + auto layoutValue = jsHClass->GetLayout(); + if (layoutValue.IsNull()) { + return true; + } + auto *layoutInfo = LayoutInfo::Cast(layoutValue.GetTaggedObject()); + auto *jsObj = JSObject::Cast(obj); + auto *propsValue = TaggedArray::Cast(jsObj->GetProperties()); + if (propsValue->IsDictionaryMode()) { + for (int idx = 0; idx < static_cast(jsHClass->NumberOfProps()); idx++) { + auto attr = layoutInfo->GetAttr(idx); + if (attr.IsInlinedProps()) { + // Do not check inline props + continue; + } + if (attr.IsWritable()) { + LOG_ECMA(ERROR) << "sendable check failed. supposed to be un-writable. idx: " << idx; + value.D(); + return false; + } + auto val = propsValue->Get(thread, idx - jsHClass->GetInlinedProperties()); + if (!CheckSendableConstraint(val)) { + LOG_ECMA(ERROR) << "sendable check failed. supposed to be sendable. idx: " << idx; + value.D(); + return false; + } + } + } + return true; + } + EcmaVM *instance {nullptr}; EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; @@ -57,7 +133,7 @@ public: HWTEST_F_L0(JsonParserTest, Parser_001) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - Utf8JsonParser parser(thread); + Utf8JsonParser parser(thread, TransformType::NORMAL); // JSON Number JSHandle handleMsg2(factory->NewFromASCII("1234")); JSHandle handleStr2(JSTaggedValue::ToString(thread, handleMsg2)); @@ -85,7 +161,7 @@ HWTEST_F_L0(JsonParserTest, Parser_001) HWTEST_F_L0(JsonParserTest, Parser_002) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - Utf16JsonParser parser(thread); + Utf16JsonParser parser(thread, TransformType::NORMAL); // JSON Number uint16_t array1Utf16[] = {0x31, 0x32, 0x33, 0x34}; // "1234" @@ -121,7 +197,7 @@ HWTEST_F_L0(JsonParserTest, Parser_002) HWTEST_F_L0(JsonParserTest, Parser_003) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - Utf8JsonParser parser(thread); + Utf8JsonParser parser(thread, TransformType::NORMAL); JSHandle handleMsg(factory->NewFromASCII( "\t\r \n{\t\r \n \"json\"\t\r\n:\t\r \n{\t\r \n}\t\r \n,\t\r \n \"prop2\"\t\r \n:\t\r \n [\t\r \nfalse\t\r" @@ -142,7 +218,7 @@ HWTEST_F_L0(JsonParserTest, Parser_004) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle lengthKeyHandle = thread->GlobalConstants()->GetHandledLengthString(); - Utf8JsonParser parser(thread); + Utf8JsonParser parser(thread, TransformType::NORMAL); JSHandle handleMsg(factory->NewFromASCII("[100,2.5,\"abc\"]")); JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Array @@ -168,7 +244,7 @@ HWTEST_F_L0(JsonParserTest, Parser_004) HWTEST_F_L0(JsonParserTest, Parser_005) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - Utf8JsonParser parser(thread); + Utf8JsonParser parser(thread, TransformType::NORMAL); JSHandle handleMsg(factory->NewFromASCII("{\"epf\":100,\"key1\":400}")); JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); // JSON Object @@ -196,7 +272,7 @@ HWTEST_F_L0(JsonParserTest, Parser_005) */ HWTEST_F_L0(JsonParserTest, Parser_006) { - Utf8JsonParser parser(thread); + Utf8JsonParser parser(thread, TransformType::NORMAL); JSHandle emptyString(thread->GlobalConstants()->GetHandledEmptyString()); JSHandle result = parser.Parse(emptyString); EXPECT_TRUE(result->IsException()); @@ -211,10 +287,95 @@ HWTEST_F_L0(JsonParserTest, Parser_006) HWTEST_F_L0(JsonParserTest, Parser_007) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - Utf8JsonParser parser(thread); + Utf8JsonParser parser(thread, TransformType::NORMAL); JSHandle handleStr(factory->NewFromASCII("\"\"")); JSHandle result = parser.Parse(handleStr); EXPECT_FALSE(result->IsException()); } + +/** + * @tc.name: Parser_008 + * @tc.desc: Try to parse a string to sendable object. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(JsonParserTest, Parser_008) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + Utf8JsonParser parser(thread, TransformType::SENDABLE); + JSHandle handleMsg( + factory->NewFromASCII(R"({"innerEntry": {"x":1, "y":"abc", "str": "innerStr"}, "x": 1, "str": "outerStr"})")); + JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); + JSHandle result = parser.Parse(handleStr); + result->D(); + EXPECT_FALSE(result->IsException()); + EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue())); +} + +/** + * @tc.name: Parser_009 + * @tc.desc: Try to parse a empty obj json string to sendable object. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(JsonParserTest, Parser_009) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + Utf8JsonParser parser(thread, TransformType::SENDABLE); + JSHandle handleMsg(factory->NewFromASCII(R"({})")); + JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); + JSHandle result = parser.Parse(handleStr); + result->D(); + EXPECT_TRUE(CheckSendableConstraint(result.GetTaggedValue())); +} + +/** + * @tc.name: Parser_010 + * @tc.desc: Try to parse a empty array json string to sendable object. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(JsonParserTest, Parser_010) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + Utf8JsonParser parser(thread, TransformType::SENDABLE); + JSHandle handleMsg(factory->NewFromASCII(R"([])")); + JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); + JSHandle result = parser.Parse(handleStr); + CheckUnsupportedSendableJson(result); +} + +/** + * @tc.name: Parser_011 + * @tc.desc: Try to parse a simple array json string to sendable object. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(JsonParserTest, Parser_011) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + Utf8JsonParser parser(thread, TransformType::SENDABLE); + JSHandle handleMsg(factory->NewFromASCII(R"([1, 2, 3])")); + JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); + JSHandle result = parser.Parse(handleStr); + CheckUnsupportedSendableJson(result); +} + +/** + * @tc.name: Parser_012 + * @tc.desc: Try to parse a json string with array to sendable object. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(JsonParserTest, Parser_012) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + Utf8JsonParser parser(thread, TransformType::SENDABLE); + JSHandle handleMsg( + factory->NewFromASCII(R"({"innerEntry": {"array": [1, 2, 3]}, "x": 1, "str": "outerStr"})")); + JSHandle handleStr(JSTaggedValue::ToString(thread, handleMsg)); + JSHandle result = parser.Parse(handleStr); + CheckUnsupportedSendableJson(result); +} } // namespace panda::test diff --git a/ecmascript/base/tests/number_helper_test.cpp b/ecmascript/base/tests/number_helper_test.cpp index e32d1dd2669a6cb5de2d5a79590079f4cab6d3a7..9b1ab036c86dfa048b4a484df5cb7c65c83807ef 100644 --- a/ecmascript/base/tests/number_helper_test.cpp +++ b/ecmascript/base/tests/number_helper_test.cpp @@ -157,6 +157,53 @@ HWTEST_F_L0(NumberHelperTest, DoubleToString_002) EXPECT_EQ(EcmaStringAccessor::Compare(instance, handleEcmaStr6, resultStr), 0); } +/** + * @tc.name: DoubleToEcmaString + * @tc.desc: This function Convert the double type data into a EcmaString. + * @tc.type: FUNC + * @tc.require: + */ +HWTEST_F_L0(NumberHelperTest, DoubleToEcmaString) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + + JSHandle resultStr1 = + factory->NewFromASCII("5562684646268003"); + double d1 = 5562684646268003; + JSHandle resultJSHandle1 = NumberHelper::DoubleToEcmaString(thread, d1); + EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle1, resultStr1), 0); + + JSHandle resultStr2 = + factory->NewFromASCII("0.005431"); + double d2 = 0.005431; + JSHandle resultJSHandle2 = NumberHelper::DoubleToEcmaString(thread, d2); + EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle2, resultStr2), 0); + + JSHandle resultStr3 = + factory->NewFromASCII("1.9045e-7"); + double d3 = 0.00000019045; + JSHandle resultJSHandle3 = NumberHelper::DoubleToEcmaString(thread, d3); + EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle3, resultStr3), 0); + + JSHandle resultStr4 = + factory->NewFromASCII("-79.39773355813419"); + double d4 = -79.39773355813419; + JSHandle resultJSHandle4 = NumberHelper::DoubleToEcmaString(thread, d4); + EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle4, resultStr4), 0); + + JSHandle resultStr5 = + factory->NewFromASCII("1e+21"); + double d5 = 1e21; + JSHandle resultJSHandle5 = NumberHelper::DoubleToEcmaString(thread, d5); + EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle5, resultStr5), 0); + + JSHandle resultStr6 = + factory->NewFromASCII("340000000000000000"); + double d6 = 340000000000000000; + JSHandle resultJSHandle6 = NumberHelper::DoubleToEcmaString(thread, d6); + EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle6, resultStr6), 0); +} + /** * @tc.name: IsEmptyString * @tc.desc: Check whether the character is empty string through "IsEmptyString" function. diff --git a/ecmascript/base/typed_array_helper-inl.h b/ecmascript/base/typed_array_helper-inl.h index 479a86a2e5021de7f2ec113366fc5ab310c667a2..f4d6389ba63ef461823d53040ec59c173659125a 100644 --- a/ecmascript/base/typed_array_helper-inl.h +++ b/ecmascript/base/typed_array_helper-inl.h @@ -77,24 +77,34 @@ DataViewType TypedArrayHelper::GetType(JSType type) { switch (type) { case JSType::JS_INT8_ARRAY: + case JSType::JS_SHARED_INT8_ARRAY: return DataViewType::INT8; case JSType::JS_UINT8_ARRAY: + case JSType::JS_SHARED_UINT8_ARRAY: return DataViewType::UINT8; case JSType::JS_UINT8_CLAMPED_ARRAY: + case JSType::JS_SHARED_UINT8_CLAMPED_ARRAY: return DataViewType::UINT8_CLAMPED; case JSType::JS_INT16_ARRAY: + case JSType::JS_SHARED_INT16_ARRAY: return DataViewType::INT16; case JSType::JS_UINT16_ARRAY: + case JSType::JS_SHARED_UINT16_ARRAY: return DataViewType::UINT16; case JSType::JS_INT32_ARRAY: + case JSType::JS_SHARED_INT32_ARRAY: return DataViewType::INT32; case JSType::JS_UINT32_ARRAY: + case JSType::JS_SHARED_UINT32_ARRAY: return DataViewType::UINT32; case JSType::JS_FLOAT32_ARRAY: + case JSType::JS_SHARED_FLOAT32_ARRAY: return DataViewType::FLOAT32; case JSType::JS_FLOAT64_ARRAY: + case JSType::JS_SHARED_FLOAT64_ARRAY: return DataViewType::FLOAT64; case JSType::JS_BIGINT64_ARRAY: + case JSType::JS_SHARED_BIGINT64_ARRAY: return DataViewType::BIGINT64; default: return DataViewType::BIGUINT64; @@ -113,13 +123,21 @@ uint32_t TypedArrayHelper::GetElementSize(JSType type) case JSType::JS_INT8_ARRAY: case JSType::JS_UINT8_ARRAY: case JSType::JS_UINT8_CLAMPED_ARRAY: + case JSType::JS_SHARED_INT8_ARRAY: + case JSType::JS_SHARED_UINT8_ARRAY: + case JSType::JS_SHARED_UINT8_CLAMPED_ARRAY: return ElementSize::ONE; case JSType::JS_INT16_ARRAY: case JSType::JS_UINT16_ARRAY: + case JSType::JS_SHARED_INT16_ARRAY: + case JSType::JS_SHARED_UINT16_ARRAY: return ElementSize::TWO; case JSType::JS_INT32_ARRAY: case JSType::JS_UINT32_ARRAY: case JSType::JS_FLOAT32_ARRAY: + case JSType::JS_SHARED_INT32_ARRAY: + case JSType::JS_SHARED_UINT32_ARRAY: + case JSType::JS_SHARED_FLOAT32_ARRAY: return ElementSize::FOUR; default: return ElementSize::EIGHT; @@ -151,8 +169,30 @@ JSHandle TypedArrayHelper::GetConstructor(JSThread *thread, const return env->GetFloat64ArrayFunction(); case JSType::JS_BIGINT64_ARRAY: return env->GetBigInt64ArrayFunction(); - default: + case JSType::JS_BIGUINT64_ARRAY: return env->GetBigUint64ArrayFunction(); + case JSType::JS_SHARED_INT8_ARRAY: + return env->GetSharedInt8ArrayFunction(); + case JSType::JS_SHARED_UINT8_ARRAY: + return env->GetSharedUint8ArrayFunction(); + case JSType::JS_SHARED_UINT8_CLAMPED_ARRAY: + return env->GetSharedUint8ClampedArrayFunction(); + case JSType::JS_SHARED_INT16_ARRAY: + return env->GetSharedInt16ArrayFunction(); + case JSType::JS_SHARED_UINT16_ARRAY: + return env->GetSharedUint16ArrayFunction(); + case JSType::JS_SHARED_INT32_ARRAY: + return env->GetSharedInt32ArrayFunction(); + case JSType::JS_SHARED_UINT32_ARRAY: + return env->GetSharedUint32ArrayFunction(); + case JSType::JS_SHARED_FLOAT32_ARRAY: + return env->GetSharedFloat32ArrayFunction(); + case JSType::JS_SHARED_FLOAT64_ARRAY: + return env->GetSharedFloat64ArrayFunction(); + case JSType::JS_SHARED_BIGINT64_ARRAY: + return env->GetSharedBigInt64ArrayFunction(); + default: + return env->GetSharedBigUint64ArrayFunction(); } } @@ -186,6 +226,36 @@ JSHandle TypedArrayHelper::GetConstructorFromType(JSThread *thread, return JSHandle(env->GetBigUint64ArrayFunction()); } +JSHandle TypedArrayHelper::GetSharedConstructorFromType(JSThread *thread, const DataViewType arrayType) +{ + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + switch (arrayType) { + case DataViewType::INT8: + return JSHandle(env->GetSharedInt8ArrayFunction()); + case DataViewType::UINT8: + return JSHandle(env->GetSharedUint8ArrayFunction()); + case DataViewType::UINT8_CLAMPED: + return JSHandle(env->GetSharedUint8ClampedArrayFunction()); + case DataViewType::INT16: + return JSHandle(env->GetSharedInt16ArrayFunction()); + case DataViewType::UINT16: + return JSHandle(env->GetSharedUint16ArrayFunction()); + case DataViewType::INT32: + return JSHandle(env->GetSharedInt32ArrayFunction()); + case DataViewType::UINT32: + return JSHandle(env->GetSharedUint32ArrayFunction()); + case DataViewType::FLOAT32: + return JSHandle(env->GetSharedFloat32ArrayFunction()); + case DataViewType::FLOAT64: + return JSHandle(env->GetSharedFloat64ArrayFunction()); + case DataViewType::BIGINT64: + return JSHandle(env->GetSharedBigInt64ArrayFunction()); + default: + break; + } + return JSHandle(env->GetSharedBigUint64ArrayFunction()); +} + JSHandle TypedArrayHelper::GetConstructorNameFromType(JSThread *thread, const DataViewType arrayType) { const GlobalEnvConstants *globalConst = thread->GlobalConstants(); @@ -216,6 +286,37 @@ JSHandle TypedArrayHelper::GetConstructorNameFromType(JSThread *t return globalConst->GetHandledBigInt64ArrayString(); } +JSHandle TypedArrayHelper::GetSharedConstructorNameFromType(JSThread *thread, + const DataViewType arrayType) +{ + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + switch (arrayType) { + case DataViewType::INT8: + return globalConst->GetHandledSharedInt8ArrayString(); + case DataViewType::UINT8: + return globalConst->GetHandledSharedUint8ArrayString(); + case DataViewType::UINT8_CLAMPED: + return globalConst->GetHandledSharedUint8ClampedArrayString(); + case DataViewType::INT16: + return globalConst->GetHandledSharedInt16ArrayString(); + case DataViewType::UINT16: + return globalConst->GetHandledSharedUint16ArrayString(); + case DataViewType::INT32: + return globalConst->GetHandledSharedInt32ArrayString(); + case DataViewType::UINT32: + return globalConst->GetHandledSharedUint32ArrayString(); + case DataViewType::FLOAT32: + return globalConst->GetHandledSharedFloat32ArrayString(); + case DataViewType::FLOAT64: + return globalConst->GetHandledSharedFloat64ArrayString(); + case DataViewType::BIGINT64: + return globalConst->GetHandledSharedBigInt64ArrayString(); + default: + break; + } + return globalConst->GetHandledSharedBigInt64ArrayString(); +} + JSHandle TypedArrayHelper::GetOnHeapHclassFromType( JSThread *thread, const JSHandle &obj, const DataViewType arrayType) { diff --git a/ecmascript/base/typed_array_helper.cpp b/ecmascript/base/typed_array_helper.cpp index 956e57be22a89f597bbd25ac28fe769cbc4716ff..d427d849c2eefbb12ecf8849ccb25c0fd11ac581 100644 --- a/ecmascript/base/typed_array_helper.cpp +++ b/ecmascript/base/typed_array_helper.cpp @@ -20,6 +20,7 @@ #include "ecmascript/base/error_type.h" #include "ecmascript/base/typed_array_helper-inl.h" #include "ecmascript/builtins/builtins_arraybuffer.h" +#include "ecmascript/builtins/builtins_sendable_arraybuffer.h" #include "ecmascript/ecma_macros.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" @@ -34,6 +35,8 @@ #include "ecmascript/js_stable_array.h" #include "ecmascript/object_factory.h" #include "ecmascript/property_detector-inl.h" +#include "ecmascript/shared_objects/js_shared_typed_array.h" +#include "ecmascript/shared_objects/js_sendable_arraybuffer.h" namespace panda::ecmascript::base { using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer; @@ -84,6 +87,52 @@ JSTaggedValue TypedArrayHelper::TypedArrayConstructor(EcmaRuntimeCallInfo *argv, return TypedArrayHelper::CreateFromOrdinaryObject(argv, obj, arrayType); } +// es11 22.2.4 The TypedArray Constructors +JSTaggedValue TypedArrayHelper::SharedTypedArrayConstructor(EcmaRuntimeCallInfo *argv, + const JSHandle &constructorName, + const DataViewType arrayType) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle newTarget = BuiltinsBase::GetNewTarget(argv); + // 2. If NewTarget is undefined, throw a TypeError exception. + if (newTarget->IsUndefined()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The NewTarget is undefined.", JSTaggedValue::Exception()); + } + // 3. Let constructorName be the String value of the Constructor Name value specified in Table 61 for this + // TypedArray constructor. + // 4. Let O be ? AllocateTypedArray(constructorName, NewTarget, "%TypedArray.prototype%"). + JSHandle firstArg = BuiltinsBase::GetCallArg(argv, 0); + if (!firstArg->IsECMAObject()) { + // es11 22.2.4.1 TypedArray ( ) + uint32_t elementLength = 0; + // es11 22.2.4.2 TypedArray ( length ) + if (!firstArg->IsUndefined()) { + JSTaggedNumber index = JSTaggedValue::ToIndex(thread, firstArg); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + elementLength = static_cast(index.GetNumber()); + } + JSHandle obj = TypedArrayHelper::AllocateSharedTypedArray(thread, constructorName, newTarget, + elementLength, arrayType); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return obj.GetTaggedValue(); + } + + JSHandle obj = TypedArrayHelper::AllocateSharedTypedArray(thread, constructorName, newTarget, arrayType); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (firstArg->IsTypedArray() || firstArg->IsSharedTypedArray()) { + return TypedArrayHelper::CreateFromTypedArray(argv, obj, arrayType); + } + if (firstArg->IsArrayBuffer() || firstArg->IsSharedArrayBuffer() || firstArg->IsSendableArrayBuffer()) { + return TypedArrayHelper::CreateFromSendableArrayBuffer(argv, obj, arrayType); + } + if (firstArg->IsStableJSArray(thread)) { + return TypedArrayHelper::FastCopyElementFromArray(argv, obj, arrayType); + } + return TypedArrayHelper::CreateFromSendableOrdinaryObject(argv, obj, arrayType); +} + JSTaggedValue TypedArrayHelper::FastCopyElementFromArray(EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType) { @@ -201,6 +250,100 @@ JSTaggedValue TypedArrayHelper::CreateFromOrdinaryObject(EcmaRuntimeCallInfo *ar return obj.GetTaggedValue(); } +// es11 22.2.4.4 TypedArray ( object ) +JSTaggedValue TypedArrayHelper::CreateFromSendableOrdinaryObject(EcmaRuntimeCallInfo *argv, + const JSHandle &obj, + const DataViewType arrayType) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + EcmaVM *ecmaVm = thread->GetEcmaVM(); + JSHandle env = ecmaVm->GetGlobalEnv(); + JSHandle objectArg = BuiltinsBase::GetCallArg(argv, 0); + JSHandle object(objectArg); + // 5. Let usingIterator be ? GetMethod(object, @@iterator). + JSHandle iteratorSymbol = env->GetIteratorSymbol(); + JSHandle usingIterator = + JSObject::GetMethod(thread, JSHandle::Cast(object), iteratorSymbol); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 6. If usingIterator is not undefined, then + if (!usingIterator->IsUndefined()) { + CVector> vec; + // a. Let values be ? IterableToList(object, usingIterator). + // b. Let len be the number of elements in values. + // c. Perform ? AllocateTypedArrayBuffer(O, len). + JSHandle iterator = JSIterator::GetIterator(thread, objectArg, usingIterator); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle next(thread, JSTaggedValue::True()); + while (!next->IsFalse()) { + next = JSIterator::IteratorStep(thread, iterator); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (!next->IsFalse()) { + JSHandle nextValue = JSIterator::IteratorValue(thread, next); + vec.push_back(nextValue); + } + } + uint32_t len = static_cast(vec.size()); + TypedArrayHelper::AllocateSharedTypedArrayBuffer(thread, obj, len, arrayType); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // d. Let k be 0. + // e. Repeat, while k < len + // i. Let Pk be ! ToString(k). + // ii. Let kValue be the first element of values and remove that element from values. + // iii. Perform ? Set(O, Pk, kValue, true). + // iv. Set k to k + 1. + JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + uint32_t k = 0; + while (k < len) { + tKey.Update(JSTaggedValue(k)); + JSHandle kKey(JSTaggedValue::ToString(thread, tKey)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle kValue = vec[k]; + JSTaggedValue::SetProperty(thread, JSHandle::Cast(obj), kKey, kValue, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + } + // f. Assert: values is now an empty List. + // g. Return O. + return obj.GetTaggedValue(); + } + + // 7. NOTE: object is not an Iterable so assume it is already an array-like object. + // 8. Let arrayLike be object. + // 9. Let len be ? LengthOfArrayLike(arrayLike). + JSHandle lengthKey = thread->GlobalConstants()->GetHandledLengthString(); + JSTaggedNumber lenTemp = + JSTaggedValue::ToLength(thread, JSTaggedValue::GetProperty(thread, objectArg, lengthKey).GetValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + uint64_t rawLen = lenTemp.GetNumber(); + // 10. Perform ? AllocateTypedArrayBuffer(O, len). + TypedArrayHelper::AllocateSharedTypedArrayBuffer(thread, obj, rawLen, arrayType); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 11. Let k be 0. + // 12. Repeat, while k < len + // a. Let Pk be ! ToString(k). + // b. Let kValue be ? Get(arrayLike, Pk). + // c. Perform ? Set(O, Pk, kValue, true). + // d. Set k to k + 1. + JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + uint32_t len = static_cast(rawLen); + uint32_t k = 0; + while (k < len) { + tKey.Update(JSTaggedValue(k)); + JSHandle kKey(JSTaggedValue::ToString(thread, tKey)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle kValue = JSTaggedValue::GetProperty(thread, objectArg, kKey).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSTaggedValue::SetProperty(thread, JSHandle::Cast(obj), kKey, kValue, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + } + // 13. Return O. + return obj.GetTaggedValue(); +} + // es11 22.2.4.3 TypedArray ( typedArray ) JSTaggedValue TypedArrayHelper::CreateFromTypedArray(EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType) @@ -376,6 +519,78 @@ JSTaggedValue TypedArrayHelper::CreateFromArrayBuffer(EcmaRuntimeCallInfo *argv, return obj.GetTaggedValue(); } +// es11 22.2.4.5 TypedArray ( buffer [ , byteOffset [ , length ] ] ) +JSTaggedValue TypedArrayHelper::CreateFromSendableArrayBuffer(EcmaRuntimeCallInfo *argv, + const JSHandle &obj, + const DataViewType arrayType) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName. + // 6. Let offset be ? ToIndex(byteOffset). + uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType); + JSHandle byteOffset = BuiltinsBase::GetCallArg(argv, 1); + JSTaggedNumber index = JSTaggedValue::ToIndex(thread, byteOffset); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + auto offset = static_cast(index.GetNumber()); + // 7. If offset modulo elementSize ≠ 0, throw a RangeError exception. + if (offset % elementSize != 0) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The offset cannot be an integral multiple of elementSize.", + JSTaggedValue::Exception()); + } + // 8. If length is not undefined, then + // a. Let newLength be ? ToIndex(length). + JSHandle length = BuiltinsBase::GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); + uint64_t newLength = 0; + if (!length->IsUndefined()) { + index = JSTaggedValue::ToIndex(thread, length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + newLength = static_cast(index.GetNumber()); + } + // 9. If IsDetachedBuffer(buffer) is true, throw a TypeError exception. + JSHandle buffer = BuiltinsBase::GetCallArg(argv, 0); + if (builtins::BuiltinsSendableArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The srcData is detached buffer.", JSTaggedValue::Exception()); + } + // 10. Let bufferByteLength be buffer.[[ArrayBufferByteLength]]. + uint32_t bufferByteLength = JSHandle(buffer)->GetArrayBufferByteLength(); + // 11. If length is undefined, then + // a. If bufferByteLength modulo elementSize ≠ 0, throw a RangeError exception. + // b. Let newByteLength be bufferByteLength - offset. + // c. If newByteLength < 0, throw a RangeError exception. + uint64_t newByteLength = 0; + if (length->IsUndefined()) { + if (bufferByteLength % elementSize != 0) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The bufferByteLength cannot be an integral multiple of elementSize.", + JSTaggedValue::Exception()); + } + if (bufferByteLength < offset) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is less than 0.", JSTaggedValue::Exception()); + } + newByteLength = bufferByteLength - offset; + } else { + // 12. Else, + // a. Let newByteLength be newLength × elementSize. + // b. If offset + newByteLength > bufferByteLength, throw a RangeError exception. + newByteLength = newLength * elementSize; + if (offset + newByteLength > bufferByteLength) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The newByteLength is out of range.", JSTaggedValue::Exception()); + } + } + // 13. Set O.[[ViewedArrayBuffer]] to buffer. + // 14. Set O.[[ByteLength]] to newByteLength. + // 15. Set O.[[ByteOffset]] to offset. + // 16. Set O.[[ArrayLength]] to newByteLength / elementSize. + JSSharedTypedArray *jsTypedArray = JSSharedTypedArray::Cast(*obj); + jsTypedArray->SetViewedArrayBufferOrByteArray(thread, buffer); + jsTypedArray->SetByteLength(newByteLength); + jsTypedArray->SetByteOffset(offset); + jsTypedArray->SetArrayLength(newByteLength / elementSize); + // 17. Return O. + return obj.GetTaggedValue(); +} + // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto ) JSHandle TypedArrayHelper::AllocateTypedArray(JSThread *thread, const JSHandle &constructorName, @@ -413,6 +628,43 @@ JSHandle TypedArrayHelper::AllocateTypedArray(JSThread *thread, return obj; } +// es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto ) +JSHandle TypedArrayHelper::AllocateSharedTypedArray(JSThread *thread, + const JSHandle &constructorName, + const JSHandle &newTarget, + const DataViewType arrayType) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto). + // 2. Let obj be ! IntegerIndexedObjectCreate(proto). + JSHandle typedArrayFunc = TypedArrayHelper::GetSharedConstructorFromType(thread, arrayType); + JSHandle obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle(thread, JSTaggedValue::Exception())); + // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined. + // 4. Set obj.[[TypedArrayName]] to constructorName. + + // 5. If constructorName is "BigInt64Array" or "BigUint64Array", set obj.[[ContentType]] to BigInt. + // 6. Otherwise, set obj.[[ContentType]] to Number. + JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj); + if (arrayType == DataViewType::BIGINT64 || + arrayType == DataViewType::BIGUINT64) { + jsTypedArray->SetContentType(ContentType::BigInt); + } else { + jsTypedArray->SetContentType(ContentType::Number); + } + // 7. If length is not present, then + // a. Set obj.[[ByteLength]] to 0. + // b. Set obj.[[ByteOffset]] to 0. + // c. Set obj.[[ArrayLength]] to 0. + jsTypedArray->SetTypedArrayName(thread, constructorName); + jsTypedArray->SetByteLength(0); + jsTypedArray->SetByteOffset(0); + jsTypedArray->SetArrayLength(0); + ASSERT_PRINT(!JSHandle(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap"); + // 9. Return obj. + return obj; +} + // es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto, length ) JSHandle TypedArrayHelper::AllocateTypedArray(JSThread *thread, const JSHandle &constructorName, @@ -437,6 +689,30 @@ JSHandle TypedArrayHelper::AllocateTypedArray(JSThread *thread, return obj; } +// es11 22.2.4.2.1 Runtime Semantics: AllocateTypedArray ( constructorName, newTarget, defaultProto, length ) +JSHandle TypedArrayHelper::AllocateSharedTypedArray(JSThread *thread, + const JSHandle &constructorName, + const JSHandle &newTarget, + uint32_t length, const DataViewType arrayType) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 1. Let proto be ? GetPrototypeFromConstructor(newTarget, defaultProto). + // 2. Let obj be ! IntegerIndexedObjectCreate(proto). + JSHandle typedArrayFunc = TypedArrayHelper::GetSharedConstructorFromType(thread, arrayType); + JSHandle obj = factory->NewJSObjectByConstructor(typedArrayFunc, newTarget); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle(thread, JSTaggedValue::Exception())); + // 3. Assert: obj.[[ViewedArrayBuffer]] is undefined. + // 4. Set obj.[[TypedArrayName]] to constructorName. + JSSharedTypedArray::Cast(*obj)->SetTypedArrayName(thread, constructorName); + // 7. If length is not present, then + // 8. Else, + // a. Perform ? AllocateTypedArrayBuffer(obj, length). + TypedArrayHelper::AllocateSharedTypedArrayBuffer(thread, obj, length, arrayType); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle(thread, JSTaggedValue::Exception())); + // 9. Return obj. + return obj; +} + // es11 22.2.4.2.2 Runtime Semantics: AllocateTypedArrayBuffer ( O, length ) JSHandle TypedArrayHelper::AllocateTypedArrayBuffer(JSThread *thread, const JSHandle &obj, uint64_t length, @@ -491,6 +767,56 @@ JSHandle TypedArrayHelper::AllocateTypedArrayBuffer(JSThread *thread, return obj; } +JSHandle TypedArrayHelper::AllocateSharedTypedArrayBuffer(JSThread *thread, + const JSHandle &obj, uint64_t length, const DataViewType arrayType) +{ + // 1. Assert: O is an Object that has a [[ViewedArrayBuffer]] internal slot. + // 2. Assert: O.[[ViewedArrayBuffer]] is undefined. + // 3. Assert: ! IsNonNegativeInteger(length) is true. + JSHandle exception(thread, JSTaggedValue::Exception()); + if (length > JSTypedArray::MAX_TYPED_ARRAY_INDEX) { + THROW_RANGE_ERROR_AND_RETURN(thread, "array length must less than 2^32 - 1", exception); + } + // 4. Let constructorName be the String value of O.[[TypedArrayName]]. + // we use type to get size + // 5. Let elementSize be the Element Size value specified in Table 61 for constructorName. + uint32_t elementSize = TypedArrayHelper::GetSizeFromType(arrayType); + // 6. Let byteLength be elementSize × length. + uint32_t arrayLength = static_cast(length); + uint64_t byteLength = static_cast(elementSize) * length; + // 7. Let data be ? AllocateArrayBuffer(%ArrayBuffer%, byteLength). + JSHandle data; + if (byteLength > JSTypedArray::MAX_ONHEAP_LENGTH) { + JSHandle constructor = thread->GetEcmaVM()->GetGlobalEnv()->GetArrayBufferFunction(); + data = JSHandle(thread, + builtins::BuiltinsSendableArrayBuffer::AllocateSendableArrayBuffer(thread, constructor, byteLength)); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle(thread, JSTaggedValue::Exception())); + ASSERT_PRINT(!JSHandle(obj)->GetClass()->IsOnHeapFromBitField(), "must be not on heap"); + } else { + data = JSHandle(thread, + thread->GetEcmaVM()->GetFactory()->NewByteArray(arrayLength, elementSize, nullptr, + MemSpaceType::SHARED_OLD_SPACE).GetTaggedValue()); + } + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, exception); + JSTypedArray *jsTypedArray = JSTypedArray::Cast(*obj); + if (arrayType == DataViewType::BIGINT64 || + arrayType == DataViewType::BIGUINT64) { + jsTypedArray->SetContentType(ContentType::BigInt); + } else { + jsTypedArray->SetContentType(ContentType::Number); + } + // 8. Set O.[[ViewedArrayBuffer]] to data. + // 9. Set O.[[ByteLength]] to byteLength. + // 10. Set O.[[ByteOffset]] to 0. + // 11. Set O.[[ArrayLength]] to length. + jsTypedArray->SetViewedArrayBufferOrByteArray(thread, data); + jsTypedArray->SetByteLength(byteLength); + jsTypedArray->SetByteOffset(0); + jsTypedArray->SetArrayLength(arrayLength); + // 12. Return O. + return obj; +} + // es11 22.2.4.7 TypedArraySpeciesCreate ( exemplar, argumentList ) JSHandle TypedArrayHelper::TypedArraySpeciesCreate(JSThread *thread, const JSHandle &obj, uint32_t argc, JSTaggedType argv[]) @@ -599,7 +925,7 @@ JSTaggedValue TypedArrayHelper::ValidateTypedArray(JSThread *thread, const JSHan { // 1. Perform ? RequireInternalSlot(O, [[TypedArrayName]]). // 2. Assert: O has a [[ViewedArrayBuffer]] internal slot. - if (!value->IsTypedArray()) { + if (!value->IsTypedArray() && !value->IsSharedTypedArray()) { THROW_TYPE_ERROR_AND_RETURN(thread, "The O is not a TypedArray.", JSTaggedValue::Exception()); } // 3. Let buffer be O.[[ViewedArrayBuffer]]. diff --git a/ecmascript/base/typed_array_helper.h b/ecmascript/base/typed_array_helper.h index 87d8211cf974d6ce9500d916660d1bbe796612da..d3b645a805f58b603e824f6c26365eff40ac46db 100644 --- a/ecmascript/base/typed_array_helper.h +++ b/ecmascript/base/typed_array_helper.h @@ -31,6 +31,9 @@ public: static JSTaggedValue TypedArrayConstructor(EcmaRuntimeCallInfo *argv, const JSHandle &constructorName, const DataViewType arrayType); + static JSTaggedValue SharedTypedArrayConstructor(EcmaRuntimeCallInfo *argv, + const JSHandle &constructorName, + const DataViewType arrayType); static JSHandle AllocateTypedArray(JSThread *thread, const JSHandle &constructorName, const JSHandle &newTarget, @@ -39,6 +42,14 @@ public: const JSHandle &constructorName, const JSHandle &newTarget, uint32_t length, const DataViewType arrayType); + static JSHandle AllocateSharedTypedArray(JSThread *thread, + const JSHandle &constructorName, + const JSHandle &newTarget, + const DataViewType arrayType); + static JSHandle AllocateSharedTypedArray(JSThread *thread, + const JSHandle &constructorName, + const JSHandle &newTarget, uint32_t length, + const DataViewType arrayType); static JSHandle TypedArraySpeciesCreate(JSThread *thread, const JSHandle &obj, uint32_t argc, JSTaggedType argv[]); static JSHandle TypedArrayCreate(JSThread *thread, const JSHandle &constructor, @@ -55,6 +66,12 @@ public: const DataViewType arrayType); inline static JSHandle GetConstructorNameFromType(JSThread *thread, const DataViewType arrayType); + + inline static JSHandle GetSharedConstructorFromType(JSThread *thread, + const DataViewType arrayType); + inline static JSHandle GetSharedConstructorNameFromType(JSThread *thread, + const DataViewType arrayType); + inline static JSHandle GetOnHeapHclassFromType( JSThread *thread, const JSHandle &obj, const DataViewType arrayType); inline static JSHandle GetNotOnHeapHclassFromType( @@ -78,12 +95,19 @@ public: private: static JSTaggedValue CreateFromOrdinaryObject(EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType); + static JSTaggedValue CreateFromSendableOrdinaryObject(EcmaRuntimeCallInfo *argv, const JSHandle &obj, + const DataViewType arrayType); static JSTaggedValue CreateFromTypedArray(EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType); static JSTaggedValue CreateFromArrayBuffer(EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType); + static JSTaggedValue CreateFromSendableArrayBuffer(EcmaRuntimeCallInfo *argv, + const JSHandle &obj, + const DataViewType arrayType); static JSHandle AllocateTypedArrayBuffer(JSThread *thread, const JSHandle &obj, uint64_t length, const DataViewType arrayType); + static JSHandle AllocateSharedTypedArrayBuffer(JSThread *thread, const JSHandle &obj, + uint64_t length, const DataViewType arrayType); static JSTaggedValue FastCopyElementFromArray(EcmaRuntimeCallInfo *argv, const JSHandle &obj, const DataViewType arrayType); }; diff --git a/ecmascript/builtins/builtins.cpp b/ecmascript/builtins/builtins.cpp index 61aa6bdb0501dd232c826f4384fa899e4ada2c26..72f29908c8b8db933b9f26428dff4036e0a710a0 100644 --- a/ecmascript/builtins/builtins.cpp +++ b/ecmascript/builtins/builtins.cpp @@ -51,6 +51,7 @@ #include "ecmascript/builtins/builtins_regexp.h" #include "ecmascript/builtins/builtins_set.h" #include "ecmascript/builtins/builtins_sharedarraybuffer.h" +#include "ecmascript/builtins/builtins_shared_typedarray.h" #include "ecmascript/builtins/builtins_string.h" #include "ecmascript/builtins/builtins_string_iterator.h" #include "ecmascript/builtins/builtins_symbol.h" @@ -60,6 +61,7 @@ #include "ecmascript/builtins/builtins_weak_set.h" #include "ecmascript/containers/containers_private.h" #include "ecmascript/ecma_runtime_call_info.h" +#include "ecmascript/global_index.h" #include "ecmascript/js_array.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_array_iterator.h" @@ -92,6 +94,9 @@ #include "ecmascript/require/js_cjs_module_cache.h" #include "ecmascript/require/js_cjs_require.h" #include "ecmascript/require/js_cjs_exports.h" +#include "ecmascript/shared_objects/js_shared_array_iterator.h" +#include "ecmascript/shared_objects/js_shared_map_iterator.h" +#include "ecmascript/shared_objects/js_shared_set_iterator.h" #include "ecmascript/symbol_table.h" #include "ecmascript/marker_cell.h" #include "ecmascript/napi/include/jsnapi.h" @@ -165,6 +170,7 @@ using Math = builtins::BuiltinsMath; using Atomics = builtins::BuiltinsAtomics; using ArrayBuffer = builtins::BuiltinsArrayBuffer; using Json = builtins::BuiltinsJson; +using SendableJson = builtins::BuiltinsSendableJson; using Proxy = builtins::BuiltinsProxy; using Reflect = builtins::BuiltinsReflect; using AsyncFunction = builtins::BuiltinsAsyncFunction; @@ -200,6 +206,7 @@ using AsyncGeneratorObject = builtins::BuiltinsAsyncGenerator; void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool lazyInit, bool isRealm) { + thread->CheckSafepointIfSuspended(); thread_ = thread; vm_ = thread->GetEcmaVM(); factory_ = vm_->GetFactory(); @@ -243,6 +250,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool // initialize Function, forbidden change order InitializeFunction(env, emptyFuncClass); + thread->CheckSafepointIfSuspended(); JSHandle asyncAwaitStatusFuncClass = factory_->CreateFunctionClass(FunctionKind::NORMAL_FUNCTION, JSAsyncAwaitStatusFunction::SIZE, JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION, env->GetFunctionPrototype()); @@ -283,9 +291,17 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool JSType::JS_FUNCTION, env->GetFunctionPrototype()); env->SetFunctionClassWithoutName(thread_, functionClass); + thread->CheckSafepointIfSuspended(); functionClass = factory_->CreateBoundFunctionClass(); env->SetBoundFunctionClass(thread_, functionClass); - + auto runtimeGlobalEnv = Runtime::GetInstance()->GetGlobalEnv(); + if (runtimeGlobalEnv.IsHole()) { + InitializeSSymbolAttributes(env); + InitializeSObjectAndSFunction(env); + } else { + CopySObjectAndSFunction(env, runtimeGlobalEnv); + RegisterSendableContainers(env); + } if (!isRealm) { InitializeAllTypeError(env, objFuncClass); InitializeSymbol(env, primRefObjHClass); @@ -297,6 +313,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool InitializeBigIntWithRealm(env); } + thread->CheckSafepointIfSuspended(); InitializeArray(env, objFuncPrototypeVal); if (lazyInit) { LazyInitializeDate(env); @@ -323,17 +340,12 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool InitializeDataView(env, objFuncPrototypeVal); InitializeSharedArrayBuffer(env, objFuncClass); } + thread->CheckSafepointIfSuspended(); InitializeNumber(env, globalObject, primRefObjHClass); InitializeObject(env, objFuncPrototype, objectFunction); InitializeBoolean(env, primRefObjHClass); InitializeRegExp(env); InitializeString(env, objFuncPrototypeVal); - auto runtimeGlobalEnv = Runtime::GetInstance()->GetGlobalEnv(); - if (runtimeGlobalEnv.IsHole()) { - InitializeSObjectAndSFunction(env); - } else { - CopySObjectAndSFunction(env, runtimeGlobalEnv); - } JSHandle argumentsClass = factory_->CreateJSArguments(env); env->SetArgumentsClass(thread_, argumentsClass); SetArgumentsSharedAccessor(env); @@ -342,6 +354,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool InitializeGlobalObject(env, globalObject); InitializeAtomics(env, objFuncPrototypeVal); InitializeJson(env, objFuncPrototypeVal); + InitializeSendableJson(env, objFuncPrototypeVal); InitializeIterator(env, objFuncClass); InitializeAsyncIterator(env, objFuncClass); InitializeAsyncFromSyncIterator(env, objFuncClass); @@ -354,6 +367,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool InitializeAsyncGeneratorFunction(env, objFuncClass); InitializePromise(env, objFuncClass); InitializePromiseJob(env); + thread->CheckSafepointIfSuspended(); #ifdef ARK_SUPPORT_INTL InitializeIntl(env, objFuncPrototypeVal); if (lazyInit) { @@ -379,6 +393,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool InitializeSegments(env); InitializeSegmenter(env); } + thread->CheckSafepointIfSuspended(); #endif InitializeModuleNamespace(env, objFuncClass); InitializeCjsModule(env); @@ -402,6 +417,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread, bool env->SetAsyncFunctionClass(thread_, asyncFuncClass); thread_->ResetGuardians(); + thread->CheckSafepointIfSuspended(); if (vm_->GetJSOptions().IsEnableLoweringBuiltin()) { if (!lazyInit) { thread_->InitializeBuiltinObject(); @@ -476,8 +492,10 @@ void Builtins::InitializeGlobalObject(const JSHandle &env, const JSHa // Global object function SetFunction(env, globalObject, "eval", Global::NotSupportEval, FunctionLength::ONE); - SetFunction(env, globalObject, "isFinite", Global::IsFinite, FunctionLength::ONE); - SetFunction(env, globalObject, "isNaN", Global::IsNaN, FunctionLength::ONE); + SetFunction(env, globalObject, "isFinite", Global::IsFinite, FunctionLength::ONE, + kungfu::BuiltinsStubCSigns::GlobalIsFinite); + SetFunction(env, globalObject, "isNaN", Global::IsNaN, FunctionLength::ONE, + kungfu::BuiltinsStubCSigns::GlobalIsNan); SetFunction(env, globalObject, "decodeURI", Global::DecodeURI, FunctionLength::ONE); SetFunction(env, globalObject, "encodeURI", Global::EncodeURI, FunctionLength::ONE); SetFunction(env, globalObject, "escape", Global::Escape, FunctionLength::ONE); @@ -570,6 +588,10 @@ void Builtins::InitializeObject(const JSHandle &env, const JSHandle protoGetter = CreateGetter(env, Object::ProtoGetter, "__proto__", FunctionLength::ZERO); JSHandle protoSetter = CreateSetter(env, Object::ProtoSetter, "__proto__", FunctionLength::ONE); SetAccessor(objFuncPrototype, protoKey, protoGetter, protoSetter); + + GlobalIndex globalIndex; + globalIndex.UpdateGlobalEnvId(static_cast(GlobalEnvField::OBJECT_FUNCTION_INDEX)); + thread_->SetInitialBuiltinGlobalHClass(objFunc->GetJSHClass(), globalIndex); } void Builtins::InitializeSymbol(const JSHandle &env, const JSHandle &objFuncClass) const @@ -600,53 +622,12 @@ void Builtins::InitializeSymbol(const JSHandle &env, const JSHandle hasInstanceSymbol(factory_->NewSWellKnownSymbolWithChar("Symbol.hasInstance")); - SetNoneAttributeProperty(symbolFunction, "hasInstance", hasInstanceSymbol); - JSHandle isConcatSpreadableSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.isConcatSpreadable")); - SetNoneAttributeProperty(symbolFunction, "isConcatSpreadable", isConcatSpreadableSymbol); - JSHandle toStringTagSymbol(factory_->NewWellKnownSymbolWithChar("Symbol.toStringTag")); - SetNoneAttributeProperty(symbolFunction, "toStringTag", toStringTagSymbol); - JSHandle asyncIteratorSymbol(factory_->NewPublicSymbolWithChar("Symbol.asyncIterator")); - SetNoneAttributeProperty(symbolFunction, "asyncIterator", asyncIteratorSymbol); - JSHandle matchSymbol(factory_->NewPublicSymbolWithChar("Symbol.match")); - SetNoneAttributeProperty(symbolFunction, "match", matchSymbol); - JSHandle matchAllSymbol(factory_->NewPublicSymbolWithChar("Symbol.matchAll")); - SetNoneAttributeProperty(symbolFunction, "matchAll", matchAllSymbol); - JSHandle searchSymbol(factory_->NewPublicSymbolWithChar("Symbol.search")); - SetNoneAttributeProperty(symbolFunction, "search", searchSymbol); - JSHandle toPrimitiveSymbol(factory_->NewPublicSymbolWithChar("Symbol.toPrimitive")); - SetNoneAttributeProperty(symbolFunction, "toPrimitive", toPrimitiveSymbol); - JSHandle unscopablesSymbol(factory_->NewPublicSymbolWithChar("Symbol.unscopables")); - SetNoneAttributeProperty(symbolFunction, "unscopables", unscopablesSymbol); - JSHandle nativeBindingSymbol(factory_->NewPublicSymbolWithChar("Symbol.nativeBinding")); - SetNoneAttributeProperty(symbolFunction, "nativeBinding", nativeBindingSymbol); - - // Symbol attributes with detectors - // Create symbol string before create symbol to allocate symbol continuously - // Attention: Symbol serialization & deserialization are not supported now and - // the order of symbols and symbol-strings must be maintained too when - // Symbol serialization & deserialization are ready. -#define INIT_SYMBOL_STRING(name, description, key) \ - { \ - [[maybe_unused]] JSHandle string = factory_->NewFromUtf8(description); \ - } -DETECTOR_SYMBOL_LIST(INIT_SYMBOL_STRING) -#undef INIT_SYMBOL_STRING - -#define INIT_PUBLIC_SYMBOL(name, description, key) \ - JSHandle key##Symbol = factory_->NewEmptySymbol(); \ - JSHandle key##String = factory_->NewFromUtf8(description); \ - key##Symbol->SetDescription(thread_, key##String.GetTaggedValue()); \ - key##Symbol->SetHashField(SymbolTable::Hash(key##String.GetTaggedValue())); \ - env->Set##name(thread_, key##Symbol); -DETECTOR_SYMBOL_LIST(INIT_PUBLIC_SYMBOL) -#undef INIT_PUBLIC_SYMBOL - -#define REGISTER_SYMBOL(name, description, key) \ - SetNoneAttributeProperty(symbolFunction, #key, JSHandle(key##Symbol)); -DETECTOR_SYMBOL_LIST(REGISTER_SYMBOL) -#undef REGISTER_SYMBOL + // Symbol attributes +#define REGISTER_SYMBOL(name, Name) \ + SetNoneAttributeProperty(symbolFunction, #name, env->Get##Name##Symbol()); + +BUILTIN_ALL_SYMBOLS(REGISTER_SYMBOL) + env->SetSymbolFunction(thread_, symbolFunction); // symbol.prototype.description PropertyDescriptor descriptionDesc(thread_); @@ -656,26 +637,14 @@ DETECTOR_SYMBOL_LIST(REGISTER_SYMBOL) // Setup symbol.prototype[@@toPrimitive] SetFunctionAtSymbol( - env, symbolFuncPrototype, toPrimitiveSymbol, "[Symbol.toPrimitive]", Symbol::ToPrimitive, FunctionLength::ONE); + env, symbolFuncPrototype, env->GetToPrimitiveSymbol(), "[Symbol.toPrimitive]", + Symbol::ToPrimitive, FunctionLength::ONE); // install the Symbol.prototype methods SetFunction(env, symbolFuncPrototype, thread_->GlobalConstants()->GetHandledToStringString(), Symbol::ToString, FunctionLength::ZERO); SetFunction(env, symbolFuncPrototype, thread_->GlobalConstants()->GetHandledValueOfString(), Symbol::ValueOf, FunctionLength::ZERO); - env->SetSymbolFunction(thread_, symbolFunction); - env->SetHasInstanceSymbol(thread_, hasInstanceSymbol); - env->SetIsConcatSpreadableSymbol(thread_, isConcatSpreadableSymbol); - env->SetToStringTagSymbol(thread_, toStringTagSymbol); - env->SetAsyncIteratorSymbol(thread_, asyncIteratorSymbol); - env->SetMatchSymbol(thread_, matchSymbol); - env->SetMatchAllSymbol(thread_, matchAllSymbol); - env->SetSearchSymbol(thread_, searchSymbol); - env->SetSpeciesSymbol(thread_, speciesSymbol); - env->SetToPrimitiveSymbol(thread_, toPrimitiveSymbol); - env->SetUnscopablesSymbol(thread_, unscopablesSymbol); - env->SetNativeBindingSymbol(thread_, nativeBindingSymbol); - // Setup %SymbolPrototype% SetStringTagSymbol(env, symbolFuncPrototype, "Symbol"); @@ -1590,7 +1559,7 @@ void Builtins::InitializeMath(const JSHandle &env, const JSHandle mathClass = factory_->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, objFuncPrototypeVal); JSHandle mathObject = factory_->NewJSObjectWithInit(mathClass); - RandomGenerator::InitRandom(); + RandomGenerator::InitRandom(thread_); for (const base::BuiltinFunctionEntry &entry: Math::GetMathFunctions()) { SetFunction(env, mathObject, entry.GetName(), entry.GetEntrypoint(), @@ -1599,7 +1568,6 @@ void Builtins::InitializeMath(const JSHandle &env, const JSHandle mathString(factory_->NewFromASCII("Math")); JSHandle globalObject(thread_, env->GetGlobalObject()); PropertyDescriptor mathDesc(thread_, JSHandle::Cast(mathObject), true, false, true); @@ -1616,7 +1584,7 @@ void Builtins::InitializeJson(const JSHandle &env, const JSHandle jsonObject = factory_->NewJSObjectWithInit(jsonHClass); SetFunction(env, jsonObject, "parse", Json::Parse, FunctionLength::TWO); - SetFunction(env, jsonObject, "stringify", Json::Stringify, FunctionLength::THREE, BUILTINS_STUB_ID(STRINGIFY)); + SetFunction(env, jsonObject, "stringify", Json::Stringify, FunctionLength::THREE, BUILTINS_STUB_ID(JsonStringify)); PropertyDescriptor jsonDesc(thread_, JSHandle::Cast(jsonObject), true, false, true); JSHandle jsonString(factory_->NewFromASCII("JSON")); @@ -1627,6 +1595,23 @@ void Builtins::InitializeJson(const JSHandle &env, const JSHandleSetJsonFunction(thread_, jsonObject); } +void Builtins::InitializeSendableJson(const JSHandle &env, + const JSHandle &objFuncPrototypeVal) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + JSHandle jsonHClass = factory_->NewEcmaHClass(JSObject::SIZE, JSType::JS_OBJECT, objFuncPrototypeVal); + JSHandle jsonObject = factory_->NewJSObjectWithInit(jsonHClass); + + SetFunction(env, jsonObject, "parse", SendableJson::Parse, FunctionLength::TWO); + PropertyDescriptor jsonDesc(thread_, JSHandle::Cast(jsonObject), true, false, true); + JSHandle jsonString(factory_->NewFromASCII("SENDABLE_JSON")); + JSHandle globalObject(thread_, env->GetGlobalObject()); + JSObject::DefineOwnProperty(thread_, globalObject, jsonString, jsonDesc); + // @@ToStringTag + SetStringTagSymbol(env, jsonObject, "SENDABLE_JSON"); + env->SetJsonFunction(thread_, jsonObject); +} + void Builtins::InitializeString(const JSHandle &env, JSHandle objFuncPrototypeVal) const { [[maybe_unused]] EcmaHandleScope scope(thread_); @@ -1657,7 +1642,7 @@ void Builtins::InitializeString(const JSHandle &env, JSHandle stringIter = SetAndReturnFunctionAtSymbol(env, stringFuncPrototype, env->GetIteratorSymbol(), "[Symbol.iterator]", BuiltinsString::GetStringIterator, FunctionLength::ZERO, - BUILTINS_STUB_ID(GetStringIterator)); + BUILTINS_STUB_ID(StringGetStringIterator)); // String method for (const base::BuiltinFunctionEntry &entry: BuiltinsString::GetStringFunctions()) { @@ -1692,7 +1677,7 @@ void Builtins::InitializeStringIterator(const JSHandle &env, strIterFuncInstanceHClass.GetTaggedValue()); SetFunction(env, strIterPrototype, "next", StringIterator::Next, FunctionLength::ZERO, - BUILTINS_STUB_ID(STRING_ITERATOR_PROTO_NEXT)); + BUILTINS_STUB_ID(StringIteratorProtoNext)); SetStringTagSymbol(env, strIterPrototype, "String Iterator"); env->SetStringIterator(thread_, strIterFunction); @@ -1736,7 +1721,7 @@ void Builtins::InitializeIterator(const JSHandle &env, const JSHandle SetFunction(env, iteratorPrototype, "next", BuiltinsIterator::Next, FunctionLength::ONE); // Iterator.prototype.return() SetFunction(env, iteratorPrototype, "return", BuiltinsIterator::Return, FunctionLength::ONE, - BUILTINS_STUB_ID(ITERATOR_PROTO_RETURN)); + BUILTINS_STUB_ID(IteratorProtoReturn)); // Iterator.prototype.throw() SetFunction(env, iteratorPrototype, "throw", BuiltinsIterator::Throw, FunctionLength::ONE); // %IteratorPrototype% [ @@iterator ] @@ -1768,8 +1753,11 @@ void Builtins::InitializeIterator(const JSHandle &env, const JSHandle InitializeForinIterator(env, iteratorFuncClass); InitializeSetIterator(env, iteratorFuncClass); + InitializeSSetIterator(env, iteratorFuncClass); InitializeMapIterator(env, iteratorFuncClass); + InitializeSMapIterator(env, iteratorFuncClass); InitializeArrayIterator(env, iteratorFuncClass, iteratorPrototypeHClass); + InitializeSArrayIterator(env, iteratorFuncClass); InitializeStringIterator(env, iteratorFuncClass); InitializeRegexpIterator(env, iteratorFuncClass); #ifdef ARK_SUPPORT_INTL @@ -1824,7 +1812,7 @@ void Builtins::InitializeSetIterator(const JSHandle &env, JSHandle setIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass)); // Iterator.prototype.next() SetFunction(env, setIteratorPrototype, "next", JSSetIterator::Next, FunctionLength::ZERO, - BUILTINS_STUB_ID(SET_ITERATOR_PROTO_NEXT)); + BUILTINS_STUB_ID(SetIteratorProtoNext)); SetStringTagSymbol(env, setIteratorPrototype, "Set Iterator"); env->SetSetIteratorPrototype(thread_, setIteratorPrototype); JSHandle protoValue = env->GetSetIteratorPrototype(); @@ -1834,6 +1822,21 @@ void Builtins::InitializeSetIterator(const JSHandle &env, hclassHandle->SetExtensible(true); } +void Builtins::InitializeSSetIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const +{ + // SetIterator.prototype + JSHandle setIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass)); + // Iterator.prototype.next() + SetFunction(env, setIteratorPrototype, "next", JSSharedSetIterator::Next, FunctionLength::ZERO); + SetStringTagSymbol(env, setIteratorPrototype, "SharedSet Iterator"); + env->SetSharedSetIteratorPrototype(thread_, setIteratorPrototype); + JSHandle protoValue = env->GetSharedSetIteratorPrototype(); + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + JSHandle hclassHandle(globalConst->GetHandledJSSharedSetIteratorClass()); + hclassHandle->SetPrototype(thread_, protoValue); + hclassHandle->SetExtensible(true); +} + void Builtins::InitializeMapIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const { @@ -1841,7 +1844,7 @@ void Builtins::InitializeMapIterator(const JSHandle &env, JSHandle mapIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass)); // Iterator.prototype.next() SetFunction(env, mapIteratorPrototype, "next", JSMapIterator::Next, FunctionLength::ZERO, - BUILTINS_STUB_ID(MAP_ITERATOR_PROTO_NEXT)); + BUILTINS_STUB_ID(MapIteratorProtoNext)); SetStringTagSymbol(env, mapIteratorPrototype, "Map Iterator"); env->SetMapIteratorPrototype(thread_, mapIteratorPrototype); JSHandle protoValue = env->GetMapIteratorPrototype(); @@ -1851,6 +1854,22 @@ void Builtins::InitializeMapIterator(const JSHandle &env, hclassHandle->SetExtensible(true); } +void Builtins::InitializeSMapIterator(const JSHandle &env, + const JSHandle &iteratorFuncClass) const +{ + // MapIterator.prototype + JSHandle mapIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass)); + // Iterator.prototype.next() + SetFunction(env, mapIteratorPrototype, "next", JSSharedMapIterator::Next, FunctionLength::ZERO); + SetStringTagSymbol(env, mapIteratorPrototype, "SharedMap Iterator"); + env->SetSharedMapIteratorPrototype(thread_, mapIteratorPrototype); + JSHandle protoValue = env->GetSharedMapIteratorPrototype(); + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + JSHandle hclassHandle(globalConst->GetHandledJSSharedMapIteratorClass()); + hclassHandle->SetPrototype(thread_, protoValue); + hclassHandle->SetExtensible(true); +} + void Builtins::InitializeArrayIterator(const JSHandle &env, const JSHandle &iteratorFuncClass, const JSHandle &iteratorPrototypeClass) const @@ -1862,7 +1881,7 @@ void Builtins::InitializeArrayIterator(const JSHandle &env, JSHandle arrayIteratorInstanceHClass(globalConst->GetHandledJSArrayIteratorClass()); // Iterator.prototype.next() SetFunction(env, arrayIteratorPrototype, "next", JSArrayIterator::Next, FunctionLength::ZERO, - BUILTINS_STUB_ID(ARRAY_ITERATOR_PROTO_NEXT)); + BUILTINS_STUB_ID(ArrayIteratorProtoNext)); arrayIteratorInstanceHClass->SetPrototype(thread_, arrayIteratorPrototypeValue); SetStringTagSymbol(env, arrayIteratorPrototype, "Array Iterator"); thread_->SetInitialBuiltinHClass(BuiltinTypeId::ARRAY_ITERATOR, nullptr, @@ -1870,6 +1889,17 @@ void Builtins::InitializeArrayIterator(const JSHandle &env, env->SetArrayIteratorPrototype(thread_, arrayIteratorPrototype); } +void Builtins::InitializeSArrayIterator(const JSHandle &env, + const JSHandle &iteratorFuncClass) const +{ + // ArrayIterator.prototype + JSHandle arrayIteratorPrototype(factory_->NewJSObjectWithInit(iteratorFuncClass)); + // Iterator.prototype.next() + SetFunction(env, arrayIteratorPrototype, "next", JSSharedArrayIterator::Next, FunctionLength::ZERO); + SetStringTagSymbol(env, arrayIteratorPrototype, "SharedArray Iterator"); + env->SetSharedArrayIteratorPrototype(thread_, arrayIteratorPrototype); +} + void Builtins::InitializeRegexpIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const { @@ -2212,6 +2242,8 @@ void Builtins::Initialize##Type(const JSHandle &env, const JSHandleSetProtoOrHClass(thread_, arrFuncInstanceHClass.GetTaggedValue()); \ SetConstant(arrFuncPrototype, "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); \ SetConstant(JSHandle(arrayFunction), "BYTES_PER_ELEMENT", JSTaggedValue(bytesPerElement)); \ + /* %TypedArray%.protoofprototype (where %TypedArray% is one of Int8Array, Uint8Array, etc.) */ \ + JSTaggedValue protoOfPrototypeValue = arrFuncPrototype->GetJSHClass()->GetPrototype(); \ env->Set##Type##Function(thread_, arrayFunction); \ env->Set##Type##FunctionPrototype(thread_, arrFuncPrototypeValue); \ env->Set##Type##RootHclass(thread_, arrFuncInstanceHClass); \ @@ -2220,7 +2252,9 @@ void Builtins::Initialize##Type(const JSHandle &env, const JSHandleSetInitialBuiltinHClass(BuiltinTypeId::TYPE, \ arrayFunction->GetJSHClass(), \ *arrFuncInstanceHClass, \ - arrFuncPrototype->GetJSHClass()); \ + arrFuncPrototype->GetJSHClass(), \ + protoOfPrototypeValue.IsHeapObject() ? protoOfPrototypeValue.GetTaggedObject()->GetClass() : nullptr, \ + *arrFuncInstanceHClassOnHeap); \ } BUILTIN_TYPED_ARRAY_TYPES(BUILTIN_TYPED_ARRAY_DEFINE_INITIALIZE) @@ -2266,7 +2300,14 @@ void Builtins::InitializeArrayBuffer(const JSHandle &env, const JSHan SetFunction(env, arrayBufferFuncPrototype, "slice", ArrayBuffer::Slice, FunctionLength::TWO); // ArrayBuffer method - SetFunction(env, arrayBufferFunction, "isView", ArrayBuffer::IsView, FunctionLength::ONE); + for (const base::BuiltinFunctionEntry& entry: ArrayBuffer::GetArrayBufferFunctions()) { + SetFunction(env, + arrayBufferFunction, + entry.GetName(), + entry.GetEntrypoint(), + entry.GetLength(), + entry.GetBuiltinStubId()); + } // 24.1.3.3 get ArrayBuffer[@@species] JSHandle speciesSymbol = env->GetSpeciesSymbol(); @@ -3798,4 +3839,36 @@ JSHandle Builtins::CreateArrayUnscopables(JSThread *thread) const JSObject::CreateDataProperty(thread, unscopableList, toSplicedKey, trueVal); return JSHandle::Cast(unscopableList); } + +void Builtins::RegisterSendableContainers(const JSHandle &env) const +{ + auto globalObject = JSHandle::Cast(env->GetJSGlobalObject()); + { + JSHandle nameString(factory_->NewFromUtf8("SharedMap")); + PropertyDescriptor desc(thread_, env->GetSBuiltininMapFunction(), true, false, true); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + } + { + JSHandle nameString(factory_->NewFromUtf8("SharedSet")); + PropertyDescriptor desc(thread_, env->GetSBuiltininSetFunction(), true, false, true); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + } + { + JSHandle nameString(factory_->NewFromUtf8("SharedArray")); + PropertyDescriptor desc(thread_, env->GetSharedArrayFunction(), true, false, true); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + } + { + JSHandle nameString(factory_->NewFromUtf8("SendableArrayBuffer")); + PropertyDescriptor desc(thread_, env->GetSBuiltininArrayBufferFunction(), true, false, true); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + } +#define REGISTER_BUILTIN_SHARED_TYPED_ARRAY(Type, ctorName, TYPE, bytesPerElement) \ + { \ + JSHandle nameString(factory_->NewFromUtf8(#ctorName)); \ + PropertyDescriptor desc(thread_, env->Get##ctorName##Function(), true, false, true); \ + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); \ + } + BUILTIN_SHARED_TYPED_ARRAY_TYPES(REGISTER_BUILTIN_SHARED_TYPED_ARRAY) +} } // namespace panda::ecmascript diff --git a/ecmascript/builtins/builtins.h b/ecmascript/builtins/builtins.h index 994bdeb2c8e11dd37f186d917ba6af921403b93e..cba8655e42a86850459408727e89c91cbd4fe649 100644 --- a/ecmascript/builtins/builtins.h +++ b/ecmascript/builtins/builtins.h @@ -20,6 +20,7 @@ #include "ecmascript/global_env.h" #include "ecmascript/js_function.h" #include "ecmascript/js_handle.h" +#include "ecmascript/js_hclass.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" #include "ecmascript/object_factory.h" @@ -99,6 +100,9 @@ private: void InitializeArray(const JSHandle &env, const JSHandle &objFuncPrototypeVal) const; + void InitializeSharedArray(const JSHandle &env, const JSHandle &sObjIHClass, + JSHandle &sFuncPrototype) const; + void InitializeTypedArray(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void LazyInitializeTypedArray(const JSHandle &env) const; @@ -202,6 +206,9 @@ private: void InitializeJson(const JSHandle &env, const JSHandle &objFuncPrototypeVal) const; + void InitializeSendableJson(const JSHandle &env, + const JSHandle &objFuncPrototypeVal) const; + void InitializeString(const JSHandle &env, JSHandle objFuncPrototypeVal) const; void InitializeIterator(const JSHandle &env, const JSHandle &objFuncClass) const; @@ -218,11 +225,14 @@ private: void InitializeForinIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const; void InitializeMapIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const; + void InitializeSMapIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const; void InitializeSetIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const; + void InitializeSSetIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const; void InitializeArrayIterator(const JSHandle &env, const JSHandle &iteratorFuncClass, const JSHandle &iteratorPrototypeClass) const; + void InitializeSArrayIterator(const JSHandle &env, const JSHandle &iteratorFuncClass) const; void InitializeArrayBuffer(const JSHandle &env, const JSHandle &objFuncClass) const; void LazyInitializeArrayBuffer(const JSHandle &env) const; @@ -346,20 +356,51 @@ private: EcmaEntrypoint func, int length) const; void SetNonConstantObject(const JSHandle &obj, std::string_view key, JSHandle &value) const; + void RegisterSendableContainers(const JSHandle &env) const; // For SharedObject/SharedFunction void InitializeSObjectAndSFunction(const JSHandle &env) const; void CopySObjectAndSFunction(const JSHandle &env, const JSTaggedValue &srcEnv) const; void InitializeSObject(const JSHandle &env, const JSHandle &sObjIHClass, - const JSHandle &sObjFuncPrototype, + const JSHandle &sObjPrototype, const JSHandle &sFuncPrototype) const; void InitializeSFunction(const JSHandle &env, const JSHandle &sFuncPrototype) const; + void InitializeSArrayBuffer(const JSHandle &env, const JSHandle &objFuncClass, + const JSHandle &sFuncPrototype) const; + void InitializeSSet(const JSHandle &env, const JSHandle &sObjPrototype, + const JSHandle &sFuncPrototype) const; + void InitializeSMap(const JSHandle &env, const JSHandle &sObjPrototype, + const JSHandle &sFuncPrototype) const; + void InitializeSTypedArray(const JSHandle &env, const JSHandle &sObjPrototype, + const JSHandle &sFuncPrototype) const; + void InitializeSInt8Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSUint8Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSUint8ClampedArray(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSInt16Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSUint16Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSInt32Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSUint32Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSFloat32Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSFloat64Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSBigInt64Array(const JSHandle &env, const JSHandle &objFuncClass) const; + void InitializeSBigUint64Array(const JSHandle &env, const JSHandle &objFuncClass) const; JSHandle CreateSObjectFunctionHClass(const JSHandle &sFuncPrototype) const; JSHandle CreateSObjectPrototypeHClass() const; JSHandle CreateSFunctionHClass(const JSHandle &sFuncPrototype) const; - JSHandle CreateSFunctionPrototypeHClass(const JSHandle &sObjFuncPrototypeVal) const; + JSHandle CreateSFunctionPrototypeHClass(const JSHandle &sObjPrototypeVal) const; + JSHandle CreateSSetPrototypeHClass(const JSHandle &sObjPrototype) const; + JSHandle CreateSSetFunctionHClass(const JSHandle &sFuncPrototype) const; + JSHandle CreateSMapPrototypeHClass(const JSHandle &sObjPrototype) const; + JSHandle CreateSMapFunctionHClass(const JSHandle &sFuncPrototype) const; + JSHandle CreateSArrayPrototypeHClass(const JSHandle &sObjPrototype) const; + JSHandle CreateSArrayFunctionHClass(const JSHandle &sFuncPrototype) const; + JSHandle CreateSTypedArrayPrototypeHClass(const JSHandle &sObjPrototype) const; + JSHandle CreateSTypedArrayFunctionHClass(const JSHandle &sFuncPrototype) const; + JSHandle CreateSSpecificTypedArrayFuncHClass(const JSHandle &sFuncPrototype) const; + JSHandle CreateSArrayBufferPrototypeHClass(const JSHandle &sObjPrototype) const; + JSHandle CreateSArrayBufferFunctionHClass(const JSHandle &sFuncPrototype) const; void InitializeSCtor(const JSHandle &protoHClass, const JSHandle &ctor, std::string_view name, int length) const; @@ -389,6 +430,7 @@ private: void SharedStrictModeForbiddenAccessCallerArguments(const JSHandle &env, uint32_t &index, const JSHandle &prototype) const; JSHandle CreateArrayUnscopables(JSThread *thread) const; + void InitializeSSymbolAttributes(const JSHandle &env); friend class builtins::BuiltinsLazyCallback; }; } // namespace panda::ecmascript diff --git a/ecmascript/builtins/builtins_ark_tools.cpp b/ecmascript/builtins/builtins_ark_tools.cpp index f47ca6a78bc43db0d8a5a26e452dba63874a83c1..672099d4593e68e57cf02371a0794513cba5d9b9 100644 --- a/ecmascript/builtins/builtins_ark_tools.cpp +++ b/ecmascript/builtins/builtins_ark_tools.cpp @@ -29,6 +29,7 @@ #include "ecmascript/property_detector-inl.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" +#include "ecmascript/linked_hash_table.h" #include "builtins_typedarray.h" #include "ecmascript/jit/jit.h" @@ -203,6 +204,7 @@ JSTaggedValue BuiltinsArkTools::ForceFullGC(EcmaRuntimeCallInfo *info) ASSERT(info); const_cast(info->GetThread()->GetEcmaVM()->GetHeap())->CollectGarbage( TriggerGCType::FULL_GC, GCReason::EXTERNAL_TRIGGER); + SharedHeap::GetInstance()->CollectGarbage(info->GetThread(), TriggerGCType::SHARED_GC, GCReason::EXTERNAL_TRIGGER); return JSTaggedValue::True(); } @@ -249,6 +251,15 @@ JSTaggedValue BuiltinsArkTools::CheckCircularImport(EcmaRuntimeCallInfo *info) return JSTaggedValue::Undefined(); } +JSTaggedValue BuiltinsArkTools::HashCode(EcmaRuntimeCallInfo *info) +{ + ASSERT(info); + JSThread *thread = info->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle key = GetCallArg(info, 0); + return JSTaggedValue(LinkedHash::Hash(thread, key.GetTaggedValue())); +} + #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) JSTaggedValue BuiltinsArkTools::StartCpuProfiler(EcmaRuntimeCallInfo *info) { diff --git a/ecmascript/builtins/builtins_ark_tools.h b/ecmascript/builtins/builtins_ark_tools.h index 5b31a7e9b5b74ce4c497416182f91ec46b4b6612..252290a9dc198dd397e4dc836d60ec20ba0daa29 100644 --- a/ecmascript/builtins/builtins_ark_tools.h +++ b/ecmascript/builtins/builtins_ark_tools.h @@ -49,7 +49,8 @@ V("printTypedOpProfilerAndReset", PrintTypedOpProfilerAndReset, 1, INVALID) \ V("isOnHeap", IsOnHeap, 1, INVALID) \ V("checkDeoptStatus", CheckDeoptStatus, 2, INVALID) \ - V("checkCircularImport", CheckCircularImport, 2, INVALID) + V("checkCircularImport", CheckCircularImport, 2, INVALID) \ + V("hashCode", HashCode, 1, ArkToolsHashCode) #define BUILTIN_ARK_TOOLS_FUNCTIONS_REGRESS(V) \ V("prepareFunctionForOptimization", PrepareFunctionForOptimization, 1, INVALID) \ @@ -170,6 +171,8 @@ public: static JSTaggedValue CheckCircularImport(EcmaRuntimeCallInfo *info); + static JSTaggedValue HashCode(EcmaRuntimeCallInfo *info); + #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER) static JSTaggedValue StartCpuProfiler(EcmaRuntimeCallInfo *info); diff --git a/ecmascript/builtins/builtins_array.cpp b/ecmascript/builtins/builtins_array.cpp index e31e5c7778e16c75ee8ff3ae41ab0f36ce4a88e9..1cc26e6ffd03b35a430c97cbee4fe79997e7656f 100644 --- a/ecmascript/builtins/builtins_array.cpp +++ b/ecmascript/builtins/builtins_array.cpp @@ -326,6 +326,7 @@ JSTaggedValue BuiltinsArray::From(EcmaRuntimeCallInfo *argv) JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); k++; + thread->CheckSafepointIfSuspended(); } // 17. Let setStatus be Set(A, "length", len, true). JSHandle lenHandle(thread, JSTaggedValue(len)); @@ -499,6 +500,7 @@ JSTaggedValue BuiltinsArray::Concat(EcmaRuntimeCallInfo *argv) // 5. Set k to k + 1. n++; k++; + thread->CheckSafepointIfSuspended(); } //c. Else } else { @@ -735,6 +737,7 @@ JSTaggedValue BuiltinsArray::Every(EcmaRuntimeCallInfo *argv) } } k++; + thread->CheckSafepointIfSuspended(); } // 9. Return true. @@ -880,6 +883,7 @@ JSTaggedValue BuiltinsArray::FilterUnStableJSArray(JSThread *thread, JSHandleCheckSafepointIfSuspended(); } return newArrayHandle.GetTaggedValue(); } @@ -1003,6 +1007,7 @@ JSTaggedValue BuiltinsArray::Find(EcmaRuntimeCallInfo *argv) return kValue.GetTaggedValue(); } k++; + thread->CheckSafepointIfSuspended(); } // 9. Return undefined. @@ -1073,6 +1078,7 @@ JSTaggedValue BuiltinsArray::FindIndex(EcmaRuntimeCallInfo *argv) return GetTaggedDouble(k); } k++; + thread->CheckSafepointIfSuspended(); } // 9. Return -1. @@ -1142,6 +1148,7 @@ JSTaggedValue BuiltinsArray::ForEach(EcmaRuntimeCallInfo *argv) RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); } k++; + thread->CheckSafepointIfSuspended(); } // 9. Return undefined. @@ -1215,6 +1222,7 @@ JSTaggedValue BuiltinsArray::IndexOfSlowPath( if (UNLIKELY(found)) { return JSTaggedValue(curIndex); } + thread->CheckSafepointIfSuspended(); } // 12. Return -1. return JSTaggedValue(-1); @@ -1322,6 +1330,7 @@ JSTaggedValue BuiltinsArray::Join(EcmaRuntimeCallInfo *argv) concatStr.append(sepStr); } concatStr.append(nextStr); + thread->CheckSafepointIfSuspended(); } // 14. Return R. @@ -1523,6 +1532,7 @@ JSTaggedValue BuiltinsArray::MapUnStableJSArray(JSThread *thread, JSHandleCheckSafepointIfSuspended(); } // 11. Return A. @@ -1669,6 +1679,7 @@ JSTaggedValue BuiltinsArray::ReduceUnStableJSArray(JSThread *thread, JSHandleCheckSafepointIfSuspended(); } return accumulator.GetTaggedValue(); } @@ -1826,6 +1837,17 @@ JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv) // e. Decrease k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSTaggedValue callResult = JSTaggedValue::Undefined(); + + JSHandle thisArgHandle = globalConst->GetHandledUndefined(); + if (thisObjVal->IsStableJSArray(thread)) { + JSTaggedValue ret = JSStableArray::HandleReduceRightOfStable(thread, thisObjHandle, + callbackFnHandle, accumulator, thisArgHandle, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (ret.ToBoolean()) { + return accumulator.GetTaggedValue(); + } + } + while (k >= 0) { key.Update(JSTaggedValue(k)); bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, key)); @@ -1833,7 +1855,6 @@ JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv) if (exists) { JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, key); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle thisArgHandle = globalConst->GetHandledUndefined(); const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O» JSHandle undefined = globalConst->GetHandledUndefined(); EcmaRuntimeCallInfo *info = @@ -2039,6 +2060,7 @@ JSTaggedValue BuiltinsArray::Shift(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } k++; + thread->CheckSafepointIfSuspended(); } // 10. Let deleteStatus be DeletePropertyOrThrow(O, ToString(len–1)). JSHandle deleteKey(thread, JSTaggedValue(len - 1)); @@ -2221,7 +2243,15 @@ JSTaggedValue BuiltinsArray::Some(EcmaRuntimeCallInfo *argv) // v. If testResult is true, return true. // e. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); - int64_t k = 0; + uint32_t k = 0; + JSTaggedValue callResult = GetTaggedBoolean(false); + if (thisObjVal->IsStableJSArray(thread)) { + callResult = JSStableArray::HandleSomeOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (callResult.ToBoolean()) { + return GetTaggedBoolean(true); + } + } while (k < len) { bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -2235,13 +2265,14 @@ JSTaggedValue BuiltinsArray::Some(EcmaRuntimeCallInfo *argv) EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); - JSTaggedValue callResult = JSFunction::Call(info); + callResult = JSFunction::Call(info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (callResult.ToBoolean()) { return GetTaggedBoolean(true); } } k++; + thread->CheckSafepointIfSuspended(); } // 9. Return false. @@ -2547,6 +2578,7 @@ JSTaggedValue BuiltinsArray::ToLocaleString(EcmaRuntimeCallInfo *argv) auto globalConst = thread->GlobalConstants(); JSHandle undefined = globalConst->GetHandledUndefined(); for (int64_t k = 0; k < len; k++) { + thread->CheckSafepointIfSuspended(); JSTaggedValue next = globalConst->GetEmptyString(); JSHandle nextElement = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_AND_POP_JOINSTACK(thread, thisHandle); @@ -3006,6 +3038,7 @@ JSTaggedValue BuiltinsArray::With(EcmaRuntimeCallInfo *argv) JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, fromKey, fromValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); ++k; + thread->CheckSafepointIfSuspended(); } // 10. Return A. return newArrayHandle.GetTaggedValue(); @@ -3384,6 +3417,7 @@ JSTaggedValue BuiltinsArray::ToReversed(EcmaRuntimeCallInfo *argv) JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); k++; + thread->CheckSafepointIfSuspended(); } // 6. Return A. return newArrayHandle.GetTaggedValue(); diff --git a/ecmascript/builtins/builtins_array.h b/ecmascript/builtins/builtins_array.h index 45a74a6ed47b901c1a648d6c79dfbacd6c739798..9c6b005e497fb02af3aa24bc6cf46aac0537af6c 100644 --- a/ecmascript/builtins/builtins_array.h +++ b/ecmascript/builtins/builtins_array.h @@ -59,7 +59,7 @@ /* Array.prototype.flat ( [ depth ] ) */ \ V("flat", Flat, 0, INVALID) \ /* Array.prototype.flatMap ( mapperFunction [ , thisArg ] ) */ \ - V("flatMap", FlatMap, 1, INVALID) \ + V("flatMap", FlatMap, 1, ArrayFlatMap) \ /* Array.prototype.forEach ( callbackfn [ , thisArg ] ) */ \ V("forEach", ForEach, 1, ArrayForEach) \ /* Array.prototype.includes ( searchElement [ , fromIndex ] ) */ \ @@ -81,35 +81,35 @@ /* Array.prototype.reduce ( callbackfn [ , initialValue ] ) */ \ V("reduce", Reduce, 1, ArrayReduce) \ /* Array.prototype.reduceRight ( callbackfn [ , initialValue ] ) */ \ - V("reduceRight", ReduceRight, 1, INVALID) \ + V("reduceRight", ReduceRight, 1, ArrayReduceRight) \ /* Array.prototype.reverse ( ) */ \ V("reverse", Reverse, 0, ArrayReverse) \ /* Array.prototype.shift ( ) */ \ - V("shift", Shift, 0, INVALID) \ + V("shift", Shift, 0, ArrayShift) \ /* Array.prototype.slice ( start, end ) */ \ V("slice", Slice, 2, ArraySlice) \ /* Array.prototype.some ( callbackfn [ , thisArg ] ) */ \ - V("some", Some, 1, INVALID) \ + V("some", Some, 1, ArraySome) \ /* Array.prototype.sort ( comparefn ) */ \ - V("sort", Sort, 1, SORT) \ + V("sort", Sort, 1, ArraySort) \ /* Array.prototype.splice ( start, deleteCount, ...items ) */ \ V("splice", Splice, 2, ArraySplice) \ /* Array.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ) */ \ V("toLocaleString", ToLocaleString, 0, INVALID) \ /* Array.prototype.toReversed ( ) */ \ - V("toReversed", ToReversed, 0, INVALID) \ + V("toReversed", ToReversed, 0, ArrayToReversed) \ /* Array.prototype.toSorted ( comparefn ) */ \ - V("toSorted", ToSorted, 1, INVALID) \ + V("toSorted", ToSorted, 1, ArrayToSorted) \ /* Array.prototype.toSpliced ( start, skipCount, ...items ) */ \ - V("toSpliced", ToSpliced, 2, INVALID) \ + V("toSpliced", ToSpliced, 2, ArrayToSpliced) \ /* Array.prototype.toString ( ) */ \ V("toString", ToString, 0, INVALID) \ /* Array.prototype.unshift ( ...items ) */ \ - V("unshift", Unshift, 1, INVALID) \ + V("unshift", Unshift, 1, ArrayUnshift) \ /* Array.prototype.values ( ) */ \ V("values", Values, 0, ArrayValues) \ /* Array.prototype.with ( index, value ) */ \ - V("with", With, 2, INVALID) + V("with", With, 2, ArrayWith) namespace panda::ecmascript::builtins { static constexpr uint8_t INDEX_TWO = 2; diff --git a/ecmascript/builtins/builtins_arraybuffer.cpp b/ecmascript/builtins/builtins_arraybuffer.cpp index aa786bcead9e3f1a5b9e106eb4d2243cc5887708..e501b7d1c9b44d91064b3ac0574f7dca40b97ae4 100644 --- a/ecmascript/builtins/builtins_arraybuffer.cpp +++ b/ecmascript/builtins/builtins_arraybuffer.cpp @@ -244,6 +244,10 @@ JSTaggedValue BuiltinsArrayBuffer::AllocateArrayBuffer(JSThread *thread, const J if (byteLength > INT_MAX) { THROW_RANGE_ERROR_AND_RETURN(thread, "Out of range", JSTaggedValue::Exception()); } + uint64_t totalNativeSize = static_cast(thread->GetNativeAreaAllocator()->GetArrayBufferNativeSize()); + if (UNLIKELY(totalNativeSize > MAX_NATIVE_SIZE_LIMIT)) { + THROW_RANGE_ERROR_AND_RETURN(thread, NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE, JSTaggedValue::Exception()); + } uint32_t arrayByteLength = static_cast(byteLength); JSHandle arrayBuffer(obj); // 6. Set obj’s [[ArrayBufferData]] internal slot to block. @@ -294,7 +298,13 @@ JSTaggedValue BuiltinsArrayBuffer::CloneArrayBuffer(JSThread *thread, const JSHa } // 4. Let srcLength be the value of srcBuffer’s [[ArrayBufferByteLength]] internal slot. JSHandle arrBuf(srcBuffer); - uint32_t srcLen = arrBuf->GetArrayBufferByteLength(); + uint32_t srcLen = 0; + if (srcBuffer->IsByteArray()) { + JSHandle byteArrayBuf(srcBuffer); + srcLen = byteArrayBuf->GetByteLength(); + } else { + srcLen = arrBuf->GetArrayBufferByteLength(); + } // 5. Assert: srcByteOffset ≤ srcLength. ASSERT(srcByteOffset <= srcLen); // 6. Let cloneLength be srcLength – srcByteOffset. diff --git a/ecmascript/builtins/builtins_arraybuffer.h b/ecmascript/builtins/builtins_arraybuffer.h index 489d20121d2daf11efc1f90b127ed90b358ff8cd..51b1a23d16bf4438754895a753d0234e76299deb 100644 --- a/ecmascript/builtins/builtins_arraybuffer.h +++ b/ecmascript/builtins/builtins_arraybuffer.h @@ -21,8 +21,17 @@ #include "ecmascript/js_dataview.h" #include "ecmascript/js_typed_array.h" +// List of functions in ArrayBuffer, excluding the '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsArrayBuffer::func refers to the native implementation of ArrayBuffer[name]. +// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available. +#define BUILTIN_ARRAY_BUFFER_FUNCTIONS(V) \ + /* ArrayBuffer.isView ( arg ) */ \ + V("isView", IsView, 1, ArrayBufferIsView) + namespace panda::ecmascript::builtins { static constexpr double NUMBER_HALF = 0.5; +static constexpr uint32_t BITS_MASK_FF = 0xFF; static constexpr uint32_t BITS_EIGHT = 8; static constexpr uint32_t BITS_TWENTY_FOUR = 24; static constexpr uint32_t BITS_FORTY = 40; @@ -72,6 +81,12 @@ public: // es12 25.1.2.7 IsBigIntElementType ( type ) static bool IsBigIntElementType(DataViewType type); + // Excluding the '@@' internal properties + static Span GetArrayBufferFunctions() + { + return Span(ARRAY_BUFFER_FUNCTIONS); + } + static JSTaggedValue FastSetValueInBuffer(JSThread* thread, JSTaggedValue arrBuf, uint32_t byteIndex, DataViewType type, double val, bool littleEndian); static JSTaggedValue TryFastSetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteBeginOffset, @@ -98,6 +113,12 @@ public: static void *GetDataPointFromBuffer(JSTaggedValue arrBuf, uint32_t byteOffset = 0); private: +#define BUILTIN_ARRAY_BUFFER_ENTRY(name, func, length, id) \ + base::BuiltinFunctionEntry::Create((name), (BuiltinsArrayBuffer::func), (length), (kungfu::BuiltinsStubCSigns::id)), + + static constexpr std::array ARRAY_BUFFER_FUNCTIONS = {BUILTIN_ARRAY_BUFFER_FUNCTIONS(BUILTIN_ARRAY_BUFFER_ENTRY)}; +#undef BUILTIN_ARRAY_BUFFER_ENTRY + template static T LittleEndianToBigEndian(T liValue); template @@ -141,7 +162,11 @@ private: static JSTaggedValue TypedArrayToList(JSThread *thread, JSHandle& items); + static constexpr uint64_t MAX_NATIVE_SIZE_LIMIT = 4_GB; + static constexpr char const *NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE = "total array buffer size out of limit(4_GB)"; + friend class BuiltinsArray; + friend class BuiltinsSharedArray; }; } // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_dataview.h b/ecmascript/builtins/builtins_dataview.h index f57d8609c2c989e4212890ff5bd47bca6c431d0d..38a65b6e1685472fc7d26a67dca4a5ef8a91f79f 100644 --- a/ecmascript/builtins/builtins_dataview.h +++ b/ecmascript/builtins/builtins_dataview.h @@ -28,29 +28,29 @@ /* DataView.prototype.get%Type% ( byteOffset ) */ \ /* For %Type% of 2 or more bytes: */ \ /* DataView.prototype.get%Type% ( byteOffset [ , littleEndian ] ) */ \ - V("getFloat32", GetFloat32, 1, INVALID) \ - V("getFloat64", GetFloat64, 1, INVALID) \ - V("getInt8", GetInt8, 1, INVALID) \ - V("getInt16", GetInt16, 1, INVALID) \ - V("getInt32", GetInt32, 1, INVALID) \ - V("getBigInt64", GetBigInt64, 1, INVALID) \ - V("getUint16", GetUint16, 1, INVALID) \ - V("getUint32", GetUint32, 1, INVALID) \ - V("getUint8", GetUint8, 1, INVALID) \ - V("getBigUint64", GetBigUint64, 1, INVALID) \ + V("getFloat32", GetFloat32, 1, DataViewGetFloat32 ) \ + V("getFloat64", GetFloat64, 1, DataViewGetFloat64 ) \ + V("getInt8", GetInt8, 1, DataViewGetInt8 ) \ + V("getInt16", GetInt16, 1, DataViewGetInt16 ) \ + V("getInt32", GetInt32, 1, DataViewGetInt32 ) \ + V("getBigInt64", GetBigInt64, 1, INVALID ) \ + V("getUint16", GetUint16, 1, DataViewGetUint16 ) \ + V("getUint32", GetUint32, 1, DataViewGetUint32 ) \ + V("getUint8", GetUint8, 1, DataViewGetUint8 ) \ + V("getBigUint64", GetBigUint64, 1, INVALID ) \ /* For %Type% of 1 bytes: */ \ /* DataView.prototype.setInt8 ( byteOffset, value ) */ \ /* For %Type% of 2 or more bytes: */ \ /* DataView.prototype.setInt16 ( byteOffset, value [ , littleEndian ] ) */ \ - V("setFloat32", SetFloat32, 2, INVALID) \ - V("setFloat64", SetFloat64, 2, INVALID) \ - V("setInt8", SetInt8, 2, INVALID) \ - V("setInt16", SetInt16, 2, INVALID) \ - V("setInt32", SetInt32, 2, INVALID) \ + V("setFloat32", SetFloat32, 2, DataViewSetFloat32) \ + V("setFloat64", SetFloat64, 2, DataViewSetFloat64) \ + V("setInt8", SetInt8, 2, DataViewSetInt8) \ + V("setInt16", SetInt16, 2, DataViewSetInt16) \ + V("setInt32", SetInt32, 2, DataViewSetInt32) \ V("setBigInt64", SetBigInt64, 2, INVALID) \ - V("setUint8", SetUint8, 2, INVALID) \ - V("setUint16", SetUint16, 2, INVALID) \ - V("setUint32", SetUint32, 2, INVALID) \ + V("setUint8", SetUint8, 2, DataViewSetUint8) \ + V("setUint16", SetUint16, 2, DataViewSetUint16) \ + V("setUint32", SetUint32, 2, DataViewSetUint32) \ V("setBigUint64", SetBigUint64, 2, INVALID) namespace panda::ecmascript::builtins { diff --git a/ecmascript/builtins/builtins_global.h b/ecmascript/builtins/builtins_global.h index 39a8a0474d4181ce1df9b139738cc6c88dafb657..e998c55bbcee73f886d522eb919289010eb9ebc3 100644 --- a/ecmascript/builtins/builtins_global.h +++ b/ecmascript/builtins/builtins_global.h @@ -35,27 +35,27 @@ // The following global object properties are not listed here: // - parseFloat ( string ), listed in builtins_number.h instead. // - parseInt ( string ), listed in builtins_number.h instead. -#define BUILTIN_GLOBAL_FUNCTIONS_COMMON(V) \ - /* decodeURI ( encodedURI ) */ \ - V("decodeURI", DecodeURI, 1, INVALID) \ - /* decodeURIComponent ( encodedURIComponent ) */ \ - V("decodeURIComponent", DecodeURIComponent, 1, INVALID) \ - /* encodeURI ( uri ) */ \ - V("encodeURI", EncodeURI, 1, INVALID) \ - /* encodeURIComponent ( uriComponent ) */ \ - V("encodeURIComponent", EncodeURIComponent, 1, INVALID) \ - /* escape ( string ), defined in B.2.1 */ \ - V("escape", Escape, 1, INVALID) \ - /* eval ( x ), which is NOT supported in ArkTS engine */ \ - V("eval", NotSupportEval, 1, INVALID) \ - /* isFinite ( number ) */ \ - V("isFinite", IsFinite, 1, INVALID) \ - /* isNaN ( number ) */ \ - V("isNaN", IsNaN, 1, INVALID) \ - /* unescape ( string )*/ \ - V("unescape", Unescape, 1, INVALID) \ - /* The following are ArkTS extensions */ \ - V("markModuleCollectable", MarkModuleCollectable, 0, INVALID) \ +#define BUILTIN_GLOBAL_FUNCTIONS_COMMON(V) \ + /* decodeURI ( encodedURI ) */ \ + V("decodeURI", DecodeURI, 1, INVALID) \ + /* decodeURIComponent ( encodedURIComponent ) */ \ + V("decodeURIComponent", DecodeURIComponent, 1, INVALID) \ + /* encodeURI ( uri ) */ \ + V("encodeURI", EncodeURI, 1, INVALID) \ + /* encodeURIComponent ( uriComponent ) */ \ + V("encodeURIComponent", EncodeURIComponent, 1, INVALID) \ + /* escape ( string ), defined in B.2.1 */ \ + V("escape", Escape, 1, INVALID) \ + /* eval ( x ), which is NOT supported in ArkTS engine */ \ + V("eval", NotSupportEval, 1, INVALID) \ + /* isFinite ( number ) */ \ + V("isFinite", IsFinite, 1, GlobalIsFinite) \ + /* isNaN ( number ) */ \ + V("isNaN", IsNaN, 1, GlobalIsNan) \ + /* unescape ( string )*/ \ + V("unescape", Unescape, 1, INVALID) \ + /* The following are ArkTS extensions */ \ + V("markModuleCollectable", MarkModuleCollectable, 0, INVALID) \ V("print", PrintEntrypoint, 0, INVALID) #if ECMASCRIPT_ENABLE_RUNTIME_STAT diff --git a/ecmascript/builtins/builtins_json.cpp b/ecmascript/builtins/builtins_json.cpp index e6aa1beee707b1774f9be92f08bb57c21ee1c5d5..b5b52ea009b84f697168c69e3e6e936d02f48d52 100644 --- a/ecmascript/builtins/builtins_json.cpp +++ b/ecmascript/builtins/builtins_json.cpp @@ -16,19 +16,51 @@ #include "ecmascript/builtins/builtins_json.h" #include "ecmascript/base/fast_json_stringifier.h" +#include "ecmascript/base/json_helper.h" #include "ecmascript/base/json_parser.h" #include "ecmascript/base/json_stringifier.h" #include "ecmascript/base/number_helper.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" +#include "ecmascript/interpreter/slow_runtime_stub.h" #include "ecmascript/js_handle.h" +#include "ecmascript/js_object.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/js_tagged_value.h" #include "ecmascript/object_factory.h" namespace panda::ecmascript::builtins { -// 24.5.1 +namespace { +using TransformType = base::JsonHelper::TransformType; + +void InitWithTransformType(JSHandle &env, TransformType transformType, + JSMutableHandle &constructor, SCheckMode &sCheckMode) +{ + if (transformType == TransformType::NORMAL) { + sCheckMode = SCheckMode::CHECK; + constructor.Update(env->GetObjectFunction()); + } else { + sCheckMode = SCheckMode::SKIP; + constructor.Update(env->GetSObjectFunction()); + } +} +} // namespace + +using Internalize = base::Internalize; + JSTaggedValue BuiltinsJson::Parse(EcmaRuntimeCallInfo *argv) +{ + return ParseWithTransformType(argv, TransformType::NORMAL); +} + +JSTaggedValue BuiltinsSendableJson::Parse(EcmaRuntimeCallInfo *argv) +{ + return BuiltinsJson::ParseWithTransformType(argv, TransformType::SENDABLE); +} + +// 24.5.1 +JSTaggedValue BuiltinsJson::ParseWithTransformType(EcmaRuntimeCallInfo *argv, TransformType transformType) { BUILTINS_API_TRACE(argv->GetThread(), Json, Parse); ASSERT(argv); @@ -44,37 +76,60 @@ JSTaggedValue BuiltinsJson::Parse(EcmaRuntimeCallInfo *argv) } JSHandle msg = GetCallArg(argv, 0); + JSMutableHandle reviverVal(thread, JSTaggedValue::Undefined()); + if (argc == 2) { // 2: 2 args + reviverVal.Update(GetCallArg(argv, 1)); + } + return ParseWithTransformType(thread->GetEcmaVM(), msg, reviverVal, transformType); +} + +JSTaggedValue BuiltinsJson::ParseWithTransformType(const EcmaVM *vm, JSHandle &msg, + JSHandle &reviverVal, TransformType transformType) +{ + JSThread *thread = vm->GetJSThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle parseString = JSTaggedValue::ToString(thread, msg); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle result; if (EcmaStringAccessor(parseString).IsUtf8()) { - panda::ecmascript::base::Utf8JsonParser parser(thread); + panda::ecmascript::base::Utf8JsonParser parser(thread, transformType); result = parser.Parse(parseString); } else { - panda::ecmascript::base::Utf16JsonParser parser(thread); + panda::ecmascript::base::Utf16JsonParser parser(thread, transformType); result = parser.Parse(*parseString); } RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue reviver = JSTaggedValue::Undefined(); - if (argc == 2) { // 2: 2 args - reviver = GetCallArg(argv, 1).GetTaggedValue(); + if (reviverVal->IsJSFunction()) { + reviver = reviverVal.GetTaggedValue(); if (reviver.IsCallable()) { JSHandle callbackfnHandle(thread, reviver); // Let root be ! OrdinaryObjectCreate(%Object.prototype%). JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); - JSHandle constructor(env->GetObjectFunction()); + JSMutableHandle constructor(thread, JSTaggedValue::Undefined()); + SCheckMode sCheckMode = SCheckMode::CHECK; + InitWithTransformType(env, transformType, constructor, sCheckMode); JSHandle root = factory->NewJSObjectByConstructor(constructor); // Let rootName be the empty String. JSHandle rootName(factory->GetEmptyString()); // Perform ! CreateDataPropertyOrThrow(root, rootName, unfiltered). - bool success = JSObject::CreateDataProperty(thread, root, rootName, result); + bool success = JSObject::CreateDataProperty(thread, root, rootName, result, sCheckMode); if (success) { - result = base::Internalize::InternalizeJsonProperty(thread, root, rootName, callbackfnHandle); + result = Internalize::InternalizeJsonProperty(thread, root, rootName, callbackfnHandle, transformType); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } } } + if (transformType == TransformType::SENDABLE) { + if (result->IsHeapObject() && !result->IsJSShared() && !result->IsString()) { + THROW_TYPE_ERROR_AND_RETURN(thread, GET_MESSAGE_STRING(ClassNotDerivedFromShared), + JSTaggedValue::Exception()); + } + } return result.GetTaggedValue(); } diff --git a/ecmascript/builtins/builtins_json.h b/ecmascript/builtins/builtins_json.h index a80ebab7bbf21a31e6298d4588f0a0d569585a25..72abf901e086f6d054a5bbc4b19b7befa41a2610 100644 --- a/ecmascript/builtins/builtins_json.h +++ b/ecmascript/builtins/builtins_json.h @@ -17,14 +17,28 @@ #define ECMASCRIPT_BUILTINS_BUILTINS_JSON_H #include "ecmascript/base/builtins_base.h" +#include "ecmascript/base/json_helper.h" #include "ecmascript/ecma_runtime_call_info.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_tagged_value.h" namespace panda::ecmascript::builtins { class BuiltinsJson : public base::BuiltinsBase { public: + using TransformType = base::JsonHelper::TransformType; static JSTaggedValue Parse(EcmaRuntimeCallInfo *argv); static JSTaggedValue Stringify(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ParseWithTransformType(EcmaRuntimeCallInfo *argv, TransformType transformType); +private: + static JSTaggedValue ParseWithTransformType(const EcmaVM *vm, JSHandle &msg, + JSHandle &reviverVal, TransformType transformType); +}; + +class BuiltinsSendableJson : public base::BuiltinsBase { +public: + static JSTaggedValue Parse(EcmaRuntimeCallInfo *argv); }; } // namespace panda::ecmascript::builtins #endif // ECMASCRIPT_BUILTINS_BUILTINS_JSON_H diff --git a/ecmascript/builtins/builtins_math.h b/ecmascript/builtins/builtins_math.h index 4f63f6b0284bd74de83bc218334e382b8009725e..608366a91077797727fcd93799c7251d3f8adca7 100644 --- a/ecmascript/builtins/builtins_math.h +++ b/ecmascript/builtins/builtins_math.h @@ -42,33 +42,33 @@ V("atan", Atan, 1, MathAtan) /* Math.atan ( x ) */ \ V("atan2", Atan2, 2, MathAtan2) /* Math.atan2 ( y, x ) */ \ V("atanh", Atanh, 1, MathAtanh) /* Math.atanh ( x ) */ \ - V("cbrt", Cbrt, 1, INVALID) /* Math.cbrt ( x ) */ \ - V("ceil", Ceil, 1, INVALID) /* Math.ceil ( x ) */ \ - V("clz32", Clz32, 1, INVALID) /* Math.clz32 ( x ) */ \ + V("cbrt", Cbrt, 1, MathCbrt) /* Math.cbrt ( x ) */ \ + V("ceil", Ceil, 1, MathCeil) /* Math.ceil ( x ) */ \ + V("clz32", Clz32, 1, MathClz32) /* Math.clz32 ( x ) */ \ V("cos", Cos, 1, MathCos) /* Math.cos ( x ) */ \ V("cosh", Cosh, 1, MathCosh) /* Math.cosh ( x ) */ \ - V("exp", Exp, 1, INVALID) /* Math.exp ( x ) */ \ - V("expm1", Expm1, 1, INVALID) /* Math.expm1 ( x ) */ \ - V("floor", Floor, 1, FLOOR) /* Math.floor ( x ) */ \ - V("fround", Fround, 1, INVALID) /* Math.fround ( x ) */ \ + V("exp", Exp, 1, MathExp) /* Math.exp ( x ) */ \ + V("expm1", Expm1, 1, MathExpm1) /* Math.expm1 ( x ) */ \ + V("floor", Floor, 1, MathFloor) /* Math.floor ( x ) */ \ + V("fround", Fround, 1, MathFRound) /* Math.fround ( x ) */ \ V("hypot", Hypot, 2, INVALID) /* Math.hypot ( ...args ) */ \ - V("imul", Imul, 2, INVALID) /* Math.imul ( x, y ) */ \ + V("imul", Imul, 2, MathImul) /* Math.imul ( x, y ) */ \ V("log", Log, 1, MathLog) /* Math.log ( x ) */ \ V("log10", Log10, 1, MathLog10) /* Math.log10 ( x ) */ \ V("log1p", Log1p, 1, MathLog1p) /* Math.log1p ( x ) */ \ V("log2", Log2, 1, MathLog2) /* Math.log2 ( x ) */ \ - V("max", Max, 2, INVALID) /* Math.max ( ...args ) */ \ - V("min", Min, 2, INVALID) /* Math.min ( ...args ) */ \ + V("max", Max, 2, MathMax) /* Math.max ( ...args ) */ \ + V("min", Min, 2, MathMin) /* Math.min ( ...args ) */ \ V("pow", Pow, 2, MathPow) /* Math.pow ( base, exponent ) */ \ V("random", Random, 0, INVALID) /* Math.random ( ) */ \ - V("round", Round, 1, INVALID) /* Math.round ( x ) */ \ - V("sign", Sign, 1, INVALID) /* Math.sign ( x ) */ \ + V("round", Round, 1, MathRound) /* Math.round ( x ) */ \ + V("sign", Sign, 1, MathSign) /* Math.sign ( x ) */ \ V("sin", Sin, 1, MathSin) /* Math.sin ( x ) */ \ V("sinh", Sinh, 1, MathSinh) /* Math.sinh ( x ) */ \ - V("sqrt", Sqrt, 1, SQRT) /* Math.sqrt ( x ) */ \ + V("sqrt", Sqrt, 1, MathSqrt) /* Math.sqrt ( x ) */ \ V("tan", Tan, 1, MathTan) /* Math.tan ( x ) */ \ V("tanh", Tanh, 1, MathTanh) /* Math.tanh ( x ) */ \ - V("trunc", Trunc, 1, INVALID) /* Math.trunc ( x ) */ + V("trunc", Trunc, 1, MathTrunc) /* Math.trunc ( x ) */ namespace panda::ecmascript::builtins { class BuiltinsMath : public base::BuiltinsBase { diff --git a/ecmascript/builtins/builtins_number.cpp b/ecmascript/builtins/builtins_number.cpp index 7645adcea7ec6052284f2a69b83ea4634b0800b9..40c7799d6ceaad90816b5639066883c34c732ece 100644 --- a/ecmascript/builtins/builtins_number.cpp +++ b/ecmascript/builtins/builtins_number.cpp @@ -530,7 +530,7 @@ JSTaggedValue NumberToStringResultCache::CreateCacheTable(const JSThread *thread JSTaggedValue NumberToStringResultCache::FindCachedResult(JSTaggedValue &number) { int entry = NumberToStringResultCache::GetNumberHash(number); - uint32_t index = entry * ENTRY_SIZE; + uint32_t index = static_cast(entry * ENTRY_SIZE); JSTaggedValue entryNumber = Get(index + NUMBER_INDEX); if (entryNumber == number) { return Get(index + RESULT_INDEX); diff --git a/ecmascript/builtins/builtins_number.h b/ecmascript/builtins/builtins_number.h index b3bde0ed31193e28ed03604b3b606c75e44f1931..c1e7a150771ced866f1d117cafbd827b3a42ed78 100644 --- a/ecmascript/builtins/builtins_number.h +++ b/ecmascript/builtins/builtins_number.h @@ -34,11 +34,11 @@ // V(name, func, length, stubIndex) // where BuiltinsNumber::func refers to the native implementation of Number[name]. // kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available. -#define BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(V) \ - V("isFinite", IsFinite, 1, INVALID) /* Number.isFinite ( number ) */ \ - V("isInteger", IsInteger, 1, INVALID) /* Number.isInteger ( number ) */ \ - V("isNaN", IsNaN, 1, INVALID) /* Number.isNaN ( number ) */ \ - V("isSafeInteger", IsSafeInteger, 1, INVALID) /* Number.isSafeInteger ( number ) */ +#define BUILTIN_NUMBER_NON_GLOBAL_FUNCTIONS(V) \ + V("isFinite", IsFinite, 1, NumberIsFinite) /* Number.isFinite ( number ) */ \ + V("isInteger", IsInteger, 1, NumberIsInteger) /* Number.isInteger ( number ) */ \ + V("isNaN", IsNaN, 1, NumberIsNaN) /* Number.isNaN ( number ) */ \ + V("isSafeInteger", IsSafeInteger, 1, NumberIsSafeInteger) /* Number.isSafeInteger ( number ) */ // List of functions in Number that can be accessed via globalThis. // V(name, func, length, stubIndex) @@ -179,13 +179,13 @@ public: void SetCachedResult(const JSThread *thread, JSTaggedValue &number, JSHandle &result); int GetNumberHash(JSTaggedValue &number) { - int mask = INITIAL_CACHE_NUMBER - 1; - int value = 0; + unsigned int mask = INITIAL_CACHE_NUMBER - 1; + unsigned int value = 0; if (number.IsInt()) { - value = number.GetInt(); + value = static_cast(number.GetInt()); } else { int64_t bits = base::bit_cast(number.GetDouble()); - value = static_cast(bits) ^ static_cast(bits >> 32); // 32: hight 32 bit + value = static_cast(bits) ^ static_cast(bits >> 32); // 32: hight 32 bit } return value & mask; } diff --git a/ecmascript/builtins/builtins_object.cpp b/ecmascript/builtins/builtins_object.cpp index d3c71f33ce77f5cc4efd242aaa8f9d8bfe3ea48a..0be4ab09a46dc56a313087019392a02221f96fb5 100644 --- a/ecmascript/builtins/builtins_object.cpp +++ b/ecmascript/builtins/builtins_object.cpp @@ -896,7 +896,7 @@ JSTaggedValue BuiltinsObject::GetBuiltinObjectToString(JSThread *thread, const J { BUILTINS_API_TRACE(thread, Object, GetBuiltinObjectToString); // 4. Let isArray be IsArray(O). - bool isArray = object->IsJSArray(); + bool isArray = object.GetTaggedValue().IsArray(thread); // 5. ReturnIfAbrupt(isArray). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); diff --git a/ecmascript/builtins/builtins_promise_job.cpp b/ecmascript/builtins/builtins_promise_job.cpp index f385e332255ff3a8a3711f32d754889d6a8d98ee..8296a5db7faec92cf08e1a98b1799366c149da23 100644 --- a/ecmascript/builtins/builtins_promise_job.cpp +++ b/ecmascript/builtins/builtins_promise_job.cpp @@ -166,11 +166,14 @@ JSTaggedValue BuiltinsPromiseJob::DynamicImportJob(EcmaRuntimeCallInfo *argv) LOG_FULL(FATAL) << "Load current file's panda file failed. Current file is " << recordNameStr; } // translate requestPath to OhmUrl - if (ModulePathHelper::NeedTranstale(requestPath)) { + if (vm->IsNormalizedOhmUrlPack()) { + ModulePathHelper::TranslateExpressionToNormalized(thread, fileNameStr, recordNameStr, requestPath); + LOG_ECMA(DEBUG) << "Exit Translate Normalized OhmUrl for DynamicImport, resultPath: " << requestPath; + } else if (ModulePathHelper::NeedTranstale(requestPath)) { ModulePathHelper::TranstaleExpressionInput(curJsPandaFile.get(), requestPath); - specifierString = thread->GetEcmaVM()->GetFactory()->NewFromUtf8(requestPath); LOG_ECMA(DEBUG) << "Exit Translate OhmUrl for DynamicImport, resultPath: " << requestPath; } + specifierString = thread->GetEcmaVM()->GetFactory()->NewFromUtf8(requestPath); } // resolve native module auto [isNative, moduleType] = SourceTextModule::CheckNativeModule(requestPath); @@ -211,6 +214,7 @@ JSTaggedValue BuiltinsPromiseJob::DynamicImportJob(EcmaRuntimeCallInfo *argv) thread, jsonRecordName, ModuleTypes::JSON_MODULE, resolve, reject, jsPandaFile.get()); } // Loading request module. + thread->GetEcmaVM()->PushToDeregisterModuleList(entryPoint); if (!moduleManager->IsImportedModuleLoaded(moduleName.GetTaggedValue())) { if (!JSPandaFileExecutor::ExecuteFromAbcFile(thread, fileNameStr.c_str(), entryPoint.c_str(), false, true)) { CString msg = "Cannot execute request dynamic-imported module : " + entryPoint; diff --git a/ecmascript/builtins/builtins_regexp.cpp b/ecmascript/builtins/builtins_regexp.cpp index 4ee3d46e4149c5c9048543f40dd4525a50fdafb7..c60d02d089ffea0d9236d3432c1b525abfb2853b 100644 --- a/ecmascript/builtins/builtins_regexp.cpp +++ b/ecmascript/builtins/builtins_regexp.cpp @@ -163,19 +163,15 @@ JSTaggedValue BuiltinsRegExp::Exec(EcmaRuntimeCallInfo *argv) // throw a TypeError exception. THROW_TYPE_ERROR_AND_RETURN(thread, "this does not have [[RegExpMatcher]]", JSTaggedValue::Exception()); } - if (BuiltinsRegExp::IsValidRegularExpression(thread, thisObj) == JSTaggedValue::False()) { - THROW_SYNTAX_ERROR_AND_RETURN(thread, "Regular expression too large", JSTaggedValue::Exception()); - } bool useCache = true; JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); if (cacheTable->GetLargeStrCount() == 0 || cacheTable->GetConflictCount() == 0) { useCache = false; } - + bool isFastPath = IsFastRegExp(thread, thisObj); // 6. Return RegExpBuiltinExec(R, S). - JSTaggedValue result = RegExpBuiltinExec(thread, thisObj, string, useCache); - return JSTaggedValue(result); + return RegExpBuiltinExec(thread, thisObj, string, isFastPath, useCache); } // 20.2.5.13 @@ -211,7 +207,7 @@ JSTaggedValue BuiltinsRegExp::Test(EcmaRuntimeCallInfo *argv) return GetTaggedBoolean(!matchResult.IsNull()); } -bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle ®exp) +bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle regexp) { JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); @@ -221,6 +217,11 @@ bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle ® if (hclass != originHClass) { return false; } + // lastIndex type is Int + JSTaggedValue lastIndex = JSHandle::Cast(regexp)->GetPropertyInlinedProps(LAST_INDEX_OFFSET); + if (!lastIndex.IsInt() || lastIndex.GetInt() < 0) { + return false; + } // RegExp.prototype hclass JSTaggedValue proto = hclass->GetPrototype(); JSHClass *regexpHclass = proto.GetTaggedObject()->GetClass(); @@ -237,20 +238,60 @@ bool BuiltinsRegExp::IsFastRegExp(JSThread *thread, JSHandle ® return true; } -JSTaggedValue BuiltinsRegExp::RegExpTestFast(JSThread *thread, JSHandle ®exp, - const JSHandle &inputStr, bool useCache) +JSTaggedValue BuiltinsRegExp::RegExpTestFast(JSThread *thread, JSHandle regexp, + const JSHandle inputStr, bool useCache) { // 1. Assert: Type(S) is String. ASSERT(inputStr->IsString()); - // 2. If R does not have a [[RegExpMatcher]] internal slot, throw a TypeError exception. - if (!regexp->IsJSRegExp()) { - // throw a TypeError exception. - THROW_TYPE_ERROR_AND_RETURN(thread, "this does not have a [[RegExpMatcher]]", JSTaggedValue::Exception()); + uint32_t lastIndex = static_cast(GetLastIndex(thread, regexp, true)); + // 2. Search RegExpExecResult cache + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); + if (useCache) { + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, inputStr, + RegExpExecResultCache::TEST_TYPE, regexp, + JSTaggedValue(lastIndex)); + if (!cacheResult.IsUndefined()) { + return cacheResult; + } } - if (BuiltinsRegExp::IsValidRegularExpression(thread, regexp) == JSTaggedValue::False()) { - THROW_SYNTAX_ERROR_AND_RETURN(thread, "Regular expression too large", JSTaggedValue::Exception()); + + uint32_t length = EcmaStringAccessor(inputStr->GetTaggedObject()).GetLength(); + if (lastIndex > length) { + SetLastIndex(thread, regexp, JSTaggedValue(0), true); + return JSTaggedValue::False(); } - return RegExpExecForTestFast(thread, regexp, inputStr, useCache); + JSHandle inputString = JSHandle::Cast(inputStr); + bool matchResult = RegExpExecInternal(thread, regexp, inputString, lastIndex); + // 2. Check whether the regexp is global or sticky, which determines whether we update last index later on. + bool global = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL); + bool sticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY); + bool ifUpdateLastIndex = global || sticky; + if (!matchResult) { + if (ifUpdateLastIndex) { + SetLastIndex(thread, regexp, JSTaggedValue(0), true); + } + if (useCache) { + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, inputStr, + JSHandle(thread, JSTaggedValue(matchResult)), + RegExpExecResultCache::TEST_TYPE, + lastIndex, 0); // 0: match fail so lastIndex is 0 + } + return JSTaggedValue::False(); + } + JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + JSTaggedValue endIndex = globalTable->GetEndIndex(); + uint32_t newLastIndex = lastIndex; + if (ifUpdateLastIndex) { + newLastIndex = endIndex.GetInt(); + SetLastIndex(thread, regexp, endIndex, true); + } + if (useCache) { + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, inputStr, + JSHandle(thread, JSTaggedValue(matchResult)), + RegExpExecResultCache::TEST_TYPE, + lastIndex, newLastIndex); + } + return GetTaggedBoolean(matchResult); } // 20.2.5.14 @@ -267,13 +308,22 @@ JSTaggedValue BuiltinsRegExp::ToString(EcmaRuntimeCallInfo *argv) if (!thisObj->IsECMAObject()) { THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception()); } - ObjectFactory *factory = ecmaVm->GetFactory(); const GlobalEnvConstants *globalConstants = thread->GlobalConstants(); - JSHandle sourceString(globalConstants->GetHandledSourceString()); - JSHandle flagsString(globalConstants->GetHandledFlagsString()); - // 3. Let pattern be ToString(Get(R, "source")). - JSHandle getSource(JSObject::GetProperty(thread, thisObj, sourceString).GetValue()); - JSHandle getFlags(JSObject::GetProperty(thread, thisObj, flagsString).GetValue()); + JSMutableHandle getSource(thread, JSTaggedValue::Undefined()); + JSMutableHandle getFlags(thread, JSTaggedValue::Undefined()); + if (IsFastRegExp(thread, thisObj)) { + JSHandle regexp(thread, JSRegExp::Cast(thisObj->GetTaggedObject())); + // 3. Let pattern be ToString(Get(R, "source")). + getSource.Update(regexp->GetOriginalSource()); + uint8_t flagsBits = static_cast(regexp->GetOriginalFlags().GetInt()); + getFlags.Update(FlagsBitsToString(thread, flagsBits)); + } else { + JSHandle sourceString(globalConstants->GetHandledSourceString()); + JSHandle flagsString(globalConstants->GetHandledFlagsString()); + // 3. Let pattern be ToString(Get(R, "source")). + getSource.Update(JSObject::GetProperty(thread, thisObj, sourceString).GetValue()); + getFlags.Update(JSObject::GetProperty(thread, thisObj, flagsString).GetValue()); + } JSHandle sourceStrHandle = JSTaggedValue::ToString(thread, getSource); // 4. ReturnIfAbrupt(pattern). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -283,6 +333,7 @@ JSTaggedValue BuiltinsRegExp::ToString(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle slashStr = JSHandle::Cast(globalConstants->GetHandledBackslashString()); // 7. Let result be the String value formed by concatenating "/", pattern, and "/", and flags. + ObjectFactory *factory = ecmaVm->GetFactory(); JSHandle tempStr = factory->ConcatFromString(slashStr, sourceStrHandle); JSHandle resultTemp = factory->ConcatFromString(tempStr, slashStr); return factory->ConcatFromString(resultTemp, flagsStrHandle).GetTaggedValue(); @@ -303,7 +354,7 @@ JSTaggedValue BuiltinsRegExp::GetFlags(EcmaRuntimeCallInfo *argv) } // 3. Let result be the empty String. // 4. ~ 19. - if (!JSHandle::Cast(thisObj)->IsJSRegExp()) { + if (!IsFastRegExp(thread, thisObj)) { return GetAllFlagsInternal(thread, thisObj); } uint8_t flagsBits = static_cast(JSRegExp::Cast(thisObj->GetTaggedObject())->GetOriginalFlags().GetInt()); @@ -522,12 +573,6 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv) // 3. Let S be ToString(string) JSHandle inputString = GetCallArg(argv, 0); JSHandle stringHandle = JSTaggedValue::ToString(thread, inputString); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - bool useCache = true; - JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); - if (cacheTable->GetLargeStrCount() == 0 || cacheTable->GetConflictCount() == 0) { - useCache = false; - } // 4. ReturnIfAbrupt(string). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle string = JSHandle::Cast(stringHandle); @@ -535,128 +580,121 @@ JSTaggedValue BuiltinsRegExp::Match(EcmaRuntimeCallInfo *argv) // 2. If Type(rx) is not Object, throw a TypeError exception. THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception()); } - - JSHandle regexpObj(thisObj); - JSMutableHandle pattern(thread, JSTaggedValue::Undefined()); - JSMutableHandle flags(thread, JSTaggedValue::Undefined()); - if (thisObj->IsJSRegExp()) { - pattern.Update(regexpObj->GetOriginalSource()); - flags.Update(regexpObj->GetOriginalFlags()); - } - - const GlobalEnvConstants *globalConst = thread->GlobalConstants(); - bool isGlobal = false; - bool fullUnicode = false; - bool unmodified = IsFastRegExp(thread, thisObj); - if (unmodified) { - uint8_t flagsBits = static_cast(flags->GetInt()); - isGlobal = (flagsBits & RegExpParser::FLAG_GLOBAL) != 0; - fullUnicode = (flagsBits & RegExpParser::FLAG_UTF16) != 0; - } else { - // 5. Let global be ToBoolean(Get(rx, "global")). - JSHandle global = globalConst->GetHandledGlobalString(); - JSTaggedValue globalValue = - ObjectFastOperator::FastGetPropertyByValue(thread, thisObj.GetTaggedValue(), global.GetTaggedValue()); - // 6. ReturnIfAbrupt(global). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - isGlobal = globalValue.ToBoolean(); + bool isFastPath = IsFastRegExp(thread, thisObj); + bool useCache = true; + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); + if (!isFastPath || cacheTable->GetLargeStrCount() == 0 || cacheTable->GetConflictCount() == 0) { + useCache = false; } + bool isGlobal = GetFlag(thread, thisObj, RegExpParser::FLAG_GLOBAL, isFastPath); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 7. If global is false, then if (!isGlobal) { // a. Return RegExpExec(rx, S). - if (useCache) { - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, inputString, - RegExpExecResultCache::EXEC_TYPE, thisObj, - JSTaggedValue(0)); - if (!cacheResult.IsUndefined()) { - return cacheResult; - } + if (isFastPath) { + return RegExpBuiltinExec(thread, thisObj, string, isFastPath, useCache); + } else { + return RegExpExec(thread, thisObj, string, useCache); } - JSTaggedValue result = RegExpExec(thread, thisObj, string, useCache); - return JSTaggedValue(result); } if (useCache) { - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, inputString, + uint32_t lastIndex = static_cast(GetLastIndex(thread, thisObj, isFastPath)); + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, inputString, RegExpExecResultCache::MATCH_TYPE, thisObj, - JSTaggedValue(0)); + JSTaggedValue(lastIndex)); if (!cacheResult.IsUndefined()) { return cacheResult; } } - - if (!unmodified) { - // 8. Else global is true - // a. Let fullUnicode be ToBoolean(Get(rx, "unicode")). - JSHandle unicode = globalConst->GetHandledUnicodeString(); - JSTaggedValue uincodeValue = - ObjectFastOperator::FastGetPropertyByValue(thread, thisObj.GetTaggedValue(), unicode.GetTaggedValue()); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - fullUnicode = uincodeValue.ToBoolean(); - } + bool fullUnicode = GetFlag(thread, thisObj, RegExpParser::FLAG_UTF16, isFastPath); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // b. Let setStatus be Set(rx, "lastIndex", 0, true). - JSHandle lastIndexString(globalConst->GetHandledLastIndexString()); - ObjectFastOperator::FastSetPropertyByValue(thread, thisObj.GetTaggedValue(), lastIndexString.GetTaggedValue(), - JSTaggedValue(0)); + SetLastIndex(thread, thisObj, JSTaggedValue(0), isFastPath); // c. ReturnIfAbrupt(setStatus). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // d. Let A be ArrayCreate(0). - JSHandle array(JSArray::ArrayCreate(thread, JSTaggedNumber(0))); + JSHandle array(JSArray::ArrayCreate(thread, JSTaggedNumber(0), ArrayMode::LITERAL)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + TaggedArray *srcElements = TaggedArray::Cast(array->GetElements().GetTaggedObject()); + JSMutableHandle elements(thread, srcElements); // e. Let n be 0. - int resultNum = 0; - JSMutableHandle result(thread, JSTaggedValue(0)); + uint32_t resultNum = 0; + uint32_t arrLen = 1; + JSMutableHandle result(thread, JSTaggedValue::Undefined()); + JSMutableHandle matchString(thread, JSTaggedValue::Undefined()); // f. Repeat, while (true) { - // i. Let result be RegExpExec(rx, S). - result.Update(RegExpExec(thread, thisObj, string, useCache)); - - // ii. ReturnIfAbrupt(result). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // iii. If result is null, then - if (result->IsNull()) { - // 1. If n=0, return null. - if (resultNum == 0) { - return JSTaggedValue::Null(); + if (isFastPath) { + uint32_t lastIndex = static_cast(GetLastIndex(thread, thisObj, isFastPath)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + result.Update(RegExpBuiltinExecWithoutResult(thread, thisObj, string, isFastPath, lastIndex, false)); + JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + uint32_t endIndex = static_cast(globalTable->GetEndOfCaptureIndex(0).GetInt()); + if (result->IsNull()) { + // 1. If n=0, return null. + lastIndex = static_cast(GetLastIndex(thread, thisObj, isFastPath)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (resultNum == 0) { + RegExpExecResultCache::AddResultInCache(thread, cacheTable, thisObj, inputString, + JSHandle(thread, JSTaggedValue::Null()), + RegExpExecResultCache::MATCH_TYPE, + 0, 0); + return JSTaggedValue::Null(); + } + RegExpExecResultCache::AddResultInCache(thread, cacheTable, thisObj, inputString, + JSHandle::Cast(array), + RegExpExecResultCache::MATCH_TYPE, + 0, 0); + // 2. Else, return A. + return array.GetTaggedValue(); } - if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputString, - JSHandle(array), - RegExpExecResultCache::MATCH_TYPE, 0, 0); + uint32_t startIndex = static_cast(globalTable->GetStartOfCaptureIndex(0).GetInt()); + uint32_t len = endIndex - startIndex; + matchString.Update(JSTaggedValue(EcmaStringAccessor::FastSubString( + thread->GetEcmaVM(), JSHandle::Cast(string), startIndex, len))); + } else { + // i. Let result be RegExpExec(rx, S). + result.Update(RegExpExec(thread, thisObj, string, useCache)); + // ii. ReturnIfAbrupt(result). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // iii. If result is null, then + if (result->IsNull()) { + // 1. If n=0, return null. + if (resultNum == 0) { + return JSTaggedValue::Null(); + } + // 2. Else, return A. + return array.GetTaggedValue(); } - // 2. Else, return A. - return array.GetTaggedValue(); - } - // iv. Else result is not null, - // 1. Let matchStr be ToString(Get(result, "0")). - JSHandle zeroString = globalConst->GetHandledZeroString(); - JSTaggedValue matchVal = ObjectFastOperator::FastGetPropertyByValue( - thread, result.GetTaggedValue(), zeroString.GetTaggedValue()); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle matchStr(thread, matchVal); - JSHandle matchString = JSTaggedValue::ToString(thread, matchStr); - // 2. ReturnIfAbrupt(matchStr). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // iv. Else result is not null, + // 1. Let matchStr be ToString(Get(result, "0")). + JSHandle zeroString = thread->GlobalConstants()->GetHandledZeroString(); + JSTaggedValue matchVal = ObjectFastOperator::FastGetPropertyByValue( + thread, result.GetTaggedValue(), zeroString.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle matchStr(thread, matchVal); + matchString.Update(JSTaggedValue::ToString(thread, matchStr)); + // 2. ReturnIfAbrupt(matchStr). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } JSHandle matchValue = JSHandle::Cast(matchString); // 3. Let status be CreateDataProperty(A, ToString(n), matchStr). - JSObject::CreateDataProperty(thread, array, resultNum, matchValue); + if (arrLen > elements->GetLength()) { + elements.Update(JSObject::GrowElementsCapacity(thread, + JSHandle::Cast(array), elements->GetLength(), true)); + } + elements->Set(thread, arrLen - 1, matchValue); + array->SetArrayLength(thread, arrLen); + arrLen++; // 5. If matchStr is the empty String, then - if (EcmaStringAccessor(JSTaggedValue::ToString(thread, matchValue)).GetLength() == 0) { - // a. Let thisIndex be ToLength(Get(rx, "lastIndex")). - JSTaggedValue lastIndex = ObjectFastOperator::FastGetPropertyByValue(thread, thisObj.GetTaggedValue(), - lastIndexString.GetTaggedValue()); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle lastIndexHandle(thread, lastIndex); - JSTaggedNumber thisIndex = JSTaggedValue::ToLength(thread, lastIndexHandle); - // b. ReturnIfAbrupt(thisIndex). + if (EcmaStringAccessor(matchString).GetLength() == 0) { + int64_t lastIndex = GetLastIndex(thread, thisObj, isFastPath); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // c. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode). // d. Let setStatus be Set(rx, "lastIndex", nextIndex, true). - JSTaggedValue nextIndex = - JSTaggedValue(AdvanceStringIndex(string, thisIndex.GetNumber(), fullUnicode)); - ObjectFastOperator::FastSetPropertyByValue(thread, thisObj.GetTaggedValue(), - lastIndexString.GetTaggedValue(), - nextIndex); + JSTaggedValue nextIndex = JSTaggedValue(AdvanceStringIndex(string, lastIndex, fullUnicode)); + SetLastIndex(thread, thisObj, nextIndex, isFastPath); // e. ReturnIfAbrupt(setStatus). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } @@ -684,63 +722,75 @@ JSTaggedValue BuiltinsRegExp::MatchAll(EcmaRuntimeCallInfo *argv) JSHandle inputString = GetCallArg(argv, 0); JSHandle stringHandle = JSTaggedValue::ToString(thread, inputString); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSMutableHandle matcher(thread, JSTaggedValue::Undefined()); + bool global = false; + bool fullUnicode = false; + bool isFastPath = IsFastRegExp(thread, thisObj); + if (isFastPath) { + JSHandle regexp = JSHandle::Cast(thisObj); + JSHandle pattern(thread, regexp->GetOriginalSource()); + JSHandle flags(thread, regexp->GetOriginalFlags()); + matcher.Update(BuiltinsRegExp::RegExpCreate(thread, pattern, flags)); + SetLastIndex(thread, matcher, + JSHandle::Cast(regexp)->GetPropertyInlinedProps(LAST_INDEX_OFFSET), isFastPath); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + global = GetOringinalFlag(thread, matcher, RegExpParser::FLAG_GLOBAL); + fullUnicode = GetOringinalFlag(thread, matcher, RegExpParser::FLAG_UTF16); + } else { + // 4. Let C be ? SpeciesConstructor(R, %RegExp%). + JSHandle defaultConstructor = ecmaVm->GetGlobalEnv()->GetRegExpFunction(); + JSHandle objHandle(thisObj); + JSHandle constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // 4. Let C be ? SpeciesConstructor(R, %RegExp%). - JSHandle defaultConstructor = ecmaVm->GetGlobalEnv()->GetRegExpFunction(); - JSHandle objHandle(thisObj); - JSHandle constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - - const GlobalEnvConstants *globalConstants = thread->GlobalConstants(); - // 5. Let flags be ? ToString(? Get(R, "flags")). - JSHandle flagsString(globalConstants->GetHandledFlagsString()); - JSHandle getFlags(JSObject::GetProperty(thread, thisObj, flagsString).GetValue()); - JSHandle flagsStrHandle = JSTaggedValue::ToString(thread, getFlags); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + const GlobalEnvConstants *globalConstants = thread->GlobalConstants(); + // 5. Let flags be ? ToString(? Get(R, "flags")). + JSHandle flagsString(globalConstants->GetHandledFlagsString()); + JSHandle getFlags(JSObject::GetProperty(thread, thisObj, flagsString).GetValue()); + JSHandle flagsStrHandle = JSTaggedValue::ToString(thread, getFlags); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // 6. Let matcher be ? Construct(C, « R, flags »). - JSHandle undefined = globalConstants->GetHandledUndefined(); - EcmaRuntimeCallInfo *runtimeInfo = - EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 2); // 2: two args - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - runtimeInfo->SetCallArg(thisObj.GetTaggedValue(), flagsStrHandle.GetTaggedValue()); - JSTaggedValue taggedMatcher = JSFunction::Construct(runtimeInfo); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle matcherHandle(thread, taggedMatcher); + // 6. Let matcher be ? Construct(C, « R, flags »). + JSHandle undefined = globalConstants->GetHandledUndefined(); + EcmaRuntimeCallInfo *runtimeInfo = + EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 2); // 2: two args + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + runtimeInfo->SetCallArg(thisObj.GetTaggedValue(), flagsStrHandle.GetTaggedValue()); + JSTaggedValue taggedMatcher = JSFunction::Construct(runtimeInfo); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + matcher.Update(taggedMatcher); - // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). - JSHandle lastIndexString(globalConstants->GetHandledLastIndexString()); - JSHandle getLastIndex(JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue()); - JSTaggedNumber thisLastIndex = JSTaggedValue::ToLength(thread, getLastIndex); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 7. Let lastIndex be ? ToLength(? Get(R, "lastIndex")). + JSHandle lastIndexString(globalConstants->GetHandledLastIndexString()); + JSHandle getLastIndex(JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue()); + JSTaggedNumber thisLastIndex = JSTaggedValue::ToLength(thread, getLastIndex); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). - ObjectFastOperator::FastSetPropertyByValue(thread, matcherHandle.GetTaggedValue(), lastIndexString.GetTaggedValue(), - thisLastIndex); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 8. Perform ? Set(matcher, "lastIndex", lastIndex, true). + ObjectFastOperator::FastSetPropertyByValue(thread, matcher.GetTaggedValue(), lastIndexString.GetTaggedValue(), + thisLastIndex); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // 9. If flags contains "g", let global be true. - // 10. Else, let global be false. - JSHandle gString(globalConstants->GetHandledGString()); - bool global = false; - if (EcmaStringAccessor::IndexOf(ecmaVm, flagsStrHandle, gString) != -1) { - global = true; - } + // 9. If flags contains "g", let global be true. + // 10. Else, let global be false. + JSHandle gString(globalConstants->GetHandledGString()); + if (EcmaStringAccessor::IndexOf(ecmaVm, flagsStrHandle, gString) != -1) { + global = true; + } - // 11. If flags contains "u", let fullUnicode be true. - // 12. Else, let fullUnicode be false. - JSHandle uString(globalConstants->GetHandledUString()); - bool fullUnicode = false; - if (EcmaStringAccessor::IndexOf(ecmaVm, flagsStrHandle, uString) != -1) { - fullUnicode = true; + // 11. If flags contains "u", let fullUnicode be true. + // 12. Else, let fullUnicode be false. + JSHandle uString(globalConstants->GetHandledUString()); + if (EcmaStringAccessor::IndexOf(ecmaVm, flagsStrHandle, uString) != -1) { + fullUnicode = true; + } } - // 13. Return ! CreateRegExpStringIterator(matcher, S, global, fullUnicode). - return JSRegExpIterator::CreateRegExpStringIterator(thread, matcherHandle, + return JSRegExpIterator::CreateRegExpStringIterator(thread, matcher, stringHandle, global, fullUnicode).GetTaggedValue(); } -JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle ®exp, +JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandle regexp, JSHandle inputString, uint32_t inputLength) { ASSERT(regexp->IsJSRegExp()); @@ -792,7 +842,7 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandleFindCachedResult(thread, pattern, flagsBits, tagInputString, + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, tagInputString, RegExpExecResultCache::REPLACE_TYPE, regexp, JSTaggedValue(lastIndexInput), globalConst->GetEmptyString()); @@ -849,7 +899,7 @@ JSTaggedValue BuiltinsRegExp::RegExpReplaceFast(JSThread *thread, JSHandleNewFromStdString(resultString); if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, tagInputString, + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, tagInputString, JSHandle(resultValue), RegExpExecResultCache::REPLACE_TYPE, lastIndexInput, lastIndex, globalConst->GetEmptyString()); @@ -893,95 +943,72 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, // 6. Let functionalReplace be IsCallable(replaceValue). bool functionalReplace = inputReplaceValue->IsCallable(); JSHandle replaceValueHandle; + // Add cache for regexp replace + bool useCache = true; if (!functionalReplace) { replaceValueHandle = JSTaggedValue::ToString(thread, inputReplaceValue); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } else { + useCache = false; } - JSHandle lastIndex = globalConst->GetHandledLastIndexString(); // 8. Let global be ToBoolean(Get(rx, "global")). ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); bool isGlobal = false; bool fullUnicode = false; - bool unmodified = IsFastRegExp(thread, thisObj); - if (unmodified) { - JSHandle regexpObj(thisObj); - uint8_t flagsBits = static_cast(regexpObj->GetOriginalFlags().GetInt()); - isGlobal = (flagsBits & RegExpParser::FLAG_GLOBAL) != 0; - fullUnicode = (flagsBits & RegExpParser::FLAG_UTF16) != 0; + bool isFastPath = IsFastRegExp(thread, thisObj); + if (isFastPath) { + isGlobal = GetOringinalFlag(thread, thisObj, RegExpParser::FLAG_GLOBAL); + fullUnicode = GetOringinalFlag(thread, thisObj, RegExpParser::FLAG_UTF16); if (isGlobal) { - ObjectFastOperator::FastSetPropertyByValue(thread, thisObj.GetTaggedValue(), - lastIndex.GetTaggedValue(), JSTaggedValue(0)); - // ReturnIfAbrupt(setStatus). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + SetLastIndex(thread, thisObj, JSTaggedValue(0), isFastPath); } } else { - JSHandle global = globalConst->GetHandledGlobalString(); - JSTaggedValue globalValue = - ObjectFastOperator::FastGetPropertyByValue(thread, thisObj.GetTaggedValue(), global.GetTaggedValue()); // 9. ReturnIfAbrupt(global). + isGlobal = GetFlag(thread, thisObj, RegExpParser::FLAG_GLOBAL, isFastPath); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - isGlobal = globalValue.ToBoolean(); // 10. If global is true, then if (isGlobal) { // a. Let fullUnicode be ToBoolean(Get(rx, "unicode")). - JSHandle unicode = globalConst->GetHandledUnicodeString(); - JSTaggedValue fullUnicodeTag = - ObjectFastOperator::FastGetPropertyByValue(thread, thisObj.GetTaggedValue(), unicode.GetTaggedValue()); + fullUnicode = GetFlag(thread, thisObj, RegExpParser::FLAG_UTF16, isFastPath); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - fullUnicode = fullUnicodeTag.ToBoolean(); // b. Let setStatus be Set(rx, "lastIndex", 0, true). - ObjectFastOperator::FastSetPropertyByValue(thread, thisObj.GetTaggedValue(), - lastIndex.GetTaggedValue(), JSTaggedValue(0)); + SetLastIndex(thread, thisObj, JSTaggedValue(0), isFastPath); // c. ReturnIfAbrupt(setStatus). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } } - // Add cache for regexp replace - bool useCache = false; // Add cache for the intermediate result of replace bool useIntermediateCache = false; - JSMutableHandle pattern(thread, JSTaggedValue::Undefined()); - JSMutableHandle flagsBits(thread, JSTaggedValue::Undefined()); JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); - if (isGlobal && thisObj->IsJSRegExp()) { - JSHClass *hclass = JSHandle::Cast(thisObj)->GetJSHClass(); - JSHClass *originHClass = JSHClass::Cast(globalConst->GetJSRegExpClass().GetTaggedObject()); - if (hclass == originHClass) { - if (!functionalReplace && EcmaStringAccessor(replaceValueHandle).GetLength() == 0) { - return RegExpReplaceFast(thread, thisObj, srcString, length); - } - JSHandle regexpHandle(thisObj); - if (regexpHandle->IsJSRegExp()) { - useIntermediateCache = true; - pattern.Update(regexpHandle->GetOriginalSource()); - flagsBits.Update(regexpHandle->GetOriginalFlags()); - } - if (!functionalReplace) { - uint32_t strLength = EcmaStringAccessor(replaceValueHandle).GetLength(); - uint32_t largeStrCount = cacheTable->GetLargeStrCount(); - if (largeStrCount != 0) { - if (strLength > MIN_REPLACE_STRING_LENGTH) { - cacheTable->SetLargeStrCount(thread, --largeStrCount); - } - } else { - cacheTable->SetStrLenThreshold(thread, MIN_REPLACE_STRING_LENGTH); + if (isFastPath) { + if (isGlobal && !functionalReplace && EcmaStringAccessor(replaceValueHandle).GetLength() == 0) { + return RegExpReplaceFast(thread, thisObj, srcString, length); + } + JSHandle regexpHandle(thisObj); + useIntermediateCache = true; + if (!functionalReplace) { + uint32_t strLength = EcmaStringAccessor(replaceValueHandle).GetLength(); + uint32_t largeStrCount = cacheTable->GetLargeStrCount(); + if (largeStrCount != 0) { + if (strLength > MIN_REPLACE_STRING_LENGTH) { + cacheTable->SetLargeStrCount(thread, --largeStrCount); } - if (strLength > cacheTable->GetStrLenThreshold()) { - useCache = true; - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flagsBits, string, - RegExpExecResultCache::REPLACE_TYPE, - thisObj, JSTaggedValue(0), - inputReplaceValue.GetTaggedValue()); - if (!cacheResult.IsUndefined()) { - return cacheResult; - } + } else { + cacheTable->SetStrLenThreshold(thread, MIN_REPLACE_STRING_LENGTH); + } + if (strLength > cacheTable->GetStrLenThreshold()) { + uint32_t lastIndexInput = static_cast(GetLastIndex(thread, thisObj, isFastPath)); + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, string, + RegExpExecResultCache::REPLACE_TYPE, thisObj, JSTaggedValue(lastIndexInput), + inputReplaceValue.GetTaggedValue()); + if (!cacheResult.IsUndefined()) { + return cacheResult; } } } } - JSHandle matchedStr = globalConst->GetHandledZeroString(); // 11. Let results be a new empty List. JSMutableHandle resultsList(thread, JSArray::ArrayCreate(thread, JSTaggedNumber(0))); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -991,10 +1018,10 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, // Add cache for the intermediate result of replace JSTaggedValue cachedResultsList(JSTaggedValue::VALUE_UNDEFINED); if (useIntermediateCache) { - cachedResultsList = cacheTable->FindCachedResult(thread, pattern, flagsBits, string, - RegExpExecResultCache::INTERMEDIATE_REPLACE_TYPE, - thisObj, JSTaggedValue(0), JSTaggedValue::Undefined(), - true); + uint32_t lastIndexInput = static_cast(GetLastIndex(thread, thisObj, isFastPath)); + cachedResultsList = cacheTable->FindCachedResult(thread, string, + RegExpExecResultCache::INTERMEDIATE_REPLACE_TYPE, thisObj, + JSTaggedValue(lastIndexInput), JSTaggedValue::Undefined(), true); } if (!cachedResultsList.IsUndefined()) { resultsList.Update(cachedResultsList); @@ -1004,7 +1031,7 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, // 13. Repeat, while done is false for (;;) { // a. Let result be RegExpExec(rx, S). - execResult.Update(RegExpExec(thread, thisObj, inputStr, useCache)); + execResult.Update(RegExpExec(thread, thisObj, inputStr, useCache, true)); // b. ReturnIfAbrupt(result). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // c. If result is null, set done to true. @@ -1012,13 +1039,20 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, break; } // d. Else result is not null, i. Append result to the end of results. - JSObject::CreateDataProperty(thread, resultsList, resultsIndex, execResult); + TaggedArray *srcElements = TaggedArray::Cast(resultsList->GetElements().GetTaggedObject()); + JSMutableHandle elements(thread, srcElements); + if (resultsIndex >= static_cast(elements->GetLength())) { + elements.Update(JSObject::GrowElementsCapacity(thread, resultsList, elements->GetLength(), true)); + } + elements->Set(thread, resultsIndex, execResult); + JSArray::Cast(*resultsList)->SetArrayLength(thread, resultsIndex + 1); resultsIndex++; // ii. If global is false, set done to true. if (!isGlobal) { break; } // iii. Else, 1. Let matchStr be ToString(Get(result, "0")). + JSHandle matchedStr = globalConst->GetHandledZeroString(); JSTaggedValue getMatchVal = ObjectFastOperator::FastGetPropertyByValue( thread, execResult.GetTaggedValue(), matchedStr.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -1029,37 +1063,26 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, // 3. If matchStr is the empty String, then if (EcmaStringAccessor(matchString).GetLength() == 0) { // a. Let thisIndex be ToLength(Get(rx, "lastIndex")). - JSTaggedValue thisIndexVal = ObjectFastOperator::FastGetPropertyByValue( - thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue()); + uint32_t thisIndex = static_cast(GetLastIndex(thread, thisObj, isFastPath)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle thisIndexHandle(thread, thisIndexVal); - uint32_t thisIndex = 0; - if (thisIndexHandle->IsInt()) { - thisIndex = static_cast(thisIndexHandle->GetInt()); - } else { - thisIndex = JSTaggedValue::ToLength(thread, thisIndexHandle).GetNumber(); - // b. ReturnIfAbrupt(thisIndex). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - } // c. Let nextIndex be AdvanceStringIndex(S, thisIndex, fullUnicode). uint32_t nextIndex = static_cast(AdvanceStringIndex(inputStr, thisIndex, fullUnicode)); nextIndexHandle.Update(JSTaggedValue(nextIndex)); // d. Let setStatus be Set(rx, "lastIndex", nextIndex, true). - ObjectFastOperator::FastSetPropertyByValue(thread, thisObj.GetTaggedValue(), lastIndex.GetTaggedValue(), - nextIndexHandle.GetTaggedValue()); + SetLastIndex(thread, thisObj, nextIndexHandle.GetTaggedValue(), isFastPath); // e. ReturnIfAbrupt(setStatus). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } } if (useIntermediateCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, string, + RegExpExecResultCache::AddResultInCache(thread, cacheTable, thisObj, string, JSHandle(resultsList), RegExpExecResultCache::INTERMEDIATE_REPLACE_TYPE, 0, 0, JSTaggedValue::Undefined(), true); } } // 14. Let accumulatedResult be the empty String value. - std::string accumulatedResult; + JSMutableHandle accumulatedResult(thread, factory->GetEmptyString()); // 15. Let nextSourcePosition be 0. uint32_t nextSourcePosition = 0; JSMutableHandle getMatchString(thread, JSTaggedValue::Undefined()); @@ -1068,11 +1091,10 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, JSMutableHandle capN(thread, JSTaggedValue(0)); // 16. Repeat, for each result in results, for (int i = 0; i < resultsIndex; i++) { - resultValues.Update(ObjectFastOperator::FastGetPropertyByIndex(thread, resultsList.GetTaggedValue(), i)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + resultValues.Update(ElementAccessor::Get(resultsList, i)); // a. Let nCaptures be ToLength(Get(result, "length")). uint32_t ncaptures; - if (unmodified) { + if (isFastPath) { ncaptures = static_cast(JSArray::Cast(resultValues.GetTaggedValue())->GetArrayLength()); } else { JSHandle lengthHandle = globalConst->GetHandledLengthString(); @@ -1095,9 +1117,7 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, // f. Let matchLength be the number of code units in matched. uint32_t matchLength = EcmaStringAccessor(matchString).GetLength(); // g. Let position be ToInteger(Get(result, "index")). - JSHandle resultIndex = globalConst->GetHandledIndexString(); - JSTaggedValue positionTag = ObjectFastOperator::FastGetPropertyByValue( - thread, resultValues.GetTaggedValue(), resultIndex.GetTaggedValue()); + JSTaggedValue positionTag = GetExecResultIndex(thread, resultValues, isFastPath); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle positionHandle(thread, positionTag); uint32_t position = 0; @@ -1137,13 +1157,11 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, } // j. Let namedCaptures be ? Get(result, "groups"). - JSHandle groupsKey = globalConst->GetHandledGroupsString(); - JSTaggedValue named = ObjectFastOperator::FastGetPropertyByValue(thread, - resultValues.GetTaggedValue(), groupsKey.GetTaggedValue()); - JSHandle namedCaptures(thread, named); + JSTaggedValue named = GetExecResultGroups(thread, resultValues, isFastPath); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle namedCaptures(thread, named); // m. If functionalReplace is true, then - CString replacement; + JSMutableHandle replacementString(thread, factory->GetEmptyString()); int emptyArrLength = 0; if (namedCaptures->IsUndefined()) { emptyArrLength = 3; // 3: «matched, pos, and string» @@ -1178,10 +1196,9 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle replValue(thread, replaceResult); // v. Let replacement be ToString(replValue). - JSHandle replacementString = JSTaggedValue::ToString(thread, replValue); + replacementString.Update(JSTaggedValue::ToString(thread, replValue)); // o. ReturnIfAbrupt(replacement). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - replacement = ConvertToString(*replacementString, StringConvertedUsage::LOGICOPERATION); } else { // n. Else, if (!namedCaptures->IsUndefined()) { @@ -1189,12 +1206,8 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); namedCaptures = JSHandle::Cast(namedCapturesObj); } - JSHandle replacementHandle( - thread, BuiltinsString::GetSubstitution(thread, matchString, srcString, - position, capturesList, namedCaptures, - replaceValueHandle)); - replacement = ConvertToString(EcmaString::Cast(replacementHandle->GetTaggedObject()), - StringConvertedUsage::LOGICOPERATION); + replacementString.Update(BuiltinsString::GetSubstitution(thread, matchString, srcString, + position, capturesList, namedCaptures, replaceValueHandle)); } // p. If position ≥ nextSourcePosition, then if (position >= nextSourcePosition) { @@ -1203,36 +1216,37 @@ JSTaggedValue BuiltinsRegExp::ReplaceInternal(JSThread *thread, // (inclusive) up to position (exclusive) and with the code units of replacement. auto substr = EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), JSHandle::Cast(inputStr), nextSourcePosition, position - nextSourcePosition); - accumulatedResult += EcmaStringAccessor(substr).ToStdString(StringConvertedUsage::LOGICOPERATION); - accumulatedResult += replacement; + accumulatedResult.Update(JSHandle(thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), + accumulatedResult, JSHandle(thread, substr)))); + accumulatedResult.Update(JSHandle(thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), + accumulatedResult, replacementString))); // iii. Let nextSourcePosition be position + matchLength. nextSourcePosition = position + matchLength; } } // 17. If nextSourcePosition ≥ lengthS, return accumulatedResult. if (nextSourcePosition >= length) { - JSHandle resultValue = factory->NewFromStdString(accumulatedResult); if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, string, - JSHandle(resultValue), + RegExpExecResultCache::AddResultInCache(thread, cacheTable, thisObj, string, + JSHandle(accumulatedResult), RegExpExecResultCache::REPLACE_TYPE, 0, nextIndexHandle->GetInt(), inputReplaceValue.GetTaggedValue()); } - return resultValue.GetTaggedValue(); + return accumulatedResult.GetTaggedValue(); } // 18. Return the String formed by concatenating the code units of accumulatedResult with the substring of S // consisting of the code units from nextSourcePosition (inclusive) up through the final code unit of S(inclusive). auto substr = EcmaStringAccessor::FastSubString(thread->GetEcmaVM(), JSHandle::Cast(inputStr), nextSourcePosition, length - nextSourcePosition); - accumulatedResult += EcmaStringAccessor(substr).ToStdString(StringConvertedUsage::LOGICOPERATION); - JSHandle resultValue = factory->NewFromStdString(accumulatedResult); + accumulatedResult.Update(JSHandle(thread, EcmaStringAccessor::Concat(thread->GetEcmaVM(), + accumulatedResult, JSHandle(thread, substr)))); if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, string, - JSHandle(resultValue), + RegExpExecResultCache::AddResultInCache(thread, cacheTable, thisObj, string, + JSHandle(accumulatedResult), RegExpExecResultCache::REPLACE_TYPE, 0, nextIndexHandle->GetInt(), inputReplaceValue.GetTaggedValue()); } - return resultValue.GetTaggedValue(); + return accumulatedResult.GetTaggedValue(); } // 21.2.5.9 @@ -1254,6 +1268,11 @@ JSTaggedValue BuiltinsRegExp::Search(EcmaRuntimeCallInfo *argv) // 2. If Type(rx) is not Object, throw a TypeError exception. THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception()); } + + bool isFastPath = IsFastRegExp(thread, thisObj); + if (isFastPath) { + return RegExpSearchFast(thread, thisObj, string); + } // 4. Let previousLastIndex be ? Get(rx, "lastIndex"). JSHandle lastIndexString(thread->GlobalConstants()->GetHandledLastIndexString()); JSHandle previousLastIndex = JSObject::GetProperty(thread, thisObj, lastIndexString).GetValue(); @@ -1286,50 +1305,55 @@ JSTaggedValue BuiltinsRegExp::Search(EcmaRuntimeCallInfo *argv) return JSObject::GetProperty(thread, result, index).GetValue().GetTaggedValue(); } -// 21.2.5.11 -// NOLINTNEXTLINE(readability-function-size) -JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) +JSTaggedValue BuiltinsRegExp::RegExpSearchFast(JSThread *thread, + const JSHandle regexp, + const JSHandle string) { - ASSERT(argv); - BUILTINS_API_TRACE(argv->GetThread(), RegExp, Split); - JSThread *thread = argv->GetThread(); - [[maybe_unused]] EcmaHandleScope handleScope(thread); - bool useCache = false; - // 1. Let rx be the this value. - JSHandle thisObj = GetThis(argv); - auto ecmaVm = thread->GetEcmaVM(); - // 3. Let S be ToString(string). - JSHandle inputString = GetCallArg(argv, 0); - JSHandle limit = GetCallArg(argv, 1); - JSHandle stringHandle = JSTaggedValue::ToString(thread, inputString); - - // 4. ReturnIfAbrupt(string). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle jsString = JSHandle::Cast(stringHandle); - if (!thisObj->IsECMAObject()) { - // 2. If Type(rx) is not Object, throw a TypeError exception. - THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception()); + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, string, + RegExpExecResultCache::SEARCH_TYPE, regexp, + JSTaggedValue(0)); + if (!cacheResult.IsUndefined()) { + return cacheResult; + } + JSHandle stringHandle = JSHandle::Cast(string); + bool matchResult = RegExpExecInternal(thread, regexp, stringHandle, 0); + if (!matchResult) { + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, string, + JSHandle(thread, JSTaggedValue(-1)), + RegExpExecResultCache::SEARCH_TYPE, + 0, 0); + return JSTaggedValue(-1); } - if (IsFastRegExp(thread, thisObj)) { - JSHandle regexpObj(thisObj); - JSMutableHandle flags(thread, regexpObj->GetOriginalFlags()); - uint8_t flagsBits = static_cast(flags->GetInt()); - bool sticky = (flagsBits & RegExpParser::FLAG_STICKY) != 0; - if (!sticky) { - if (limit->IsUndefined()) { - useCache = true; - return RegExpSplitFast(thread, thisObj, stringHandle, MAX_SPLIT_LIMIT, useCache); - } else if (limit->IsInt()) { - int64_t lim = limit->GetInt(); - if (lim >= 0) { - return RegExpSplitFast(thread, thisObj, stringHandle, static_cast(lim), useCache); - } + JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + JSTaggedValue result = globalTable->GetStartOfCaptureIndex(0); + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, string, + JSHandle(thread, JSTaggedValue(result)), + RegExpExecResultCache::SEARCH_TYPE, + 0, 0); + return result; +} + +JSTaggedValue BuiltinsRegExp::RegExpSplit(JSThread *thread, const JSHandle regexp, + JSHandle jsString, JSHandle limit, + bool isFastPath) +{ + bool useCache = false; + if (isFastPath) { + if (limit->IsUndefined()) { + useCache = true; + return RegExpSplitFast(thread, regexp, jsString, MAX_SPLIT_LIMIT, useCache); + } else if (limit->IsInt()) { + int64_t lim = limit->GetInt(); + if (lim >= 0) { + return RegExpSplitFast(thread, regexp, jsString, static_cast(lim), useCache); } } } + auto ecmaVm = thread->GetEcmaVM(); // 5. Let C be SpeciesConstructor(rx, %RegExp%). JSHandle defaultConstructor = ecmaVm->GetGlobalEnv()->GetRegExpFunction(); - JSHandle objHandle(thisObj); + JSHandle objHandle(regexp); JSHandle constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); // 6. ReturnIfAbrupt(C). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -1337,7 +1361,7 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) ObjectFactory *factory = ecmaVm->GetFactory(); const GlobalEnvConstants *globalConstants = thread->GlobalConstants(); JSHandle flagsString(globalConstants->GetHandledFlagsString()); - JSHandle taggedFlags = JSObject::GetProperty(thread, thisObj, flagsString).GetValue(); + JSHandle taggedFlags = JSObject::GetProperty(thread, regexp, flagsString).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle flags; @@ -1363,44 +1387,13 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) newFlagsHandle = factory->ConcatFromString(flags, yStr); } - // 17. If limit is undefined, let lim be 2^32–1; else let lim be ToUint32(limit). - uint32_t lim; - if (limit->IsUndefined()) { - lim = MAX_SPLIT_LIMIT; - } else { - lim = JSTaggedValue::ToUint32(thread, limit); - // 18. ReturnIfAbrupt(lim). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - } - - if (lim == MAX_SPLIT_LIMIT) { - useCache = true; - } - - JSHandle regexpHandle(thisObj); - JSMutableHandle pattern(thread, JSTaggedValue::Undefined()); - JSMutableHandle flagsBits(thread, JSTaggedValue::Undefined()); - if (thisObj->IsJSRegExp()) { - pattern.Update(regexpHandle->GetOriginalSource()); - flagsBits.Update(regexpHandle->GetOriginalFlags()); - } - JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); - if (useCache) { - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flagsBits, inputString, - RegExpExecResultCache::SPLIT_TYPE, thisObj, - JSTaggedValue(0)); - if (!cacheResult.IsUndefined()) { - return cacheResult; - } - } - // 13. Let splitter be Construct(C, «rx, newFlags»). JSHandle globalObject(thread, thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject()); JSHandle undefined = globalConstants->GetHandledUndefined(); EcmaRuntimeCallInfo *runtimeInfo = EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 2); // 2: two args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - runtimeInfo->SetCallArg(thisObj.GetTaggedValue(), newFlagsHandle.GetTaggedValue()); + runtimeInfo->SetCallArg(regexp.GetTaggedValue(), newFlagsHandle.GetTaggedValue()); JSTaggedValue taggedSplitter = JSFunction::Construct(runtimeInfo); // 14. ReturnIfAbrupt(splitter). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -1412,6 +1405,16 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) // 16. Let lengthA be 0. uint32_t aLength = 0; + // 17. If limit is undefined, let lim be 2^32–1; else let lim be ToUint32(limit). + uint32_t lim; + if (limit->IsUndefined()) { + lim = MAX_SPLIT_LIMIT; + } else { + lim = JSTaggedValue::ToUint32(thread, limit); + // 18. ReturnIfAbrupt(lim). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + // 19. Let size be the number of elements in S. uint32_t size = EcmaStringAccessor(jsString->GetTaggedObject()).GetLength(); // 20. Let p be 0. @@ -1481,11 +1484,6 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) ++aLength; // 5. If lengthA = lim, return A. if (aLength == lim) { - if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, inputString, - JSHandle(array), - RegExpExecResultCache::SPLIT_TYPE, 0, lastIndex); - } return array.GetTaggedValue(); } // 6. Let p be e. @@ -1517,11 +1515,6 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) ++aLength; // f. If lengthA = lim, return A. if (aLength == lim) { - if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, inputString, - JSHandle(array), - RegExpExecResultCache::SPLIT_TYPE, 0, lastIndex); - } return array.GetTaggedValue(); } } @@ -1539,48 +1532,75 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) // 27. Perform CreateDataProperty(A, ToString(lengthA), t). JSHandle tValue(factory->NewFromStdString(stdStrT)); JSObject::CreateDataProperty(thread, array, aLength, tValue); - if (lim == MAX_SPLIT_LIMIT) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flagsBits, inputString, - JSHandle(array), RegExpExecResultCache::SPLIT_TYPE, - 0, endIndex); - } // 28. Return A. return array.GetTaggedValue(); } +// 21.2.5.11 +// NOLINTNEXTLINE(readability-function-size) +JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), RegExp, Split); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let rx be the this value. + JSHandle thisObj = GetThis(argv); + // 3. Let S be ToString(string). + JSHandle inputString = GetCallArg(argv, 0); + JSHandle limit = GetCallArg(argv, 1); + JSHandle stringHandle = JSTaggedValue::ToString(thread, inputString); -JSTaggedValue BuiltinsRegExp::RegExpSplitFast(JSThread *thread, const JSHandle ®exp, - JSHandle string, uint32_t limit, bool useCache) + // 4. ReturnIfAbrupt(string). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle jsString = JSHandle::Cast(stringHandle); + if (!thisObj->IsECMAObject()) { + // 2. If Type(rx) is not Object, throw a TypeError exception. + THROW_TYPE_ERROR_AND_RETURN(thread, "this is not Object", JSTaggedValue::Exception()); + } + bool isFastPath = IsFastRegExp(thread, thisObj); + return RegExpSplit(thread, thisObj, jsString, limit, isFastPath); +} + +JSTaggedValue BuiltinsRegExp::RegExpSplitFast(JSThread *thread, const JSHandle regexp, + JSHandle jsString, uint32_t limit, bool useCache) { - JSHandle jsString = JSHandle::Cast(string); if (limit == 0) { return JSArray::ArrayCreate(thread, JSTaggedNumber(0), ArrayMode::LITERAL).GetTaggedValue(); } + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); + if (useCache) { + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, jsString, + RegExpExecResultCache::SPLIT_TYPE, regexp, + JSTaggedValue(0)); + if (!cacheResult.IsUndefined()) { + return cacheResult; + } + } uint32_t size = EcmaStringAccessor(jsString->GetTaggedObject()).GetLength(); + JSHandle string = JSHandle::Cast(jsString); if (size == 0) { bool matchResult = RegExpExecInternal(thread, regexp, string, 0); // 0: lastIndex if (matchResult) { - return JSArray::ArrayCreate(thread, JSTaggedNumber(0), ArrayMode::LITERAL).GetTaggedValue(); + JSHandle res = JSArray::ArrayCreate(thread, JSTaggedNumber(0), ArrayMode::LITERAL); + if (useCache) { + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, jsString, + res, RegExpExecResultCache::SPLIT_TYPE, 0, 0); + } + return res.GetTaggedValue(); } JSHandle element = thread->GetEcmaVM()->GetFactory()->NewTaggedArray(1); // 1: length element->Set(thread, 0, jsString); - return JSArray::CreateArrayFromList(thread, element).GetTaggedValue(); - } - JSHandle regexpObj(regexp); - JSMutableHandle pattern(thread, regexpObj->GetOriginalSource()); - JSMutableHandle flags(thread, regexpObj->GetOriginalFlags()); - uint8_t flagsBits = static_cast(flags->GetInt()); - bool isUnicode = (flagsBits & RegExpParser::FLAG_UTF16) != 0; - - JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); - if (useCache) { - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, jsString, - RegExpExecResultCache::SPLIT_TYPE, regexp, - JSTaggedValue(0)); - if (!cacheResult.IsUndefined()) { - return cacheResult; + JSHandle res = JSHandle::Cast(JSArray::CreateArrayFromList(thread, element)); + if (useCache) { + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, jsString, + res, RegExpExecResultCache::SPLIT_TYPE, 0, 0); } + return res.GetTaggedValue(); } + bool isUnicode = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_UTF16); + bool isSticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY); + uint32_t nextMatchFrom = 0; uint32_t lastMatchEnd = 0; uint32_t arrLen = 1; // at least one result string @@ -1592,8 +1612,12 @@ JSTaggedValue BuiltinsRegExp::RegExpSplitFast(JSThread *thread, const JSHandle(AdvanceStringIndex(jsString, nextMatchFrom, isUnicode)); + continue; } // find match result JSHandle matchResultInfo(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); @@ -1613,9 +1637,9 @@ JSTaggedValue BuiltinsRegExp::RegExpSplitFast(JSThread *thread, const JSHandleSetArrayLength(thread, arrLen); if (arrLen == limit) { if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, jsString, + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, jsString, JSHandle(splitArray), - RegExpExecResultCache::SPLIT_TYPE, 0, matchEndIndex); + RegExpExecResultCache::SPLIT_TYPE, 0, 0); } return JSTaggedValue(splitArray.GetTaggedValue().GetTaggedObject()); } @@ -1642,9 +1666,9 @@ JSTaggedValue BuiltinsRegExp::RegExpSplitFast(JSThread *thread, const JSHandleSetArrayLength(thread, arrLen); if (arrLen == limit) { if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, jsString, + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, jsString, JSHandle(splitArray), - RegExpExecResultCache::SPLIT_TYPE, 0, matchEndIndex); + RegExpExecResultCache::SPLIT_TYPE, 0, 0); } return JSTaggedValue(splitArray.GetTaggedValue().GetTaggedObject()); } @@ -1663,15 +1687,15 @@ JSTaggedValue BuiltinsRegExp::RegExpSplitFast(JSThread *thread, const JSHandleSet(thread, arrLen - 1, matchValue); splitArray->SetArrayLength(thread, arrLen); if (limit == MAX_SPLIT_LIMIT) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, jsString, + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, jsString, JSHandle(splitArray), RegExpExecResultCache::SPLIT_TYPE, - 0, lastMatchEnd); + 0, 0); } return JSTaggedValue(splitArray.GetTaggedValue().GetTaggedObject()); } -bool BuiltinsRegExp::RegExpExecInternal(JSThread *thread, const JSHandle ®exp, - JSHandle &inputString, int32_t lastIndex) +bool BuiltinsRegExp::RegExpExecInternal(JSThread *thread, const JSHandle regexp, + JSHandle inputString, int32_t lastIndex) { size_t stringLength = EcmaStringAccessor(inputString).GetLength(); bool isUtf16 = EcmaStringAccessor(inputString).IsUtf16(); @@ -1695,7 +1719,7 @@ bool BuiltinsRegExp::RegExpExecInternal(JSThread *thread, const JSHandle ®exp, +bool BuiltinsRegExp::Matcher(JSThread *thread, const JSHandle regexp, const uint8_t *buffer, size_t length, int32_t lastIndex, bool isUtf16) { @@ -1851,99 +1875,61 @@ JSHandle BuiltinsRegExp::MakeMatchIndicesIndexPairArray(JSThread } // 21.2.5.2.2 -JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle ®exp, - const JSHandle &inputStr, bool useCache) +JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle regexp, + const JSHandle inputStr, + bool isFastPath, bool useCache, bool isIntermediateResult) { ASSERT(JSObject::IsRegExp(thread, regexp)); ASSERT(inputStr->IsString()); BUILTINS_API_TRACE(thread, RegExp, RegExpBuiltinExec); - const GlobalEnvConstants *globalConst = thread->GlobalConstants(); - JSHandle lastIndexHandle = globalConst->GetHandledLastIndexString(); - JSTaggedValue result = - ObjectFastOperator::FastGetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue()); + uint32_t lastIndex = static_cast(GetLastIndex(thread, regexp, isFastPath)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - int32_t lastIndex = 0; - if (result.IsInt()) { - lastIndex = result.GetInt(); - } else { - JSHandle lastIndexResult(thread, result); - JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - lastIndex = lastIndexNumber.GetNumber(); - } - - JSHandle regexpObj(regexp); - JSMutableHandle pattern(thread, regexpObj->GetOriginalSource()); - JSMutableHandle flags(thread, regexpObj->GetOriginalFlags()); JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); - - uint8_t flagsBits = static_cast(flags->GetInt()); - bool global = (flagsBits & RegExpParser::FLAG_GLOBAL) != 0; - bool sticky = (flagsBits & RegExpParser::FLAG_STICKY) != 0; - bool hasIndices = (flagsBits & RegExpParser::FLAG_HASINDICES) != 0; - if (!global && !sticky) { - lastIndex = 0; - } - uint32_t lastIndexInput = static_cast(lastIndex); if (useCache) { - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, inputStr, + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, inputStr, RegExpExecResultCache::EXEC_TYPE, regexp, - JSTaggedValue(lastIndexInput)); + JSTaggedValue(lastIndex)); if (!cacheResult.IsUndefined()) { return cacheResult; } } - - uint32_t length = EcmaStringAccessor(inputStr->GetTaggedObject()).GetLength(); - if (lastIndex > static_cast(length)) { - ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), - JSTaggedValue(0)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - return JSTaggedValue::Null(); + JSTaggedValue result = RegExpBuiltinExecWithoutResult(thread, regexp, inputStr, isFastPath, lastIndex, useCache); + if (result.IsNull()) { + return result; } JSHandle inputString = JSHandle::Cast(inputStr); - bool matchResult = RegExpExecInternal(thread, regexp, inputString, lastIndex); - if (!matchResult) { - if (global || sticky) { - JSHandle lastIndexValue(thread, JSTaggedValue(0)); - ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), - lastIndexHandle.GetTaggedValue(), - JSTaggedValue(0)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - } - return JSTaggedValue::Null(); - } JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); - uint32_t endIndex = static_cast(globalTable->GetEndIndex().GetInt()); - if (global || sticky) { - // a. Let setStatus be Set(R, "lastIndex", e, true). - ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), - JSTaggedValue(endIndex)); - // b. ReturnIfAbrupt(setStatus). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - } uint32_t capturesSize = static_cast(globalTable->GetTotalCaptureCounts().GetInt()); JSHandle results(JSArray::ArrayCreate(thread, JSTaggedNumber(capturesSize))); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // 24. Perform CreateDataProperty(A, "index", matchIndex). - JSHandle indexKey = globalConst->GetHandledIndexString(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle indexValue(thread, globalTable->GetStartOfCaptureIndex(0)); - JSObject::CreateDataProperty(thread, results, indexKey, indexValue); - // 25. Perform CreateDataProperty(A, "input", S). - JSHandle inputKey = globalConst->GetHandledInputString(); - JSHandle inputValue(thread, static_cast(inputStr->GetTaggedObject())); - JSObject::CreateDataProperty(thread, results, inputKey, inputValue); + if (isIntermediateResult) { + // inlined intermediate result + results->SetPropertyInlinedPropsWithRep(thread, EXEC_RESULT_INDEX_OFFSET, indexValue.GetTaggedValue()); + results->SetPropertyInlinedPropsWithRep(thread, EXEC_RESULT_INPUT_OFFSET, inputStr.GetTaggedValue()); + } else { + // 24. Perform CreateDataProperty(A, "index", matchIndex). + JSHandle indexKey = globalConst->GetHandledIndexString(); + JSObject::CreateDataProperty(thread, results, indexKey, indexValue); + // 25. Perform CreateDataProperty(A, "input", S). + JSHandle inputKey = globalConst->GetHandledInputString(); + JSObject::CreateDataProperty(thread, results, inputKey, inputStr); + } // 27. Perform CreateDataProperty(A, "0", matched_substr). uint32_t startIndex = static_cast(globalTable->GetStartOfCaptureIndex(0).GetInt()); uint32_t len = static_cast(globalTable->GetEndOfCaptureIndex(0).GetInt()) - startIndex; JSHandle zeroValue(thread, JSTaggedValue(EcmaStringAccessor::FastSubString( thread->GetEcmaVM(), inputString, startIndex, len))); - JSObject::CreateDataProperty(thread, results, 0, zeroValue); + TaggedArray *srcElements = TaggedArray::Cast(results->GetElements().GetTaggedObject()); + JSHandle resultElements(thread, srcElements); + resultElements->Set(thread, 0, zeroValue); // Let indices be a new empty List. // Let groupNames be a new empty List. // Append match to indices. + uint32_t endIndex = globalTable->GetEndIndex().GetInt(); std::vector> indices; std::vector> groupNames; indices.emplace_back(std::make_pair(globalTable->GetStartOfCaptureIndex(0), JSTaggedValue(endIndex))); @@ -1953,6 +1939,7 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle // Else, // a. Let groups be undefined. // b. Let hasGroups be false. + JSHandle regexpObj(regexp); JSHandle groupName(thread, regexpObj->GetGroupName()); JSMutableHandle groups(thread, JSTaggedValue::Undefined()); bool hasGroups = false; @@ -1963,9 +1950,14 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle groups.Update(nullObj.GetTaggedValue()); hasGroups = true; } - // Perform ! CreateDataPropertyOrThrow(A, "groups", groups). - JSHandle groupsKey = globalConst->GetHandledGroupsString(); - JSObject::CreateDataProperty(thread, results, groupsKey, groups); + if (isIntermediateResult) { + // inlined intermediate result + results->SetPropertyInlinedPropsWithRep(thread, EXEC_RESULT_GROUPS_OFFSET, groups.GetTaggedValue()); + } else { + // Perform ! CreateDataPropertyOrThrow(A, "groups", groups). + JSHandle groupsKey = globalConst->GetHandledGroupsString(); + JSObject::CreateDataProperty(thread, results, groupsKey, groups); + } // Create a new RegExp on global uint32_t captureIndex = 1; JSHandle undefined = globalConst->GetHandledUndefined(); @@ -1989,7 +1981,7 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle globalTable->SetCapture(thread, captureIndex, iValue.GetTaggedValue()); } - JSObject::CreateDataProperty(thread, results, captureIndex, iValue); + resultElements->Set(thread, captureIndex, iValue); if (!groupName->IsUndefined()) { JSHandle groupObject = JSHandle::Cast(groups); TaggedArray *groupArray = TaggedArray::Cast(regexpObj->GetGroupName().GetTaggedObject()); @@ -2007,6 +1999,7 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle // If hasIndices is true, then // a. Let indicesArray be MakeMatchIndicesIndexPairArray(S, indices, groupNames, hasGroups). // b. Perform ! CreateDataPropertyOrThrow(A, "indices", indicesArray). + bool hasIndices = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_HASINDICES); if (hasIndices) { auto indicesArray = MakeMatchIndicesIndexPairArray(thread, indices, groupNames, hasGroups); JSHandle indicesKey = globalConst->GetHandledIndicesString(); @@ -2018,17 +2011,68 @@ JSTaggedValue BuiltinsRegExp::RegExpBuiltinExec(JSThread *thread, const JSHandle ++captureIndex; } if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputStr, + uint32_t newLastIndex = lastIndex; + bool global = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL); + bool sticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY); + if (global || sticky) { + newLastIndex = globalTable->GetEndIndex().GetInt(); + } + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, inputStr, JSHandle(results), RegExpExecResultCache::EXEC_TYPE, - lastIndexInput, endIndex); + lastIndex, newLastIndex); } // 29. Return A. return results.GetTaggedValue(); } +JSTaggedValue BuiltinsRegExp::RegExpBuiltinExecWithoutResult(JSThread *thread, const JSHandle regexp, + const JSHandle inputStr, + bool isFastPath, uint32_t lastIndex, bool useCache) +{ + // check global and sticky flag to determine whether need to update lastIndex + bool global = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_GLOBAL); + bool sticky = GetOringinalFlag(thread, regexp, RegExpParser::FLAG_STICKY); + bool ifUpdateLastIndex = global || sticky; + if (ifUpdateLastIndex) { + uint32_t length = EcmaStringAccessor(inputStr->GetTaggedObject()).GetLength(); + if (lastIndex > length) { + SetLastIndex(thread, regexp, JSTaggedValue(0), isFastPath); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return JSTaggedValue::Null(); + } + } else { + lastIndex = 0; + } + JSHandle inputString = JSHandle::Cast(inputStr); + bool matchResult = RegExpExecInternal(thread, regexp, inputString, lastIndex); + if (!matchResult) { + uint32_t endIndex = lastIndex; + if (ifUpdateLastIndex) { + endIndex = 0; + SetLastIndex(thread, regexp, JSTaggedValue(0), isFastPath); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + if (useCache) { + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); + RegExpExecResultCache::AddResultInCache(thread, cacheTable, regexp, inputStr, + JSHandle(thread, JSTaggedValue::Null()), + RegExpExecResultCache::EXEC_TYPE, + lastIndex, endIndex); + } + return JSTaggedValue::Null(); + } + JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); + JSTaggedValue endIndex = globalTable->GetEndIndex(); + if (ifUpdateLastIndex) { + SetLastIndex(thread, regexp, endIndex, isFastPath); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + return JSTaggedValue::True(); +} // 21.2.5.2.1 JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle ®exp, - const JSHandle &inputString, bool useCache) + const JSHandle &inputString, bool useCache, + bool isIntermediateResult) { BUILTINS_API_TRACE(thread, RegExp, RegExpExec); // 1. Assert: Type(R) is Object. @@ -2038,22 +2082,11 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle inputStr = JSTaggedValue::ToString(thread, inputString); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle execHandle = globalConst->GetHandledExecString(); JSTaggedValue execVal = ObjectFastOperator::FastGetPropertyByValue(thread, regexp.GetTaggedValue(), execHandle.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - if (execVal == env->GetTaggedRegExpExecFunction() && regexp->IsJSRegExp()) { - JSTaggedValue result = RegExpBuiltinExec(thread, regexp, JSHandle(inputStr), useCache); - // b. ReturnIfAbrupt(result). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - if (!result.IsECMAObject() && !result.IsNull()) { - // throw a TypeError exception. - THROW_TYPE_ERROR_AND_RETURN(thread, "exec result is null or is not Object", JSTaggedValue::Exception()); - } - return result; - } JSHandle exec(thread, execVal); // 4. ReturnIfAbrupt(exec). @@ -2079,79 +2112,7 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandle ®exp, - const JSHandle &inputStr, bool useCache) -{ - JSHandle object = JSHandle::Cast(regexp); - JSTaggedValue lastIndexValue = object->GetPropertyInlinedProps(LAST_INDEX_OFFSET); - // ASSERT GetPropertyInlinedProps(LAST_INDEX_OFFSET) is not hole - ASSERT(!JSTaggedValue::SameValue(lastIndexValue, JSTaggedValue::Hole())); - // 1. load lastIndex as length - int32_t lastIndex = 0; - if (lastIndexValue.IsInt()) { - lastIndex = lastIndexValue.GetInt(); - } else { - JSHandle lastIndexResult(thread, lastIndexValue); - JSTaggedNumber lastIndexNumber = JSTaggedValue::ToLength(thread, lastIndexResult); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - lastIndex = lastIndexNumber.GetNumber(); - } - // 2. Check whether the regexp is global or sticky, which determines whether we update last index later on. - JSHandle regexpObj(regexp); - JSMutableHandle pattern(thread, regexpObj->GetOriginalSource()); - JSMutableHandle flags(thread, regexpObj->GetOriginalFlags()); - JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); - uint8_t flagsBits = static_cast(flags->GetInt()); - bool global = (flagsBits & RegExpParser::FLAG_GLOBAL) != 0; - bool sticky = (flagsBits & RegExpParser::FLAG_STICKY) != 0; - if (!global && !sticky) { - lastIndex = 0; - } - // 3. Search RegExpExecResult cache - uint32_t lastIndexInput = static_cast(lastIndex); - if (useCache) { - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, inputStr, - RegExpExecResultCache::TEST_TYPE, regexp, - JSTaggedValue(lastIndexInput)); - if (!cacheResult.IsUndefined()) { - return cacheResult; - } - } - - uint32_t length = EcmaStringAccessor(inputStr->GetTaggedObject()).GetLength(); - if (lastIndex > static_cast(length)) { - object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(0)); - return JSTaggedValue::False(); - } - JSHandle inputString = JSHandle::Cast(inputStr); - bool matchResult = RegExpExecInternal(thread, regexp, inputString, lastIndex); - if (!matchResult) { - if (global || sticky) { - object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, JSTaggedValue(0)); - } - if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputStr, - JSHandle(thread, JSTaggedValue(matchResult)), - RegExpExecResultCache::TEST_TYPE, - lastIndexInput, 0); // 0: match fail so lastIndex is 0 - } - return JSTaggedValue::False(); - } - JSHandle globalTable(thread->GetCurrentEcmaContext()->GetRegExpGlobalResult()); - JSTaggedValue endIndex = globalTable->GetEndIndex(); - if (global || sticky) { - object->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, endIndex); - } - if (useCache) { - RegExpExecResultCache::AddResultInCache(thread, cacheTable, pattern, flags, inputStr, - JSHandle(thread, JSTaggedValue(matchResult)), - RegExpExecResultCache::TEST_TYPE, - lastIndexInput, endIndex.GetInt()); - } - return GetTaggedBoolean(matchResult); + return RegExpBuiltinExec(thread, regexp, inputString, false, useCache, isIntermediateResult); } // 21.2.3.2.1 @@ -2294,8 +2255,6 @@ JSTaggedValue BuiltinsRegExp::RegExpInitialize(JSThread *thread, const JSHandle< flagsBits = static_cast(UpdateExpressionFlags(thread, checkStr)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - // String -> CString - CString patternStdStr = ConvertToString(*patternStrHandle, StringConvertedUsage::LOGICOPERATION); // 9. 10. Chunk chunk(thread->GetNativeAreaAllocator()); RegExpParser parser = RegExpParser(thread, &chunk); @@ -2303,6 +2262,8 @@ JSTaggedValue BuiltinsRegExp::RegExpInitialize(JSThread *thread, const JSHandle< CVector groupName; auto getCache = regExpParserCache->GetCache(*patternStrHandle, flagsBits, groupName); if (getCache.first.IsHole()) { + // String -> CString + CString patternStdStr = ConvertToString(*patternStrHandle, StringConvertedUsage::LOGICOPERATION); parser.Init(const_cast(reinterpret_cast(patternStdStr.c_str())), patternStdStr.size(), flagsBits); parser.Parse(); @@ -2337,11 +2298,7 @@ JSTaggedValue BuiltinsRegExp::RegExpInitialize(JSThread *thread, const JSHandle< regexp->SetLength(static_cast(getCache.second)); } // 14. Let setStatus be Set(obj, "lastIndex", 0, true). - JSHandle lastIndexString = thread->GlobalConstants()->GetHandledLastIndexString(); - ObjectFastOperator::FastSetPropertyByValue(thread, obj.GetTaggedValue(), - lastIndexString.GetTaggedValue(), JSTaggedValue(0)); - // 15. ReturnIfAbrupt(setStatus). - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + SetLastIndex(thread, obj, JSTaggedValue(0), true); // 16. Return obj. return obj.GetTaggedValue(); } @@ -2383,17 +2340,6 @@ EcmaString *BuiltinsRegExp::EscapeRegExpPattern(JSThread *thread, const JSHandle return *factory->NewFromUtf8(srcStdStr); } -JSTaggedValue BuiltinsRegExp::IsValidRegularExpression(JSThread *thread, JSHandle &thisObj) -{ - JSHandle patternStrHandle = JSTaggedValue::ToString(thread, thisObj); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - uint32_t regExpStringLength = static_cast(EcmaStringAccessor(patternStrHandle).GetLength()); - if (regExpStringLength > BuiltinsRegExp::MAX_REGEXP_STRING_COUNT) { - return JSTaggedValue::False(); - } - return JSTaggedValue::True(); -} - // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_GET_CAPTURE_IMPL(index) \ JSTaggedValue BuiltinsRegExp::GetCapture##index(JSThread *thread, [[maybe_unused]] const JSHandle &obj) \ @@ -2435,27 +2381,26 @@ JSTaggedValue RegExpExecResultCache::CreateCacheTable(JSThread *thread) } JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, - const JSHandle &pattern, - const JSHandle &flags, - const JSHandle &input, CacheType type, - const JSHandle ®exp, + const JSHandle input, CacheType type, + const JSHandle regexp, JSTaggedValue lastIndexInput, JSTaggedValue extend, bool isIntermediateResult) { - JSTaggedValue patternValue = pattern.GetTaggedValue(); - JSTaggedValue flagsValue = flags.GetTaggedValue(); + JSHandle regexpObj(regexp); + JSTaggedValue pattern = regexpObj->GetOriginalSource(); + JSTaggedValue flags = regexpObj->GetOriginalFlags(); JSTaggedValue inputValue = input.GetTaggedValue(); - if (!pattern->IsString() || !flags->IsInt() || !input->IsString() || !lastIndexInput.IsInt()) { + if (!pattern.IsString() || !flags.IsInt() || !input->IsString() || !lastIndexInput.IsInt()) { return JSTaggedValue::Undefined(); } - uint32_t hash = pattern->GetKeyHashCode() + static_cast(flags->GetInt()) + + uint32_t hash = pattern.GetKeyHashCode() + static_cast(flags.GetInt()) + input->GetKeyHashCode() + static_cast(lastIndexInput.GetInt()); uint32_t entry = hash & static_cast(GetCacheLength() - 1); - if (!Match(entry, patternValue, flagsValue, inputValue, lastIndexInput, extend, type)) { + if (!Match(entry, pattern, flags, inputValue, lastIndexInput, extend, type)) { uint32_t entry2 = (entry + 1) & static_cast(GetCacheLength() - 1); - if (!Match(entry2, patternValue, flagsValue, inputValue, lastIndexInput, extend, type)) { + if (!Match(entry2, pattern, flags, inputValue, lastIndexInput, extend, type)) { return JSTaggedValue::Undefined(); } entry = entry2; @@ -2488,16 +2433,18 @@ JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, case TEST_TYPE: result = Get(index + RESULT_TEST_INDEX); break; + case SEARCH_TYPE: + result = Get(index + RESULT_SEARCH_INDEX); + break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); break; } SetHitCount(thread, GetHitCount() + 1); - JSHandle lastIndexHandle = thread->GlobalConstants()->GetHandledLastIndexString(); - ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), lastIndexHandle.GetTaggedValue(), - Get(index + LAST_INDEX_INDEX)); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (type != SEARCH_TYPE && type != SPLIT_TYPE) { + BuiltinsRegExp::SetLastIndex(thread, regexp, Get(index + LAST_INDEX_INDEX), true); + } if (!isIntermediateResult && result.IsJSArray()) { JSHandle resultHandle(thread, JSArray::Cast(result)); JSHandle copyArray = thread->GetEcmaVM()->GetFactory()->CloneArrayLiteral(resultHandle); @@ -2507,12 +2454,15 @@ JSTaggedValue RegExpExecResultCache::FindCachedResult(JSThread *thread, } void RegExpExecResultCache::AddResultInCache(JSThread *thread, JSHandle cache, - const JSHandle &pattern, - const JSHandle &flags, const JSHandle &input, - const JSHandle &resultArray, CacheType type, + const JSHandle regexp, + const JSHandle input, + const JSHandle resultArray, CacheType type, uint32_t lastIndexInput, uint32_t lastIndex, JSTaggedValue extend, bool isIntermediateResult) { + JSHandle regexpObj(regexp); + JSHandle pattern(thread, regexpObj->GetOriginalSource()); + JSHandle flags(thread, regexpObj->GetOriginalFlags()); if (!pattern->IsString() || !flags->IsInt() || !input->IsString()) { return; } @@ -2610,7 +2560,6 @@ void RegExpExecResultCache::UpdateResultArray(JSThread *thread, int entry, JSTag static_cast(entry) * static_cast(ENTRY_SIZE)) <= static_cast(INT_MAX)); int index = CACHE_TABLE_HEADER_SIZE + entry * ENTRY_SIZE; switch (type) { - break; case REPLACE_TYPE: Set(thread, index + RESULT_REPLACE_INDEX, resultArray); break; @@ -2629,6 +2578,9 @@ void RegExpExecResultCache::UpdateResultArray(JSThread *thread, int entry, JSTag case TEST_TYPE: Set(thread, index + RESULT_TEST_INDEX, resultArray); break; + case SEARCH_TYPE: + Set(thread, index + RESULT_SEARCH_INDEX, resultArray); + break; default: LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -2729,4 +2681,97 @@ JSHandle RegExpGlobalResult::GrowCapturesCapacity(JSThread * thread->GetCurrentEcmaContext()->SetRegExpGlobalResult(newResult.GetTaggedValue()); return JSHandle(newResult); } + +bool BuiltinsRegExp::GetFlag(JSThread *thread, const JSHandle regexp, uint32_t flag, bool isFastPath) +{ + if (isFastPath) { + uint8_t flagsBits = static_cast(JSHandle::Cast(regexp)->GetOriginalFlags().GetInt()); + return (flagsBits & flag) != 0; + } else { + JSMutableHandle flagStr(thread, JSTaggedValue::Undefined()); + switch (flag) { + case RegExpParser::FLAG_GLOBAL: + flagStr.Update(thread->GlobalConstants()->GetHandledGlobalString()); + break; + case RegExpParser::FLAG_UTF16: + flagStr.Update(thread->GlobalConstants()->GetHandledUnicodeString()); + break; + case RegExpParser::FLAG_STICKY: + flagStr.Update(thread->GlobalConstants()->GetHandledStickyString()); + break; + case RegExpParser::FLAG_MULTILINE: + flagStr.Update(thread->GlobalConstants()->GetHandledMultilineString()); + break; + case RegExpParser::FLAG_IGNORECASE: + flagStr.Update(thread->GlobalConstants()->GetHandledIgnoreCaseString()); + break; + case RegExpParser::FLAG_HASINDICES: + flagStr.Update(thread->GlobalConstants()->GetHandledHasIndicesString()); + break; + case RegExpParser::FLAG_DOTALL: + UNREACHABLE(); + default: + break; + } + JSTaggedValue globalValue = + ObjectFastOperator::FastGetPropertyByValue(thread, regexp.GetTaggedValue(), flagStr.GetTaggedValue()); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); + return globalValue.ToBoolean(); + } +} + +bool BuiltinsRegExp::GetOringinalFlag(JSThread *thread, const JSHandle regexp, uint32_t flag) +{ + return GetFlag(thread, regexp, flag, true); +} + +void BuiltinsRegExp::SetLastIndex(JSThread *thread, const JSHandle regexp, + JSTaggedValue lastIndex, bool isFastPath) +{ + if (isFastPath) { + JSHandle::Cast(regexp)->SetPropertyInlinedPropsWithRep(thread, LAST_INDEX_OFFSET, lastIndex); + return; + } + ObjectFastOperator::FastSetPropertyByValue(thread, regexp.GetTaggedValue(), + thread->GlobalConstants()->GetHandledLastIndexString().GetTaggedValue(), lastIndex); +} + +int64_t BuiltinsRegExp::GetLastIndex(JSThread *thread, const JSHandle regexp, bool isFastPath) +{ + if (isFastPath) { + return JSHandle::Cast(regexp)->GetPropertyInlinedProps(LAST_INDEX_OFFSET).GetInt(); + } + JSHandle lastIndexHandle(thread, ObjectFastOperator::FastGetPropertyByValue( + thread, regexp.GetTaggedValue(), thread->GlobalConstants()->GetHandledLastIndexString().GetTaggedValue())); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); + JSTaggedNumber thisIndex = JSTaggedValue::ToLength(thread, lastIndexHandle); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); + return thisIndex.GetNumber(); +} + +JSTaggedValue BuiltinsRegExp::GetExecResultIndex(JSThread *thread, const JSHandle &execResults, + bool isFastPath) +{ + if (isFastPath) { + return JSHandle::Cast(execResults)->GetPropertyInlinedProps(EXEC_RESULT_INDEX_OFFSET); + } + JSHandle resultIndex = thread->GlobalConstants()->GetHandledIndexString(); + JSTaggedValue index = ObjectFastOperator::FastGetPropertyByValue( + thread, execResults.GetTaggedValue(), resultIndex.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return index; +} + +JSTaggedValue BuiltinsRegExp::GetExecResultGroups(JSThread *thread, const JSHandle &execResults, + bool isFastPath) +{ + if (isFastPath) { + return JSHandle::Cast(execResults)->GetPropertyInlinedProps(EXEC_RESULT_GROUPS_OFFSET); + } + JSHandle groupKey = thread->GlobalConstants()->GetHandledGroupsString(); + JSTaggedValue groups = ObjectFastOperator::FastGetPropertyByValue( + thread, execResults.GetTaggedValue(), groupKey.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return groups; +} } // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_regexp.h b/ecmascript/builtins/builtins_regexp.h index 099145bd09988b96e1b477eb12bef173221d1800..c847318701453e40f6ad4f7b05ee7247ac07da04 100644 --- a/ecmascript/builtins/builtins_regexp.h +++ b/ecmascript/builtins/builtins_regexp.h @@ -69,7 +69,8 @@ public: static JSTaggedValue FlagsBitsToString(JSThread *thread, uint8_t flags); // 21.2.5.2.1 Runtime Semantics: RegExpExec ( R, S ) static JSTaggedValue RegExpExec(JSThread *thread, const JSHandle ®exp, - const JSHandle &inputString, bool useCache); + const JSHandle &inputString, bool useCache, + bool isIntermediateResult = false); // 21.2.5.2.3 AdvanceStringIndex ( S, index, unicode ) static int64_t AdvanceStringIndex(const JSHandle &inputStr, int64_t index, bool unicode); @@ -81,7 +82,27 @@ public: JSHandle string, JSHandle inputReplaceValue); static JSTaggedValue GetAllFlagsInternal(JSThread *thread, JSHandle &thisObj); - static JSTaggedValue IsValidRegularExpression(JSThread *thread, JSHandle &thisObj); + static bool IsFastRegExp(JSThread *thread, JSHandle regexp); + static bool GetFlag(JSThread *thread, const JSHandle regexp, uint32_t flag, bool isFastPath); + static void SetLastIndex(JSThread *thread, const JSHandle regexp, + JSTaggedValue lastIndex, bool isFastPath); + static int64_t GetLastIndex(JSThread *thread, const JSHandle regexp, bool isFastPath); + static JSTaggedValue RegExpBuiltinExecWithoutResult(JSThread *thread, const JSHandle regexp, + const JSHandle inputStr, + bool isFastPath, uint32_t lastIndex, bool useCache); + // 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S ) + static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle regexp, + const JSHandle inputStr, + bool isFastPath, bool useCache, bool isIntermediateResult = false); + static JSTaggedValue RegExpSearchFast(JSThread *thread, const JSHandle regexp, + const JSHandle string); + static JSTaggedValue RegExpSplit(JSThread *thread, const JSHandle regexp, + JSHandle jsString, JSHandle limit, + bool isFastPath); + static JSTaggedValue GetExecResultIndex(JSThread *thread, const JSHandle &execResults, + bool isFastPath); + static JSTaggedValue GetExecResultGroups(JSThread *thread, const JSHandle &execResults, + bool isFastPath); // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define SET_GET_CAPTURE(index) \ static JSTaggedValue GetCapture##index(JSThread *thread, const JSHandle &obj); \ @@ -104,17 +125,15 @@ private: static constexpr uint32_t MAX_SPLIT_LIMIT = 0xFFFFFFFFu; static constexpr uint32_t REGEXP_GLOBAL_ARRAY_SIZE = 9; static constexpr uint32_t LAST_INDEX_OFFSET = 0; - static constexpr uint32_t MAX_REGEXP_STRING_COUNT = 1U << 16; + static constexpr uint32_t EXEC_RESULT_INDEX_OFFSET = 1; + static constexpr uint32_t EXEC_RESULT_INPUT_OFFSET = 2; + static constexpr uint32_t EXEC_RESULT_GROUPS_OFFSET = 3; - static bool Matcher(JSThread *thread, const JSHandle ®exp, + static bool Matcher(JSThread *thread, const JSHandle regexp, const uint8_t *buffer, size_t length, int32_t lastindex, bool isUtf16); static JSTaggedValue GetFlagsInternal(JSThread *thread, const JSHandle &obj, const JSHandle &constructor, const uint8_t mask); - // 21.2.5.2.2 Runtime Semantics: RegExpBuiltinExec ( R, S ) - static JSTaggedValue RegExpBuiltinExec(JSThread *thread, const JSHandle ®exp, - const JSHandle &inputStr, bool useCache); - // 21.2.3.2.1 Runtime Semantics: RegExpAlloc ( newTarget ) static JSTaggedValue RegExpAlloc(JSThread *thread, const JSHandle &newTarget); @@ -126,21 +145,21 @@ private: // 21.2.3.2.4 Runtime Semantics: EscapeRegExpPattern ( P, F ) static EcmaString *EscapeRegExpPattern(JSThread *thread, const JSHandle &src, const JSHandle &flags); - static JSTaggedValue RegExpReplaceFast(JSThread *thread, JSHandle ®exp, + static JSTaggedValue RegExpReplaceFast(JSThread *thread, JSHandle regexp, JSHandle inputString, uint32_t inputLength); - static JSTaggedValue RegExpTestFast(JSThread *thread, JSHandle ®exp, - const JSHandle &inputString, bool useCache); - static JSTaggedValue RegExpExecForTestFast(JSThread *thread, JSHandle ®exp, - const JSHandle &inputStr, bool useCache); - static bool IsFastRegExp(JSThread *thread, JSHandle ®exp); + static JSTaggedValue RegExpTestFast(JSThread *thread, JSHandle regexp, + const JSHandle inputString, bool useCache); + static JSTaggedValue RegExpExecForTestFast(JSThread *thread, JSHandle regexp, + const JSHandle inputStr, bool useCache); // 22.2.7.8 MakeMatchIndicesIndexPairArray ( S, indices, groupNames, hasGroups ) static JSHandle MakeMatchIndicesIndexPairArray(JSThread* thread, const std::vector>& indices, const std::vector>& groupNames, bool hasGroups); - static bool RegExpExecInternal(JSThread *thread, const JSHandle ®exp, - JSHandle &inputString, int32_t lastIndex); - static JSTaggedValue RegExpSplitFast(JSThread *thread, const JSHandle ®exp, - JSHandle string, uint32_t limit, bool useCache); + static bool RegExpExecInternal(JSThread *thread, const JSHandle regexp, + JSHandle inputString, int32_t lastIndex); + static JSTaggedValue RegExpSplitFast(JSThread *thread, const JSHandle regexp, + JSHandle string, uint32_t limit, bool useCache); + static bool GetOringinalFlag(JSThread *thread, const JSHandle regexp, uint32_t flag); }; class RegExpExecResultCache : public TaggedArray { @@ -151,7 +170,8 @@ public: MATCH_TYPE, EXEC_TYPE, INTERMEDIATE_REPLACE_TYPE, - TEST_TYPE + TEST_TYPE, + SEARCH_TYPE, }; static RegExpExecResultCache *Cast(TaggedObject *object) { @@ -159,15 +179,14 @@ public: } static JSTaggedValue CreateCacheTable(JSThread *thread); // extend as an additional parameter to judge cached - JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle &patten, - const JSHandle &flags, const JSHandle &input, - CacheType type, const JSHandle ®exp, + JSTaggedValue FindCachedResult(JSThread *thread, const JSHandle input, + CacheType type, const JSHandle regexp, JSTaggedValue lastIndexInput, JSTaggedValue extend = JSTaggedValue::Undefined(), bool isIntermediateResult = false); // extend as an additional parameter to judge cached static void AddResultInCache(JSThread *thread, JSHandle cache, - const JSHandle &patten, const JSHandle &flags, - const JSHandle &input, const JSHandle &resultArray, + const JSHandle regexp, + const JSHandle input, const JSHandle resultArray, CacheType type, uint32_t lastIndexInput, uint32_t lastIndex, JSTaggedValue extend = JSTaggedValue::Undefined(), bool isIntermediateResult = false); @@ -269,9 +288,10 @@ private: static constexpr int RESULT_EXEC_INDEX = 8; static constexpr int RESULT_INTERMEDIATE_REPLACE_INDEX = 9; static constexpr int RESULT_TEST_INDEX = 10; + static constexpr int RESULT_SEARCH_INDEX = 11; // Extend index used for saving an additional parameter to judge cached - static constexpr int EXTEND_INDEX = 11; - static constexpr int ENTRY_SIZE = 12; + static constexpr int EXTEND_INDEX = 12; + static constexpr int ENTRY_SIZE = 13; }; class RegExpGlobalResult : public TaggedArray { diff --git a/ecmascript/builtins/builtins_sendable_arraybuffer.cpp b/ecmascript/builtins/builtins_sendable_arraybuffer.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6074ac306ca536cde9442f275991d788d3d5c909 --- /dev/null +++ b/ecmascript/builtins/builtins_sendable_arraybuffer.cpp @@ -0,0 +1,956 @@ +/* + * Copyright (c) 2021-2022 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. + */ + +#include "ecmascript/builtins/builtins_sendable_arraybuffer.h" + +#include + +#include "ecmascript/base/builtins_base.h" +#include "ecmascript/base/number_helper.h" +#include "ecmascript/builtins/builtins_bigint.h" +#include "ecmascript/ecma_macros.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/js_arraybuffer.h" +#include "ecmascript/js_object-inl.h" +#include "ecmascript/js_tagged_number.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/shared_objects/js_sendable_arraybuffer.h" +#include "ecmascript/base/typed_array_helper-inl.h" +#include "ecmascript/base/typed_array_helper.h" + +#include "securec.h" +#include "cstdio" +#include "cstring" + +namespace panda::ecmascript::builtins { +using TypedArrayHelper = base::TypedArrayHelper; +// 24.1.2.1 ArrayBuffer(length) +JSTaggedValue BuiltinsSendableArrayBuffer::ArrayBufferConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SendableArrayBuffer, Constructor); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle newTarget = GetNewTarget(argv); + // 1. If NewTarget is undefined, throw a TypeError exception. + if (newTarget->IsUndefined()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "newtarget is undefined", JSTaggedValue::Exception()); + } + JSHandle lengthHandle = GetCallArg(argv, 0); + JSTaggedNumber lenNum = JSTaggedValue::ToIndex(thread, lengthHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + uint64_t length = lenNum.GetNumber(); + return AllocateSendableArrayBuffer(thread, newTarget, length); +} + +// 24.1.3.1 ArrayBuffer.isView(arg) +JSTaggedValue BuiltinsSendableArrayBuffer::IsView(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SendableArrayBuffer, IsView); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle arg = GetCallArg(argv, 0); + // 1. If Type(arg) is not Object, return false. + if (!arg->IsECMAObject()) { + return BuiltinsSendableArrayBuffer::GetTaggedBoolean(false); + } + // 2. If arg has a [[ViewedArrayBuffer]] internal slot, return true. + if (arg->IsDataView() || arg->IsTypedArray()) { + return BuiltinsSendableArrayBuffer::GetTaggedBoolean(true); + } + // 3. Return false. + return BuiltinsSendableArrayBuffer::GetTaggedBoolean(false); +} + +// 24.1.3.3 get ArrayBuffer [ @@species ] +JSTaggedValue BuiltinsSendableArrayBuffer::Species(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SendableArrayBuffer, Species); + return GetThis(argv).GetTaggedValue(); +} + +// 24.1.4.1 get ArrayBuffer.prototype.byteLength +JSTaggedValue BuiltinsSendableArrayBuffer::GetByteLength(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SendableArrayBuffer, GetByteLength); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, throw a TypeError exception. + if (!thisHandle->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception()); + } + // 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. + if (!thisHandle->IsSendableArrayBuffer()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception()); + } + // 4. If IsDetachedBuffer(O) is true, throw a TypeError exception. + if (IsDetachedBuffer(thisHandle.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "IsDetachedBuffer", JSTaggedValue::Exception()); + } + JSHandle arrBuf(thisHandle); + // 5. Let length be the value of O’s [[ArrayBufferByteLength]] internal slot. + uint32_t length = arrBuf->GetArrayBufferByteLength(); + // 6. Return length. + return JSTaggedValue(length); +} + +// 24.1.4.3 ArrayBuffer.prototype.slice(start, end) +JSTaggedValue BuiltinsSendableArrayBuffer::Slice(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SendableArrayBuffer, Slice); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, throw a TypeError exception. + if (!thisHandle->IsHeapObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "this value is not an object", JSTaggedValue::Exception()); + } + JSHandle arrBuf(thisHandle); + // 3. If O does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. + if (!thisHandle->IsSendableArrayBuffer()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "don't have internal slot", JSTaggedValue::Exception()); + } + // 4. If IsDetachedBuffer(O) is true, throw a TypeError exception. + if (IsDetachedBuffer(thisHandle.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "this value IsDetachedBuffer", JSTaggedValue::Exception()); + } + // 5. Let len be the value of O’s [[ArrayBufferByteLength]] internal slot. + int32_t len = static_cast(arrBuf->GetArrayBufferByteLength()); + JSHandle startHandle = GetCallArg(argv, 0); + // 6. Let relativeStart be ToInteger(start). + JSTaggedNumber relativeStart = JSTaggedValue::ToInteger(thread, startHandle); + // 7. ReturnIfAbrupt(relativeStart). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + int32_t start = base::NumberHelper::DoubleInRangeInt32(relativeStart.GetNumber()); + int32_t end = 0; + int32_t first = 0; + int32_t last = 0; + // 8. If relativeStart < 0, let first be max((len + relativeStart),0); else let first be min(relativeStart, len). + if (start < 0) { + first = std::max((len + start), 0); + } else { + first = std::min(start, len); + } + // 9. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). + JSHandle endHandle = GetCallArg(argv, 1); + if (endHandle->IsUndefined()) { + end = len; + } else { + JSTaggedNumber relativeEnd = JSTaggedValue::ToInteger(thread, endHandle); + // 10. ReturnIfAbrupt(relativeEnd). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + end = base::NumberHelper::DoubleInRangeInt32(relativeEnd.GetNumber()); + } + // 11. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). + if (end < 0) { + last = std::max((len + end), 0); + } else { + last = std::min(end, len); + } + // 12. Let newLen be max(final-first,0). + uint32_t newLen = std::max((last - first), 0); + // 13. Let ctor be SpeciesConstructor(O, %ArrayBuffer%). + JSHandle defaultConstructor = env->GetSBuiltininArrayBufferFunction(); + JSHandle objHandle(thisHandle); + JSHandle constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); + // 14. ReturnIfAbrupt(ctor). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 15. Let new be Construct(ctor, «newLen»). + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, constructor, undefined, undefined, 1); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(JSTaggedValue(newLen)); + JSTaggedValue taggedNewArrBuf = JSFunction::Construct(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle newArrBuf(thread, taggedNewArrBuf); + // 16. ReturnIfAbrupt(new). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 17. If new does not have an [[ArrayBufferData]] internal slot, throw a TypeError exception. + if (!newArrBuf->IsSendableArrayBuffer()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "don't have bufferdata internal slot", JSTaggedValue::Exception()); + } + // 18. If IsDetachedBuffer(new) is true, throw a TypeError exception. + if (IsDetachedBuffer(newArrBuf.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "new arrayBuffer IsDetachedBuffer", JSTaggedValue::Exception()); + } + // 19. If SameValue(new, O) is true, throw a TypeError exception. + if (JSTaggedValue::SameValue(newArrBuf.GetTaggedValue(), thisHandle.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "value of new arraybuffer and this is same", JSTaggedValue::Exception()); + } + JSHandle newJsArrBuf(newArrBuf); + // 20. If the value of new’s [[ArrayBufferByteLength]] internal slot < newLen, throw a TypeError exception. + uint32_t newArrBufLen = newJsArrBuf->GetArrayBufferByteLength(); + if (newArrBufLen < newLen) { + THROW_TYPE_ERROR_AND_RETURN(thread, "new array buffer length smaller than newlen", JSTaggedValue::Exception()); + } + // 21. NOTE: Side-effects of the above steps may have detached O. + // 22. If IsDetachedBuffer(O) is true, throw a TypeError exception. + if (IsDetachedBuffer(thisHandle.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "this value IsDetachedBuffer", JSTaggedValue::Exception()); + } + if (newLen > 0) { + // 23. Let fromBuf be the value of O’s [[ArrayBufferData]] internal slot. + void *fromBuf = GetDataPointFromBuffer(arrBuf.GetTaggedValue()); + // 24. Let toBuf be the value of new’s [[ArrayBufferData]] internal slot. + void *toBuf = GetDataPointFromBuffer(newJsArrBuf.GetTaggedValue()); + // 25. Perform CopyDataBlockBytes(toBuf, fromBuf, first, newLen). + JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, first, newLen); + } + // Return new. + return newArrBuf.GetTaggedValue(); +} + +// 24.1.1.1 AllocateArrayBuffer(constructor, byteLength) +JSTaggedValue BuiltinsSendableArrayBuffer::AllocateSendableArrayBuffer( + JSThread *thread, const JSHandle &newTarget, uint64_t byteLength) +{ + BUILTINS_API_TRACE(thread, SendableArrayBuffer, AllocateSendableArrayBuffer); + /** + * 1. Let obj be OrdinaryCreateFromConstructor(constructor, "%ArrayBufferPrototype%", + * «[[ArrayBufferData]], [[ArrayBufferByteLength]]» ). + * */ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + JSHandle arrBufFunc = env->GetSBuiltininArrayBufferFunction(); + JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(arrBufFunc), newTarget); + ASSERT(obj.GetTaggedValue().IsInSharedHeap()); + // 2. ReturnIfAbrupt + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 4. Let block be CreateByteDataBlock(byteLength). + if (byteLength > INT_MAX) { + THROW_RANGE_ERROR_AND_RETURN(thread, "Out of range", JSTaggedValue::Exception()); + } + uint64_t totalNativeSize = static_cast(thread->GetNativeAreaAllocator()->GetArrayBufferNativeSize()); + if (UNLIKELY(totalNativeSize > MAX_NATIVE_SIZE_LIMIT)) { + THROW_RANGE_ERROR_AND_RETURN(thread, NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE, JSTaggedValue::Exception()); + } + uint32_t arrayByteLength = static_cast(byteLength); + JSHandle arrayBuffer(obj); + // 6. Set obj’s [[ArrayBufferData]] internal slot to block. + factory->NewJSSendableArrayBufferData(arrayBuffer, arrayByteLength); + // 7. Set obj’s [[ArrayBufferByteLength]] internal slot to byteLength. + arrayBuffer->SetArrayBufferByteLength(arrayByteLength); + // 8. Return obj. + return arrayBuffer.GetTaggedValue(); +} + +// 24.1.1.2 IsDetachedBuffer() +bool BuiltinsSendableArrayBuffer::IsDetachedBuffer(JSTaggedValue arrayBuffer) +{ + if (arrayBuffer.IsByteArray()) { + return false; + } + // 1. Assert: Type(arrayBuffer) is Object and it has an [[ArrayBufferData]] internal slot. + ASSERT(arrayBuffer.IsSendableArrayBuffer()); + JSSendableArrayBuffer *buffer = JSSendableArrayBuffer::Cast(arrayBuffer.GetTaggedObject()); + JSTaggedValue dataSlot = buffer->GetArrayBufferData(); + // 2. If arrayBuffer’s [[ArrayBufferData]] internal slot is null, return true. + // 3. Return false. + return dataSlot.IsNull(); +} + +// 24.1.1.4 +JSTaggedValue BuiltinsSendableArrayBuffer::CloneArrayBuffer(JSThread *thread, + const JSHandle &srcBuffer, + uint32_t srcByteOffset, + JSHandle constructor) +{ + BUILTINS_API_TRACE(thread, SendableArrayBuffer, CloneArrayBuffer); + // 1. Assert: Type(srcBuffer) is Object and it has an [[ArrayBufferData]] internal slot. + ASSERT(srcBuffer->IsSendableArrayBuffer() || srcBuffer->IsSharedArrayBuffer() || srcBuffer->IsByteArray()); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + // 2. If cloneConstructor is not present + if (constructor->IsUndefined()) { + // a. Let cloneConstructor be SpeciesConstructor(srcBuffer, %ArrayBuffer%). + JSHandle defaultConstructor = env->GetSBuiltininArrayBufferFunction(); + JSHandle objHandle(srcBuffer); + constructor = JSObject::SpeciesConstructor(thread, objHandle, defaultConstructor); + // b. ReturnIfAbrupt(cloneConstructor). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // c. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. + if (IsDetachedBuffer(srcBuffer.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception()); + } else { + ASSERT(constructor->IsConstructor()); + } + } + // 4. Let srcLength be the value of srcBuffer’s [[ArrayBufferByteLength]] internal slot. + JSHandle arrBuf(srcBuffer); + uint32_t srcLen = arrBuf->GetArrayBufferByteLength(); + // 5. Assert: srcByteOffset ≤ srcLength. + ASSERT(srcByteOffset <= srcLen); + // 6. Let cloneLength be srcLength – srcByteOffset. + int32_t cloneLen = static_cast(srcLen - srcByteOffset); + // 8. Let targetBuffer be AllocateArrayBuffer(cloneConstructor, cloneLength). + JSTaggedValue taggedBuf = AllocateSendableArrayBuffer(thread, constructor, cloneLen); + // 9. ReturnIfAbrupt(targetBuffer). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 10. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. + if (IsDetachedBuffer(srcBuffer.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Is Detached Buffer", JSTaggedValue::Exception()); + } + // 11. Let targetBlock be the value of targetBuffer’s [[ArrayBufferData]] internal slot. + JSHandle newArrBuf(thread, taggedBuf); + // Perform CopyDataBlockBytes(targetBlock, 0, srcBlock, srcByteOffset, cloneLength). + // 7. Let srcBlock be the value of srcBuffer’s [[ArrayBufferData]] internal slot. + void *fromBuf = GetDataPointFromBuffer(arrBuf.GetTaggedValue()); + void *toBuf = GetDataPointFromBuffer(taggedBuf); + if (cloneLen > 0) { + JSArrayBuffer::CopyDataPointBytes(toBuf, fromBuf, srcByteOffset, cloneLen); + } + return taggedBuf; +} + +// 24.1.1.5 +// NOLINTNEXTLINE(readability-function-size) +JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBuffer( + JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, DataViewType type, bool littleEndian) +{ + void *pointer = GetDataPointFromBuffer(arrBuf); + uint8_t *block = reinterpret_cast(pointer); + return GetValueFromBuffer(thread, byteIndex, block, type, littleEndian); +} + +JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block, + DataViewType type, bool littleEndian) +{ + switch (type) { + case DataViewType::UINT8: + case DataViewType::UINT8_CLAMPED: { + uint8_t res = block[byteIndex]; // NOLINT + return GetTaggedInt(res); + } + case DataViewType::INT8: { + uint8_t res = block[byteIndex]; // NOLINT + auto int8Res = static_cast(res); + return GetTaggedInt(int8Res); + } + case DataViewType::UINT16: + return GetValueFromBufferForInteger(block, byteIndex, littleEndian); + case DataViewType::INT16: + return GetValueFromBufferForInteger(block, byteIndex, littleEndian); + case DataViewType::UINT32: + return GetValueFromBufferForInteger(block, byteIndex, littleEndian); + case DataViewType::INT32: + return GetValueFromBufferForInteger(block, byteIndex, littleEndian); + case DataViewType::FLOAT32: + return GetValueFromBufferForFloat(block, byteIndex, littleEndian); + case DataViewType::FLOAT64: + return GetValueFromBufferForFloat(block, byteIndex, littleEndian); + case DataViewType::BIGINT64: + return GetValueFromBufferForBigInt(thread, block, byteIndex, littleEndian); + case DataViewType::BIGUINT64: + return GetValueFromBufferForBigInt(thread, block, byteIndex, littleEndian); + default: + break; + } + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); +} + +// 24.1.1.6 +JSTaggedValue BuiltinsSendableArrayBuffer::SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, + DataViewType type, const JSHandle &value, + bool littleEndian) +{ + if (UNLIKELY(IsBigIntElementType(type))) { + JSHandle arrBufHandle(thread, arrBuf); + switch (type) { + case DataViewType::BIGINT64: + SetValueInBufferForBigInt(thread, value, arrBufHandle, byteIndex, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + case DataViewType::BIGUINT64: + SetValueInBufferForBigInt(thread, value, arrBufHandle, byteIndex, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + } + return JSTaggedValue::Undefined(); + } + void *pointer = GetDataPointFromBuffer(arrBuf); + uint8_t *block = reinterpret_cast(pointer); + JSTaggedNumber numberValue = JSTaggedValue::ToNumber(thread, value.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + double val = numberValue.GetNumber(); + return SetValueInBuffer(thread, byteIndex, block, type, val, littleEndian); +} + +// es12 25.1.2.7 IsBigIntElementType ( type ) +bool BuiltinsSendableArrayBuffer::IsBigIntElementType(DataViewType type) +{ + if (type == DataViewType::BIGINT64 || type == DataViewType::BIGUINT64) { + return true; + } + return false; +} + +// es12 25.1.2.6 IsUnclampedIntegerElementType ( type ) +bool BuiltinsSendableArrayBuffer::IsUnclampedIntegerElementType(DataViewType type) +{ + switch (type) { + case DataViewType::INT8: + case DataViewType::INT16: + case DataViewType::INT32: + case DataViewType::UINT8: + case DataViewType::UINT16: + case DataViewType::UINT32: + return true; + default: + return false; + } +} + +template +void BuiltinsSendableArrayBuffer::SetTypeData(uint8_t *block, T value, uint32_t index) +{ + uint32_t sizeCount = sizeof(T); + uint8_t *res = reinterpret_cast(&value); + for (uint32_t i = 0; i < sizeCount; i++) { + *(block + index + i) = *(res + i); // NOLINT + } +} + +template +void BuiltinsSendableArrayBuffer::FastSetTypeData(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, T value) +{ + uint32_t sizeCount = sizeof(T); + if (sizeCount == 1) { + memset_s(byteBeginOffset, byteEndOffset-byteBeginOffset, value, byteEndOffset-byteBeginOffset); + } else { + uint8_t *resAddr = reinterpret_cast(&value); + for (uint8_t *addr = byteBeginOffset; addr < byteEndOffset; addr += sizeCount) { + for (uint32_t i = 0; i < sizeCount; ++i) { + *(addr + i) = *(resAddr + i); + } + } + } +} + +template +T BuiltinsSendableArrayBuffer::LittleEndianToBigEndian(T liValue) +{ + uint8_t sizeCount = sizeof(T); + T biValue; + switch (sizeCount) { + case NumberSize::UINT16: + biValue = ((liValue & 0x00FF) << BITS_EIGHT) // NOLINT + | ((liValue & 0xFF00) >> BITS_EIGHT); // NOLINT + break; + case NumberSize::UINT32: + biValue = ((liValue & 0x000000FF) << BITS_TWENTY_FOUR) // NOLINT + | ((liValue & 0x0000FF00) << BITS_EIGHT) // NOLINT + | ((liValue & 0x00FF0000) >> BITS_EIGHT) // NOLINT + | ((liValue & 0xFF000000) >> BITS_TWENTY_FOUR); // NOLINT + break; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + break; + } + return biValue; +} +template +T BuiltinsSendableArrayBuffer::LittleEndianToBigEndian64Bit(T liValue) +{ + return ((liValue & 0x00000000000000FF) << BITS_FIFTY_SIX) // NOLINT + | ((liValue & 0x000000000000FF00) << BITS_FORTY) // NOLINT + | ((liValue & 0x0000000000FF0000) << BITS_TWENTY_FOUR) // NOLINT + | ((liValue & 0x00000000FF000000) << BITS_EIGHT) // NOLINT + | ((liValue & 0x000000FF00000000) >> BITS_EIGHT) // NOLINT + | ((liValue & 0x0000FF0000000000) >> BITS_TWENTY_FOUR) // NOLINT + | ((liValue & 0x00FF000000000000) >> BITS_FORTY) // NOLINT + | ((liValue & 0xFF00000000000000) >> BITS_FIFTY_SIX); // NOLINT +} + +template +JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBufferForInteger( + uint8_t *block, uint32_t byteIndex, bool littleEndian) +{ + ASSERT_PRINT(std::is_integral_v, "T must be integral"); + ASSERT_PRINT(sizeof(T) == size, "Invalid number size"); + ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8"); + + ASSERT(size >= NumberSize::UINT16 || size <= NumberSize::FLOAT64); + T res = *reinterpret_cast(block + byteIndex); + if (!littleEndian) { + res = LittleEndianToBigEndian(res); + } + + // uint32_t maybe overflow with TaggedInt + // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon) + if constexpr (std::is_same_v) { + // NOLINTNEXTLINE(clang-diagnostic-sign-compare) + if (res > static_cast(std::numeric_limits::max())) { + return GetTaggedDouble(static_cast(res)); + } + } + return GetTaggedInt(res); +} + +template +JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBufferForFloat( + uint8_t *block, uint32_t byteIndex, bool littleEndian) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be correct type"); + ASSERT_PRINT(sizeof(T) == size, "Invalid number size"); + + UnionType unionValue = {0}; + // NOLINTNEXTLINE(readability-braces-around-statements) + if constexpr (std::is_same_v) { + unionValue.uValue = *reinterpret_cast(block + byteIndex); + uint32_t res = LittleEndianToBigEndian(unionValue.uValue); + return CommonConvert(unionValue.value, res, littleEndian); + } else if constexpr (std::is_same_v) { // NOLINTNEXTLINE(readability-braces-around-statements) + unionValue.uValue = *reinterpret_cast(block + byteIndex); + uint64_t res = LittleEndianToBigEndian64Bit(unionValue.uValue); + return CommonConvert(unionValue.value, res, littleEndian); + } + + return GetTaggedDouble(unionValue.value); +} + +template +JSTaggedValue BuiltinsSendableArrayBuffer::CommonConvert(T1 &value, T2 &res, bool littleEndian) +{ + if (std::isnan(value) && !JSTaggedValue::IsImpureNaN(value)) { + return GetTaggedDouble(value); + } + if (!littleEndian) { + T1 d = base::bit_cast(res); + if (JSTaggedValue::IsImpureNaN(d)) { + return GetTaggedDouble(base::NAN_VALUE); + } + return GetTaggedDouble(d); + } else { + if (JSTaggedValue::IsImpureNaN(value)) { + return GetTaggedDouble(base::NAN_VALUE); + } + } + return GetTaggedDouble(value); +} + + +template +JSTaggedValue BuiltinsSendableArrayBuffer::GetValueFromBufferForBigInt(JSThread *thread, uint8_t *block, + uint32_t byteIndex, bool littleEndian) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be uint64_t/int64_t"); + auto pTmp = *reinterpret_cast(block + byteIndex); + if (!littleEndian) { + pTmp = LittleEndianToBigEndian64Bit(pTmp); + } + if constexpr (std::is_same_v) { + return BigInt::Uint64ToBigInt(thread, pTmp).GetTaggedValue(); + } + return BigInt::Int64ToBigInt(thread, pTmp).GetTaggedValue(); +} + + +template +void BuiltinsSendableArrayBuffer::SetValueInBufferForByte(double val, uint8_t *block, uint32_t byteIndex) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be int8/uint8"); + T res; + if (std::isnan(val) || std::isinf(val)) { + res = 0; + SetTypeData(block, res, byteIndex); + return; + } + auto int64Val = static_cast(val); + auto *resArr = reinterpret_cast(&int64Val); + res = *resArr; + SetTypeData(block, res, byteIndex); +} + +void BuiltinsSendableArrayBuffer::SetValueInBufferForUint8Clamped(double val, uint8_t *block, uint32_t byteIndex) +{ + uint8_t res; + if (std::isnan(val) || val <= 0) { + res = 0; + } else if (val > UINT8_MAX) { + res = UINT8_MAX; + } else { + // same as ToUint8Clamp + res = std::lrint(val); + } + SetTypeData(block, res, byteIndex); +} + +template +void BuiltinsSendableArrayBuffer::SetValueInBufferForInteger( + double val, uint8_t *block, uint32_t byteIndex, bool littleEndian) +{ + ASSERT_PRINT(std::is_integral_v, "T must be integral"); + ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8"); + T res; + if (std::isnan(val) || std::isinf(val)) { + res = 0; + SetTypeData(block, res, byteIndex); + return; + } + auto int64Val = static_cast(val); + // NOLINTNEXTLINE(readability-braces-around-statements) + if constexpr (std::is_same_v) { + auto *pTmp = reinterpret_cast(&int64Val); + int16_t tmp = *pTmp; + res = static_cast(tmp); + } else { // NOLINTNEXTLINE(readability-braces-around-statements) + auto *pTmp = reinterpret_cast(&int64Val); + res = *pTmp; + } + + if (!littleEndian) { + res = LittleEndianToBigEndian(res); + } + SetTypeData(block, res, byteIndex); +} + +template +void BuiltinsSendableArrayBuffer::SetValueInBufferForFloat( + double val, uint8_t *block, uint32_t byteIndex, bool littleEndian) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be float type"); + auto data = static_cast(val); + if (std::isnan(val)) { + SetTypeData(block, data, byteIndex); + return; + } + if (!littleEndian) { + if constexpr (std::is_same_v) { + uint32_t res = base::bit_cast(data); + data = base::bit_cast(LittleEndianToBigEndian(res)); + } else if constexpr (std::is_same_v) { + uint64_t res = base::bit_cast(data); + data = base::bit_cast(LittleEndianToBigEndian64Bit(res)); + } + } + SetTypeData(block, data, byteIndex); +} + +template +void BuiltinsSendableArrayBuffer::SetValueInBufferForBigInt(JSThread *thread, + const JSHandle &val, + JSHandle &arrBuf, + uint32_t byteIndex, bool littleEndian) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be int64_t/uint64_t"); + T value = 0; + bool lossless = true; + if constexpr(std::is_same_v) { + BigInt::BigIntToUint64(thread, val, reinterpret_cast(&value), &lossless); + } else { + BigInt::BigIntToInt64(thread, val, reinterpret_cast(&value), &lossless); + } + RETURN_IF_ABRUPT_COMPLETION(thread); + if (!littleEndian) { + value = LittleEndianToBigEndian64Bit(value); + } + void *pointer = GetDataPointFromBuffer(arrBuf.GetTaggedValue()); + uint8_t *block = reinterpret_cast(pointer); + SetTypeData(block, value, byteIndex); +} + +template +void BuiltinsSendableArrayBuffer::SetValueInBufferForBigInt(JSThread *thread, + double val, uint8_t *block, + uint32_t byteIndex, bool littleEndian) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be int64_t/uint64_t"); + T value = 0; + bool lossless = true; + + JSHandle valHandle(thread, GetTaggedDouble(val)); + if constexpr(std::is_same_v) { + BigInt::BigIntToUint64(thread, valHandle, reinterpret_cast(&value), &lossless); + } else { + BigInt::BigIntToInt64(thread, valHandle, reinterpret_cast(&value), &lossless); + } + RETURN_IF_ABRUPT_COMPLETION(thread); + if (!littleEndian) { + value = LittleEndianToBigEndian64Bit(value); + } + SetTypeData(block, value, byteIndex); +} + +JSTaggedValue BuiltinsSendableArrayBuffer::FastSetValueInBuffer( + JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, DataViewType type, double val, bool littleEndian) +{ + void *pointer = GetDataPointFromBuffer(arrBuf); + uint8_t *block = reinterpret_cast(pointer); + return SetValueInBuffer(thread, byteIndex, block, type, val, littleEndian); +} + +JSTaggedValue BuiltinsSendableArrayBuffer::SetValueInBuffer(JSThread* thread, uint32_t byteIndex, uint8_t *block, + DataViewType type, double val, bool littleEndian) +{ + switch (type) { + case DataViewType::UINT8: + SetValueInBufferForByte(val, block, byteIndex); + break; + case DataViewType::UINT8_CLAMPED: + SetValueInBufferForUint8Clamped(val, block, byteIndex); + break; + case DataViewType::INT8: + SetValueInBufferForByte(val, block, byteIndex); + break; + case DataViewType::UINT16: + SetValueInBufferForInteger(val, block, byteIndex, littleEndian); + break; + case DataViewType::INT16: + SetValueInBufferForInteger(val, block, byteIndex, littleEndian); + break; + case DataViewType::UINT32: + SetValueInBufferForInteger(val, block, byteIndex, littleEndian); + break; + case DataViewType::INT32: + SetValueInBufferForInteger(val, block, byteIndex, littleEndian); + break; + case DataViewType::FLOAT32: + SetValueInBufferForFloat(val, block, byteIndex, littleEndian); + break; + case DataViewType::FLOAT64: + SetValueInBufferForFloat(val, block, byteIndex, littleEndian); + break; + case DataViewType::BIGINT64: + SetValueInBufferForBigInt(thread, val, block, byteIndex, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + case DataViewType::BIGUINT64: + SetValueInBufferForBigInt(thread, val, block, byteIndex, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + } + return JSTaggedValue::Undefined(); +} + +void *BuiltinsSendableArrayBuffer::GetDataPointFromBuffer(JSTaggedValue arrBuf, uint32_t byteOffset) +{ + if (arrBuf.IsByteArray()) { + return reinterpret_cast(ToUintPtr(ByteArray::Cast(arrBuf.GetTaggedObject())->GetData()) + byteOffset); + } + + JSSendableArrayBuffer *arrayBuffer = JSSendableArrayBuffer::Cast(arrBuf.GetTaggedObject()); + if (arrayBuffer->GetArrayBufferByteLength() == 0) { + return nullptr; + } + + JSTaggedValue data = arrayBuffer->GetArrayBufferData(); + return reinterpret_cast(ToUintPtr(JSNativePointer::Cast(data.GetTaggedObject()) + ->GetExternalPointer()) + byteOffset); +} + +JSTaggedValue BuiltinsSendableArrayBuffer::TypedArrayToList(JSThread *thread, JSHandle& items) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle bufferHandle(thread, items->GetViewedArrayBufferOrByteArray()); + uint32_t arrayLen = items->GetArrayLength(); + JSHandle newArrayHandle(thread, JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle oldElements(thread, newArrayHandle->GetElements()); + JSHandle elements = (oldElements->GetLength() < arrayLen) ? + factory->ExtendArray(oldElements, arrayLen) : oldElements; + newArrayHandle->SetElements(thread, elements); + uint32_t offset = items->GetByteOffset(); + uint32_t elementSize = TypedArrayHelper::GetElementSize(items); + DataViewType elementType = TypedArrayHelper::GetType(items); + uint32_t index = 0; + while (index < arrayLen) { + uint32_t byteIndex = index * elementSize + offset; + JSHandle result(thread, GetValueFromBuffer(thread, bufferHandle.GetTaggedValue(), + byteIndex, elementType, true)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + ElementAccessor::Set(thread, newArrayHandle, index, result, true); + index++; + } + JSHandle(newArrayHandle)->SetArrayLength(thread, arrayLen); + return newArrayHandle.GetTaggedValue(); +} + +template +void BuiltinsSendableArrayBuffer::FastSetValueInBufferForByte(uint8_t *byteBeginOffset, + uint8_t *byteEndOffset, + double val) +{ + ASSERT_PRINT(sizeof(T) == 1, "sizeof(T) must be one"); + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be int8/uint8"); + T res; + if (std::isnan(val) || std::isinf(val)) { + res = 0; + } else { + auto int64Val = static_cast(val); + auto *resArr = reinterpret_cast(&int64Val); + res = *resArr; + } + FastSetTypeData(byteBeginOffset, byteEndOffset, res); +} + +void BuiltinsSendableArrayBuffer::FastSetValueInBufferForUint8Clamped(uint8_t *byteBeginOffset, + uint8_t *byteEndOffset, + double val) +{ + uint8_t res; + if (std::isnan(val) || val <= 0) { + res = 0; + } else { + val = val >= UINT8_MAX ? UINT8_MAX : val; + constexpr double HALF = 0.5; + val = val == HALF ? 0 : std::round(val); + res = static_cast(val); + } + FastSetTypeData(byteBeginOffset, byteEndOffset, res); +} + +template +void BuiltinsSendableArrayBuffer::FastSetValueInBufferForInteger(uint8_t *byteBeginOffset, + uint8_t *byteEndOffset, + double val, bool littleEndian) +{ + ASSERT_PRINT(std::is_integral_v, "T must be integral"); + ASSERT_PRINT(sizeof(T) >= sizeof(uint16_t), "T must have a size more than uint8"); + T res; + if (std::isnan(val) || std::isinf(val)) { + res = 0; + } else { + auto int64Val = static_cast(val); + // NOLINTNEXTLINE(readability-braces-around-statements) + if constexpr (std::is_same_v) { + auto *pTmp = reinterpret_cast(&int64Val); + int16_t tmp = *pTmp; + res = static_cast(tmp); + } else { // NOLINTNEXTLINE(readability-braces-around-statements) + auto *pTmp = reinterpret_cast(&int64Val); + res = *pTmp; + } + if (!littleEndian) { + res = LittleEndianToBigEndian(res); + } + } + FastSetTypeData(byteBeginOffset, byteEndOffset, res); +} + +template +void BuiltinsSendableArrayBuffer::FastSetValueInBufferForFloat(uint8_t *byteBeginOffset, + uint8_t *byteEndOffset, + double val, bool littleEndian) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be float type"); + auto data = static_cast(val); + if (!std::isnan(val)) { + if (!littleEndian) { + if constexpr (std::is_same_v) { + uint32_t res = base::bit_cast(data); + data = base::bit_cast(LittleEndianToBigEndian(res)); + } else if constexpr (std::is_same_v) { + uint64_t res = base::bit_cast(data); + data = base::bit_cast(LittleEndianToBigEndian64Bit(res)); + } + } + } + FastSetTypeData(byteBeginOffset, byteEndOffset, data); +} + +template +void BuiltinsSendableArrayBuffer::FastSetValueInBufferForBigInt(JSThread *thread, + uint8_t *byteBeginOffset, + uint8_t *byteEndOffset, + double val, bool littleEndian) +{ + ASSERT_PRINT((std::is_same_v || std::is_same_v), "T must be int64_t/uint64_t"); + T value = 0; + bool lossless = true; + + JSHandle valHandle(thread, GetTaggedDouble(val)); + if constexpr(std::is_same_v) { + BigInt::BigIntToUint64(thread, valHandle, reinterpret_cast(&value), &lossless); + } else { + BigInt::BigIntToInt64(thread, valHandle, reinterpret_cast(&value), &lossless); + } + RETURN_IF_ABRUPT_COMPLETION(thread); + if (!littleEndian) { + value = LittleEndianToBigEndian64Bit(value); + } + FastSetTypeData(byteBeginOffset, byteEndOffset, value); +} + +JSTaggedValue BuiltinsSendableArrayBuffer::TryFastSetValueInBuffer([[maybe_unused]] JSThread *thread, + JSTaggedValue arrBuf, + uint32_t byteBeginOffset, uint32_t byteEndOffset, + DataViewType type, double val, bool littleEndian) +{ + uint8_t *beginPointer = reinterpret_cast(GetDataPointFromBuffer(arrBuf, byteBeginOffset)); + uint8_t *endPointer = reinterpret_cast(GetDataPointFromBuffer(arrBuf, byteEndOffset)); + switch (type) { + case DataViewType::UINT8: + FastSetValueInBufferForByte(beginPointer, endPointer, val); + break; + case DataViewType::UINT8_CLAMPED: + FastSetValueInBufferForUint8Clamped(beginPointer, endPointer, val); + break; + case DataViewType::INT8: + FastSetValueInBufferForByte(beginPointer, endPointer, val); + break; + case DataViewType::UINT16: + FastSetValueInBufferForInteger(beginPointer, endPointer, val, littleEndian); + break; + case DataViewType::INT16: + FastSetValueInBufferForInteger(beginPointer, endPointer, val, littleEndian); + break; + case DataViewType::UINT32: + FastSetValueInBufferForInteger(beginPointer, endPointer, val, littleEndian); + break; + case DataViewType::INT32: + FastSetValueInBufferForInteger(beginPointer, endPointer, val, littleEndian); + break; + case DataViewType::FLOAT32: + FastSetValueInBufferForFloat(beginPointer, endPointer, val, littleEndian); + break; + case DataViewType::FLOAT64: + FastSetValueInBufferForFloat(beginPointer, endPointer, val, littleEndian); + break; + case DataViewType::BIGINT64: + FastSetValueInBufferForBigInt(thread, beginPointer, endPointer, val, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + case DataViewType::BIGUINT64: + FastSetValueInBufferForBigInt(thread, beginPointer, endPointer, val, littleEndian); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + break; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + } + return JSTaggedValue::Undefined(); +} +} // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_sendable_arraybuffer.h b/ecmascript/builtins/builtins_sendable_arraybuffer.h new file mode 100644 index 0000000000000000000000000000000000000000..e06c8dd313a72ce9e64f5b3086d9ae5daba6c603 --- /dev/null +++ b/ecmascript/builtins/builtins_sendable_arraybuffer.h @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2021-2022 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. + */ + +#ifndef ECMASCRIPT_BUILTINS_BUILTINS_SENDABLE_ARRAYBUFFER_H +#define ECMASCRIPT_BUILTINS_BUILTINS_SENDABLE_ARRAYBUFFER_H + +#include "ecmascript/base/builtins_base.h" +#include "ecmascript/base/number_helper.h" +#include "ecmascript/js_dataview.h" +#include "ecmascript/js_typed_array.h" + +// List of functions in ArrayBuffer, excluding the '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsArrayBuffer::func refers to the native implementation of ArrayBuffer[name]. +// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available. +#define BUILTIN_ARRAY_BUFFER_FUNCTIONS(V) \ + /* ArrayBuffer.isView ( arg ) */ \ + V("isView", IsView, 1, ArrayBufferIsView) + +namespace panda::ecmascript::builtins { +using DataViewType = ecmascript::DataViewType; +using BuiltinFunctionEntry = base::BuiltinFunctionEntry; + +class BuiltinsSendableArrayBuffer : public base::BuiltinsBase { +public: + enum NumberSize : uint8_t { + UINT16 = 2, INT16 = 2, UINT32 = 4, INT32 = 4, FLOAT32 = 4, FLOAT64 = 8, BIGINT64 = 8, BIGUINT64 = 8 + }; + + // 24.1.2.1 ArrayBuffer(length) + static JSTaggedValue ArrayBufferConstructor(EcmaRuntimeCallInfo *argv); + // 24.1.3.1 ArrayBuffer.isView(arg) + static JSTaggedValue IsView(EcmaRuntimeCallInfo *argv); + // 24.1.3.3 get ArrayBuffer[@@species] + static JSTaggedValue Species(EcmaRuntimeCallInfo *argv); + // 24.1.4.1 get ArrayBuffer.prototype.byteLength + static JSTaggedValue GetByteLength(EcmaRuntimeCallInfo *argv); + // 24.1.4.3 ArrayBuffer.prototype.slice() + static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv); + // 24.1.1.2 IsDetachedBuffer(arrayBuffer) + static bool IsDetachedBuffer(JSTaggedValue arrayBuffer); + // 24.1.1.5 GetValueFromBuffer ( arrayBuffer, byteIndex, type, isLittleEndian ) + static JSTaggedValue GetValueFromBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, + DataViewType type, bool littleEndian); + // 24.1.1.6 SetValueInBuffer ( arrayBuffer, byteIndex, type, value, isLittleEndian ) + static JSTaggedValue SetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteIndex, + DataViewType type, const JSHandle &value, bool littleEndian); + // 24.1.1.4 CloneArrayBuffer( srcBuffer, srcByteOffset [, cloneConstructor] ) + static JSTaggedValue CloneArrayBuffer(JSThread *thread, const JSHandle &srcBuffer, + uint32_t srcByteOffset, JSHandle constructor); + // 24.1.1.1 AllocateArrayBuffer(constructor, byteLength) + static JSTaggedValue AllocateSendableArrayBuffer( + JSThread *thread, const JSHandle &newTarget, uint64_t byteLength); + // es12 25.1.2.6 IsUnclampedIntegerElementType ( type ) + static bool IsUnclampedIntegerElementType(DataViewType type); + // es12 25.1.2.7 IsBigIntElementType ( type ) + static bool IsBigIntElementType(DataViewType type); + + // Excluding the '@@' internal properties + static Span GetArrayBufferFunctions() + { + return Span(ARRAY_BUFFER_FUNCTIONS); + } + + static JSTaggedValue FastSetValueInBuffer(JSThread* thread, JSTaggedValue arrBuf, uint32_t byteIndex, + DataViewType type, double val, bool littleEndian); + static JSTaggedValue TryFastSetValueInBuffer(JSThread *thread, JSTaggedValue arrBuf, uint32_t byteBeginOffset, + uint32_t byteEndOffset, DataViewType type, + double val, bool littleEndian); + template + static void FastSetValueInBufferForByte(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, + double val); + static void FastSetValueInBufferForUint8Clamped(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, + double val); + template + static void FastSetValueInBufferForInteger(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, + double val, bool littleEndian); + template + static void FastSetValueInBufferForFloat(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, + double val, bool littleEndian); + template + static void FastSetValueInBufferForBigInt(JSThread *thread, uint8_t *byteBeginOffset, uint8_t *byteEndOffset, + double val, bool littleEndian); + static JSTaggedValue SetValueInBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block, + DataViewType type, double val, bool littleEndian); + static JSTaggedValue GetValueFromBuffer(JSThread *thread, uint32_t byteIndex, uint8_t *block, + DataViewType type, bool littleEndian); + static void *GetDataPointFromBuffer(JSTaggedValue arrBuf, uint32_t byteOffset = 0); + + static size_t GetNumPrototypeInlinedProperties() + { + // 3 : 3 more inline properties in Set.prototype + // (1) Set.prototype.slice + // (2) Set.prototype [ @@toStringTag ] + // (3) get Set.prototype.size + return 3; + } + + static Span> GetPrototypeProperties() + { + return Span>(ARRAYBUFFER_PROTOTYPE_PROPERTIES); + } + + static Span> GetFunctionProperties() + { + return Span>(ARRAYBUFFER_FUNCTION_PROPERTIES); + } + +private: +#define BUILTIN_ARRAY_BUFFER_ENTRY(name, func, length, id) \ + BuiltinFunctionEntry::Create(name, BuiltinsSendableArrayBuffer::func, length, kungfu::BuiltinsStubCSigns::id), + + static constexpr std::array ARRAY_BUFFER_FUNCTIONS = {BUILTIN_ARRAY_BUFFER_FUNCTIONS(BUILTIN_ARRAY_BUFFER_ENTRY)}; +#undef BUILTIN_ARRAY_BUFFER_ENTRY + +#define ARRAYBUFFER_PROPERTIES_PAIR(name, func, length, id) \ + std::pair(name, false), + + static constexpr std::array ARRAYBUFFER_PROTOTYPE_PROPERTIES = { + std::pair("slice", false), + std::pair("byteLength", true), + std::pair("[Symbol.toStringTag]", false), + }; + + static constexpr std::array ARRAYBUFFER_FUNCTION_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + BUILTIN_ARRAY_BUFFER_FUNCTIONS(ARRAYBUFFER_PROPERTIES_PAIR) + std::pair("[Symbol.species]", true), + }; +#undef SET_PROPERTIES_PAIR + + template + static T LittleEndianToBigEndian(T liValue); + template + static T LittleEndianToBigEndian64Bit(T liValue); + + template + static void SetTypeData(uint8_t *block, T value, uint32_t index); + + template + static void FastSetTypeData(uint8_t *byteBeginOffset, uint8_t *byteEndOffset, T value); + + template + static JSTaggedValue GetValueFromBufferForInteger(uint8_t *block, uint32_t byteIndex, bool littleEndian); + + template + static JSTaggedValue GetValueFromBufferForFloat(uint8_t *block, uint32_t byteIndex, bool littleEndian); + template + static JSTaggedValue CommonConvert(T1 &value, T2 &res, bool littleEndian); + template + static JSTaggedValue GetValueFromBufferForBigInt(JSThread *thread, uint8_t *block, + uint32_t byteIndex, bool littleEndian); + + template + static void SetValueInBufferForByte(double val, uint8_t *block, uint32_t byteIndex); + + static void SetValueInBufferForUint8Clamped(double val, uint8_t *block, uint32_t byteIndex); + + template + static void SetValueInBufferForInteger(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian); + + template + static void SetValueInBufferForFloat(double val, uint8_t *block, uint32_t byteIndex, bool littleEndian); + + template + static void SetValueInBufferForBigInt(JSThread *thread, const JSHandle &val, + JSHandle &arrBuf, uint32_t byteIndex, bool littleEndian); + + template + static void SetValueInBufferForBigInt(JSThread *thread, double val, + uint8_t *block, uint32_t byteIndex, bool littleEndian); + + static JSTaggedValue TypedArrayToList(JSThread *thread, JSHandle& items); + + static constexpr uint64_t MAX_NATIVE_SIZE_LIMIT = 4_GB; + static constexpr char const *NATIVE_SIZE_OUT_OF_LIMIT_MESSAGE = "total array buffer size out of limit(4_GB)"; + + friend class BuiltinsArray; + friend class BuiltinsSharedArray; +}; +} // namespace panda::ecmascript::builtins + +#endif // ECMASCRIPT_BUILTINS_BUILTINS_SENDABLE_ARRAYBUFFER_H diff --git a/ecmascript/builtins/builtins_shared_array.cpp b/ecmascript/builtins/builtins_shared_array.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0b14484cb4f2e67bc4ff1ffb7fb3748cdf1707a1 --- /dev/null +++ b/ecmascript/builtins/builtins_shared_array.cpp @@ -0,0 +1,2251 @@ +/* + * 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. + */ + +#include "ecmascript/builtins/builtins_shared_array.h" + +#include + +#include "ecmascript/base/array_helper.h" +#include "ecmascript/base/number_helper.h" +#include "ecmascript/base/typed_array_helper-inl.h" +#include "ecmascript/base/typed_array_helper.h" +#include "ecmascript/builtins/builtins_array.h" +#include "ecmascript/builtins/builtins_string.h" +#include "ecmascript/containers/containers_errors.h" +#include "ecmascript/ecma_macros.h" +#include "ecmascript/ecma_runtime_call_info.h" +#include "ecmascript/ecma_string.h" +#include "ecmascript/global_env.h" +#include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/js_array.h" +#include "ecmascript/js_function.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_hclass.h" +#include "ecmascript/js_map_iterator.h" +#include "ecmascript/js_object.h" +#include "ecmascript/js_stable_array.h" +#include "ecmascript/js_tagged_number.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/mem/tagged_object.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/object_fast_operator-inl.h" +#include "ecmascript/shared_objects/concurrent_api_scope.h" +#include "ecmascript/shared_objects/js_shared_array.h" +#include "ecmascript/shared_objects/js_shared_array_iterator.h" +#include "ecmascript/tagged_array-inl.h" +#include "jsnapi_expo.h" + +namespace panda::ecmascript::builtins { +namespace { + constexpr int32_t COUNT_LENGTH_AND_INIT = 2; +} // namespace +using ArrayHelper = base::ArrayHelper; +using TypedArrayHelper = base::TypedArrayHelper; +using ContainerError = containers::ContainerError; + +// 22.1.1 +JSTaggedValue BuiltinsSharedArray::ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_ENTRY_DEBUG_LOG(); + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Constructor); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let numberOfArgs be the number of arguments passed to this function call. + uint32_t argc = argv->GetArgsNumber(); + + // 3. If NewTarget is undefined, throw exception + JSHandle newTarget = GetNewTarget(argv); + if (newTarget->IsUndefined()) { + JSTaggedValue error = containers::ContainerError::BusinessError( + thread, containers::ErrorFlag::IS_NULL_ERROR, "The ArkTS Array's constructor cannot be directly invoked."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + + // 4. Let proto be GetPrototypeFromConstructor(newTarget, "%ArrayPrototype%"). + // In NewJSObjectByConstructor(), will get prototype. + // 5. ReturnIfAbrupt(proto). + + // 22.1.1.1 Array ( ) + if (argc == 0) { + // 6. Return ArrayCreate(0, proto). + return JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0), newTarget).GetTaggedValue(); + } + + // 22.1.1.3 Array(...items ) + JSTaggedValue newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(argc), newTarget).GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (!newArray.IsJSSharedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create array.", JSTaggedValue::Exception()); + } + JSHandle newArrayHandle(thread, newArray); + // 8. Let k be 0. + // 9. Let items be a zero-origined List containing the argument items in order. + // 10. Repeat, while k < numberOfArgs + // a. Let Pk be ToString(k). + // b. Let itemK be items[k]. + // c. Let defineStatus be CreateDataProperty(array, Pk, itemK). + // d. Assert: defineStatus is true. + // e. Increase k by 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle itemK(thread, JSTaggedValue::Undefined()); + for (uint32_t k = 0; k < argc; k++) { + key.Update(JSTaggedValue(k)); + itemK.Update(GetCallArg(argv, k)); + if (!itemK->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSObject::CreateDataProperty(thread, newArrayHandle, key, itemK); + } + // 11. Assert: the value of array’s length property is numberOfArgs. + // 12. Return array. + JSSharedArray::Cast(*newArrayHandle)->SetArrayLength(thread, argc); + newArrayHandle->GetJSHClass()->SetExtensible(false); + return newArrayHandle.GetTaggedValue(); +} + +// 22.1.2.1 Array.from ( items [ , mapfn [ , thisArg ] ] ) +// NOLINTNEXTLINE(readability-function-size) +JSTaggedValue BuiltinsSharedArray::From(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, From); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let C be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If mapfn is undefined, let mapping be false. + bool mapping = false; + // 3. else + // a. If IsCallable(mapfn) is false, throw a TypeError exception. + // b. If thisArg was supplied, let T be thisArg; else let T be undefined. + // c. Let mapping be true + JSHandle thisArgHandle = GetCallArg(argv, INDEX_TWO); + JSHandle mapfn = GetCallArg(argv, 1); + if (!mapfn->IsUndefined()) { + if (!mapfn->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the mapfn is not callable.", JSTaggedValue::Exception()); + } + mapping = true; + } + // 4. Let usingIterator be GetMethod(items, @@iterator). + JSHandle items = GetCallArg(argv, 0); + if (items->IsNull()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The items is null.", JSTaggedValue::Exception()); + } + if (!mapping && items->IsString()) { + JSHandle strItems(items); + return BuiltinsString::StringToSList(thread, strItems); + } + // Fast path for TypedArray + if (!mapping && items->IsTypedArray()) { + auto error = ContainerError::ParamError(thread, "Parameter error.TypedArray not support yet."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + JSHandle iteratorSymbol = env->GetIteratorSymbol(); + JSHandle usingIterator = JSObject::GetMethod(thread, items, iteratorSymbol); + // 5. ReturnIfAbrupt(usingIterator). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 6. If usingIterator is not undefined, then + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + if (!usingIterator->IsUndefined()) { + // Fast path for MapIterator + if (!mapping && items->IsJSMapIterator()) { + return JSMapIterator::MapIteratorToList(thread, items, usingIterator); + } + + // a. If IsConstructor(C) is true, then + // i. Let A be Construct(C). + // b. Else, + // i. Let A be ArrayCreate(0). + // c. ReturnIfAbrupt(A). + JSTaggedValue newArray; + if (thisHandle->IsConstructor()) { + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 0); + newArray = JSFunction::Construct(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } else { + newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + if (!newArray.IsJSSharedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception()); + } + JSHandle newArrayHandle(thread, newArray); + // d. Let iterator be GetIterator(items, usingIterator). + JSHandle iterator = JSIterator::GetIterator(thread, items, usingIterator); + // e. ReturnIfAbrupt(iterator). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // f. Let k be 0. + int k = 0; + // g. Repeat + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle mapValue(thread, JSTaggedValue::Undefined()); + while (true) { + key.Update(JSTaggedValue(k)); + // i. Let Pk be ToString(k). + // ii. Let next be IteratorStep(iterator). + JSHandle next = JSIterator::IteratorStep(thread, iterator); + // iii. ReturnIfAbrupt(next). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // iv. If next is false, then + // 1. Let setStatus be Set(A, "length", k, true). + // 2. ReturnIfAbrupt(setStatus). + // 3. Return A. + if (next->IsFalse()) { + JSSharedArray::LengthSetter(thread, newArrayHandle, key, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + newArrayHandle->GetJSHClass()->SetExtensible(false); + return newArrayHandle.GetTaggedValue(); + } + // v. Let nextValue be IteratorValue(next). + JSHandle nextValue = JSIterator::IteratorValue(thread, next); + // vi. ReturnIfAbrupt(nextValue). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // vii. If mapping is true, then + // 1. Let mappedValue be Call(mapfn, T, «nextValue, k»). + // 2. If mappedValue is an abrupt completion, return IteratorClose(iterator, mappedValue). + // 3. Let mappedValue be mappedValue.[[value]]. + // viii. Else, let mappedValue be nextValue. + if (mapping) { + const uint32_t argsLength = 2; // 2: «nextValue, k» + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(nextValue.GetTaggedValue(), key.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, + JSIterator::IteratorClose(thread, iterator, mapValue).GetTaggedValue()); + mapValue.Update(callResult); + } else { + mapValue.Update(nextValue.GetTaggedValue()); + } + if (!mapValue->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + // ix. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue). + // x. If defineStatus is an abrupt completion, return IteratorClose(iterator, defineStatus). + // xi. Increase k by 1. + JSHandle defineStatus(thread, JSTaggedValue(JSObject::CreateDataPropertyOrThrow( + thread, newArrayHandle, key, mapValue, SCheckMode::SKIP))); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, + JSIterator::IteratorClose(thread, iterator, defineStatus).GetTaggedValue()); + k++; + } + } + // 7. Assert: items is not an Iterable so assume it is an array-like object. + // 8. Let arrayLike be ToObject(items). + JSHandle arrayLikeObj = JSTaggedValue::ToObject(thread, items); + // 9. ReturnIfAbrupt(arrayLike). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle arrayLike(arrayLikeObj); + // 10. Let len be ToLength(Get(arrayLike, "length")). + int64_t len = ArrayHelper::GetArrayLength(thread, arrayLike); + // 11. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 12. If IsConstructor(C) is true, then + // a. Let A be Construct(C, «len»). + // 13. Else, + // a. Let A be ArrayCreate(len). + // 14. ReturnIfAbrupt(A). + JSTaggedValue newArray; + if (thisHandle->IsConstructor()) { + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 1); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(JSTaggedValue(len)); + newArray = JSFunction::Construct(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } else { + newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(static_cast(len))).GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + if (!newArray.IsJSSharedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception()); + } + JSHandle newArrayHandle(thread, newArray); + // 15. Let k be 0. + // 16. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kValue be Get(arrayLike, Pk). + // d. If mapping is true, then + // i. Let mappedValue be Call(mapfn, T, «kValue, k»). + // e. Else, let mappedValue be kValue. + // f. Let defineStatus be CreateDataPropertyOrThrow(A, Pk, mappedValue). + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle mapValue(thread, JSTaggedValue::Undefined()); + int64_t k = 0; + while (k < len) { + JSHandle kValue = JSSharedArray::FastGetPropertyByValue(thread, arrayLike, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (mapping) { + key.Update(JSTaggedValue(k)); + const uint32_t argsLength = 2; // 2: «kValue, k» + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + mapValue.Update(callResult); + } else { + mapValue.Update(kValue.GetTaggedValue()); + } + if (!mapValue->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapValue, SCheckMode::SKIP); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + } + // 17. Let setStatus be Set(A, "length", len, true). + JSHandle lenHandle(thread, JSTaggedValue(len)); + JSSharedArray::LengthSetter(thread, newArrayHandle, lenHandle, true); + newArrayHandle->GetJSHClass()->SetExtensible(false); + // 18. ReturnIfAbrupt(setStatus). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 19. Return A. + return newArrayHandle.GetTaggedValue(); +} + +// Array.create ( arrayLength, initialValue ) +JSTaggedValue BuiltinsSharedArray::Create(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, From); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + if (argv->GetArgsNumber() < COUNT_LENGTH_AND_INIT) { + auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameters."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisHandle = GetThis(argv); + JSHandle arrayLengthValue = GetCallArg(argv, 0); + if (!arrayLengthValue->IsInt()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + auto arrayLength = JSTaggedValue::ToUint32(thread, arrayLengthValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (JSTaggedNumber(arrayLengthValue.GetTaggedValue()).GetNumber() != arrayLength) { + auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle initValue = GetCallArg(argv, 1); + if (!initValue->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + JSTaggedValue newArray; + if (thisHandle->IsConstructor()) { + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, thisHandle, undefined, undefined, 0); + newArray = JSFunction::Construct(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } else { + newArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + if (!newArray.IsJSSharedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the array.", JSTaggedValue::Exception()); + } + JSHandle newArrayHandle(thread, newArray); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + for (uint32_t k = 0; k < arrayLength; k++) { + key.Update(JSTaggedValue(k)); + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, key, initValue, SCheckMode::SKIP); + } + key.Update(JSTaggedValue(arrayLength)); + JSSharedArray::LengthSetter(thread, newArrayHandle, key, true); + newArrayHandle->GetJSHClass()->SetExtensible(false); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // Return A. + return newArrayHandle.GetTaggedValue(); +} + +// 22.1.2.5 get Array [ @@species ] +JSTaggedValue BuiltinsSharedArray::Species(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Species); + return BuiltinsArray::Species(argv); +} + +// 22.1.3.1 Array.prototype.concat ( ...arguments ) +JSTaggedValue BuiltinsSharedArray::Concat(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Concat); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + int argc = static_cast(argv->GetArgsNumber()); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The concat method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 2. Let A be ArraySpeciesCreate(O, 0). + uint32_t arrayLen = 0; + JSTaggedValue newArray = JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (!(newArray.IsECMAObject() || newArray.IsUndefined())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "array must be object or undefined.", JSTaggedValue::Exception()); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle newArrayHandle(thread, newArray); + + // 3. Let n be 0. + int64_t n = 0; + JSMutableHandle ele(thread, JSTaggedValue::Undefined()); + JSMutableHandle fromKey(thread, JSTaggedValue::Undefined()); + JSMutableHandle toKey(thread, JSTaggedValue::Undefined()); + // 4. Prepend O to items. + // 5. For each element E of items, do + for (int i = -1; i < argc; i++) { + if (i < 0) { + ele.Update(thisObjHandle.GetTaggedValue()); + } else { + ele.Update(GetCallArg(argv, i)); + } + if (!ele->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + // a. Let spreadable be ? IsConcatSpreadable(E). + bool isSpreadable = ArrayHelper::IsConcatSpreadable(thread, ele); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // b. If spreadable is true, then + if (isSpreadable) { + // i. Let k be 0. + // ii. Let len be ? LengthOfArrayLike(E). + // iii. If n + len > 253 - 1, throw a TypeError exception. + int64_t len = ArrayHelper::GetArrayLength(thread, ele); + int64_t k = 0; + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (n + len > base::MAX_SAFE_INTEGER) { + THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); + } + + if (ele->IsStableJSArray(thread)) { + JSStableArray::Concat(thread, newArrayHandle, JSHandle::Cast(ele), k, n); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + // iv. Repeat, while k < len, + while (k < len) { + // 1. Let P be ToString(k). + // 2. Let exists be HasProperty(E, P). + // 3. If exists is true, then + fromKey.Update(JSTaggedValue::ToString(thread, JSTaggedValue(k))); + toKey.Update(JSTaggedValue(n)); + bool exists = JSTaggedValue::HasProperty(thread, ele, fromKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + // a. Let subElement be Get(E, P). + JSHandle fromValHandle = + JSSharedArray::FastGetPropertyByValue(thread, ele, fromKey); + if (!fromValHandle->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // b. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), subElement). + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toKey, fromValHandle, SCheckMode::SKIP); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + // 4. Set n to n + 1. + // 5. Set k to k + 1. + n++; + k++; + } + //c. Else + } else { + // ii. If n ≥ 253 - 1, throw a TypeError exception. + if (n >= base::MAX_SAFE_INTEGER) { + THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); + } + // iii. Perform ? CreateDataPropertyOrThrow(A, ! ToString(𝔽(n)), E). + // iv. Set n to n + 1. + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, n, ele, SCheckMode::SKIP); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + n++; + } + } + // 6. Perform ? Set(A, "length", 𝔽(n), true). + JSHandle lenHandle(thread, JSTaggedValue(n)); + JSSharedArray::LengthSetter(thread, newArrayHandle, lenHandle, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 7. Return A. + return newArrayHandle.GetTaggedValue(); +} + +// 22.1.3.4 Array.prototype.entries ( ) +JSTaggedValue BuiltinsSharedArray::Entries(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Entries); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The entries method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 1. Let O be ToObject(this value). + // 2. ReturnIfAbrupt(O). + JSHandle self = JSTaggedValue::ToObject(thread, GetThis(argv)); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 3. Return CreateArrayIterator(O, "key+value"). + JSHandle iter(factory->NewJSSharedArrayIterator(self, IterationKind::KEY_AND_VALUE)); + return iter.GetTaggedValue(); +} + +// 22.1.3.6 Array.prototype.fill (value [ , start [ , end ] ] ) +JSTaggedValue BuiltinsSharedArray::Fill(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Fill); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisObjVal = GetThis(argv); + if (!thisObjVal->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The fill method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisObjVal); + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisObjHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (thisObjVal->IsJSSharedArray()) { + bool isDictionary = thisObjHandle->GetJSHClass()->IsDictionaryElement(); + if (isDictionary) { + uint32_t length = JSSharedArray::Cast(*thisObjHandle)->GetLength(); + uint32_t size = thisObjHandle->GetNumberOfElements(); + if (length - size > JSObject::MAX_GAP) { + JSObject::TryOptimizeAsFastElements(thread, thisObjHandle); + } + } + } + + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle value = GetCallArg(argv, 0); + if (!value->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + if (thisObjVal->IsTypedArray()) { + ContentType contentType = JSHandle::Cast(thisObjVal)->GetContentType(); + if (contentType == ContentType::BigInt) { + value = JSHandle(thread, JSTaggedValue::ToBigInt(thread, value)); + } else { + value = JSHandle(thread, JSTaggedValue::ToNumber(thread, value)); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. Let relativeStart be ToInteger(start). + JSHandle startArg = GetCallArg(argv, 1); + JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, startArg); + // 6. ReturnIfAbrupt(relativeStart). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + double argStart = argStartTemp.GetNumber(); + // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len). + int64_t start = 0; + if (argStart < 0) { + double tempStart = argStart + len; + start = tempStart > 0 ? tempStart : 0; + } else { + start = argStart < len ? argStart : len; + } + + // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). + double argEnd = len; + JSHandle endArg = GetCallArg(argv, INDEX_TWO); + if (!endArg->IsUndefined()) { + JSTaggedNumber argEndTemp = JSTaggedValue::ToInteger(thread, endArg); + // 9. ReturnIfAbrupt(relativeEnd). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + argEnd = argEndTemp.GetNumber(); + } + + // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). + int64_t end = len; + if (argEnd < 0) { + double tempEnd = argEnd + len; + end = tempEnd > 0 ? tempEnd : 0; + } else { + end = argEnd < len ? argEnd : len; + } + // 11. Repeat, while k < final + // a. Let Pk be ToString(k). + // b. Let setStatus be Set(O, Pk, value, true). + // c. ReturnIfAbrupt(setStatus). + // d. Increase k by 1. + + if (thisObjVal->IsStableJSArray(thread) && !startArg->IsJSObject() && !endArg->IsJSObject()) { + auto opResult = JSStableArray::Fill(thread, thisObjHandle, value, start, end, len); + return opResult; + } + + if (thisObjVal->IsTypedArray()) { + bool result = JSTypedArray::FastTypedArrayFill(thread, thisObjVal, value, start, end); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (result) { + return thisObjHandle.GetTaggedValue(); + } + } + + int64_t k = start; + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + while (k < end) { + key.Update(JSTaggedValue(k)); + JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, key, value); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + } + + // 12. Return O. + return thisObjHandle.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedArray::FilterUnStableJSArray(JSThread *thread, JSHandle &thisArgHandle, + JSHandle &thisObjVal, int64_t k, int64_t len, uint32_t toIndex, JSHandle newArrayHandle, + JSHandle &callbackFnHandle) +{ + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + const uint32_t argsLength = 3; // 3: «kValue, k, O» + JSTaggedValue callResult = GetTaggedBoolean(true); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle toIndexHandle(thread, JSTaggedValue::Undefined()); + while (k < len) { + bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + JSHandle kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); + callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (callResult.ToBoolean()) { + toIndexHandle.Update(JSTaggedValue(toIndex)); + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, toIndexHandle, kValue, SCheckMode::SKIP); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + toIndex++; + } + } + k++; + } + return newArrayHandle.GetTaggedValue(); +} + +// 22.1.3.7 Array.prototype.filter ( callbackfn [ , thisArg ] ) +JSTaggedValue BuiltinsSharedArray::Filter(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SharedArray, Filter); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The filter method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + uint64_t len = static_cast(ArrayHelper::GetArrayLength(thread, thisObjVal)); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 7. Let A be ArraySpeciesCreate(O, 0). + int32_t arrayLen = 0; + JSTaggedValue newArray = JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(arrayLen)); + // 8. ReturnIfAbrupt(A). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle newArrayHandle(thread, newArray); + + // 9. Let k be 0. + // 10. Let to be 0. + // 11. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + // d. If kPresent is true, then + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + // iii. Let selected be ToBoolean(Call(callbackfn, T, «kValue, k, O»)). + // iv. ReturnIfAbrupt(selected). + // v. If selected is true, then + // 1. Let status be CreateDataPropertyOrThrow (A, ToString(to), kValue). + // 2. ReturnIfAbrupt(status). + // 3. Increase to by 1. + // e. Increase k by 1. + uint32_t toIndex = 0; + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle toIndexHandle(thread, JSTaggedValue::Undefined()); + uint32_t k = 0; + if (thisObjVal->IsStableJSArray(thread)) { + JSStableArray::Filter(newArrayHandle, thisObjHandle, argv, k, toIndex); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + auto opResult = + FilterUnStableJSArray(thread, thisArgHandle, thisObjVal, k, len, toIndex, newArrayHandle, callbackFnHandle); + + return opResult; +} + +// 22.1.3.8 Array.prototype.find ( predicate [ , thisArg ] ) +JSTaggedValue BuiltinsSharedArray::Find(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Find); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The find method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(predicate) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception()); + } + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 7. Let k be 0. + // 8. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kValue be Get(O, Pk). + // c. ReturnIfAbrupt(kValue). + // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)). + // e. ReturnIfAbrupt(testResult). + // f. If testResult is true, return kValue. + // g. Increase k by 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + int64_t k = 0; + while (k < len) { + JSHandle kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + const uint32_t argsLength = 3; // 3: «kValue, k, O» + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (callResult.ToBoolean()) { + return kValue.GetTaggedValue(); + } + k++; + } + + // 9. Return undefined. + return JSTaggedValue::Undefined(); +} + +// 22.1.3.9 Array.prototype.findIndex ( predicate [ , thisArg ] ) +JSTaggedValue BuiltinsSharedArray::FindIndex(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, FindIndex); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The findIndex method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + uint64_t len = static_cast(ArrayHelper::GetLength(thread, thisObjVal)); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(predicate) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the predicate is not callable.", JSTaggedValue::Exception()); + } + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 7. Let k be 0. + // 8. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kValue be Get(O, Pk). + // c. ReturnIfAbrupt(kValue). + // d. Let testResult be ToBoolean(Call(predicate, T, «kValue, k, O»)). + // e. ReturnIfAbrupt(testResult). + // f. If testResult is true, return k. + // g. Increase k by 1. + uint32_t k = 0; + JSTaggedValue callResult = GetTaggedBoolean(true); + if (thisObjVal->IsStableJSArray(thread)) { + callResult = JSStableArray::HandleFindIndexOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (callResult.ToBoolean()) { + return GetTaggedDouble(k); + } + } + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + const uint32_t argsLength = 3; // 3: «kValue, k, O» + while (k < len) { + JSHandle kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); + callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (callResult.ToBoolean()) { + return GetTaggedDouble(k); + } + k++; + } + + // 9. Return -1. + return GetTaggedDouble(-1); +} + +// 22.1.3.10 Array.prototype.forEach ( callbackfn [ , thisArg ] ) +JSTaggedValue BuiltinsSharedArray::ForEach(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SharedArray, ForEach); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The forEach method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + uint64_t len = static_cast(ArrayHelper::GetArrayLength(thread, thisObjVal)); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 7. Let k be 0. + // 8. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + // d. If kPresent is true, then + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). + // iv. ReturnIfAbrupt(funcResult). + // e. Increase k by 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + uint32_t k = 0; + if (thisObjVal->IsStableJSArray(thread)) { + JSStableArray::HandleforEachOfStable(thread, thisObjHandle, callbackFnHandle, thisArgHandle, len, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + const uint32_t argsLength = 3; // 3: «kValue, k, O» + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + while (k < len) { + bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + JSHandle kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); + JSTaggedValue funcResult = JSFunction::Call(info); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); + } + k++; + } + + // 9. Return undefined. + return JSTaggedValue::Undefined(); +} + +JSTaggedValue BuiltinsSharedArray::IndexOfStable( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle) +{ + int64_t length = JSHandle::Cast(thisHandle)->GetArrayLength(); + if (length == 0) { + return JSTaggedValue(-1); + } + int64_t fromIndex = 0; + uint32_t argc = argv->GetArgsNumber(); + // 2: [target, fromIndex]. Note that fromIndex is missing in most usage cases. + if (UNLIKELY(argc >= 2)) { + JSHandle fromIndexHandle = argv->GetCallArg(1); + fromIndex = ArrayHelper::GetStartIndex(thread, fromIndexHandle, length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // Slow path when fromIndex is obtained from an ECMAObject + // due to potential side effects in its 'toString' and 'valueOf' methods which modify the array object. + if (UNLIKELY(fromIndexHandle->IsECMAObject())) { + return IndexOfSlowPath(argv, thread, thisHandle, length, fromIndex); + } + } + if (fromIndex >= length) { + return JSTaggedValue(-1); + } + JSHandle target = GetCallArg(argv, 0); + return JSStableArray::IndexOf( + thread, thisHandle, target, static_cast(fromIndex), static_cast(length)); +} + +JSTaggedValue BuiltinsSharedArray::IndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle) +{ + // 1. Let O be ToObject(this value). + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + // 3. Let len be ToLength(Get(O, "length")). + int64_t length = ArrayHelper::GetLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 5. If len is 0, return −1. + if (length == 0) { + return JSTaggedValue(-1); + } + // 6. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0. + int64_t fromIndex = ArrayHelper::GetStartIndexFromArgs(thread, argv, 1, length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return IndexOfSlowPath(argv, thread, thisObjVal, length, fromIndex); +} + +JSTaggedValue BuiltinsSharedArray::IndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisObjVal, + int64_t length, int64_t fromIndex) +{ + if (fromIndex >= length) { + return JSTaggedValue(-1); + } + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); + JSHandle target = GetCallArg(argv, 0); + // 11. Repeat, while k < len + for (int64_t curIndex = fromIndex; curIndex < length; ++curIndex) { + keyHandle.Update(JSTaggedValue(curIndex)); + bool found = ArrayHelper::ElementIsStrictEqualTo(thread, thisObjVal, keyHandle, target); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (UNLIKELY(found)) { + return JSTaggedValue(curIndex); + } + } + // 12. Return -1. + return JSTaggedValue(-1); +} + +// 22.1.3.11 Array.prototype.indexOf ( searchElement [ , fromIndex ] ) +JSTaggedValue BuiltinsSharedArray::IndexOf(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SharedArray, IndexOf); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The indexOf method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSTaggedValue opResult; + if (thisHandle->IsStableJSArray(thread)) { + opResult = IndexOfStable(argv, thread, thisHandle); + } else { + opResult = IndexOfSlowPath(argv, thread, thisHandle); + } + + return opResult; +} + +// 22.1.3.12 Array.prototype.join (separator) +JSTaggedValue BuiltinsSharedArray::Join(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Join); + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The join method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + auto opResult = BuiltinsArray::Join(argv); + return opResult; +} + +// 22.1.3.13 Array.prototype.keys ( ) +JSTaggedValue BuiltinsSharedArray::Keys(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Keys); + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The keys method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + auto opResult = BuiltinsArray::Keys(argv); + return opResult; +} + +JSTaggedValue BuiltinsSharedArray::LastIndexOfStable( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle) +{ + int64_t length = JSHandle::Cast(thisHandle)->GetArrayLength(); + if (length == 0) { + return JSTaggedValue(-1); + } + int64_t fromIndex = length - 1; + uint32_t argc = argv->GetArgsNumber(); + // 2: [target, fromIndex]. Note that fromIndex is missing in most usage cases. + if (UNLIKELY(argc >= 2)) { + JSHandle fromIndexHandle = argv->GetCallArg(1); + fromIndex = ArrayHelper::GetLastStartIndex(thread, fromIndexHandle, length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // Slow path when fromIndex is obtained from an ECMAObject + // due to potential side effects in its 'toString' and 'valueOf' methods which modify the array object. + if (UNLIKELY(fromIndexHandle->IsECMAObject())) { + return LastIndexOfSlowPath(argv, thread, thisHandle, fromIndex); + } + } + if (fromIndex < 0) { + return JSTaggedValue(-1); + } + JSHandle target = GetCallArg(argv, 0); + return JSStableArray::LastIndexOf( + thread, thisHandle, target, static_cast(fromIndex), static_cast(length)); +} + +JSTaggedValue BuiltinsSharedArray::LastIndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle) +{ + // 1. Let O be ToObject(this value). + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + // 3. Let len be ToLength(Get(O, "length")). + int64_t length = ArrayHelper::GetLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 5. If len is 0, return −1. + if (length == 0) { + return JSTaggedValue(-1); + } + // 6. If argument fromIndex was passed let n be ToInteger(fromIndex); else let n be 0. + int64_t fromIndex = ArrayHelper::GetLastStartIndexFromArgs(thread, argv, 1, length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return LastIndexOfSlowPath(argv, thread, thisObjVal, fromIndex); +} + +JSTaggedValue BuiltinsSharedArray::LastIndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisObjVal, int64_t fromIndex) +{ + if (fromIndex < 0) { + return JSTaggedValue(-1); + } + JSMutableHandle keyHandle(thread, JSTaggedValue::Undefined()); + JSHandle target = base::BuiltinsBase::GetCallArg(argv, 0); + // 11. Repeat, while k < len + for (int64_t curIndex = fromIndex; curIndex >= 0; --curIndex) { + keyHandle.Update(JSTaggedValue(curIndex)); + bool found = ArrayHelper::ElementIsStrictEqualTo(thread, thisObjVal, keyHandle, target); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (UNLIKELY(found)) { + return JSTaggedValue(curIndex); + } + } + // 12. Return -1. + return JSTaggedValue(-1); +} + +// 22.1.3.15 Array.prototype.map ( callbackfn [ , thisArg ] ) +JSTaggedValue BuiltinsSharedArray::Map(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Map); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The map method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t rawLen = ArrayHelper::GetArrayLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 7. Let A be ArraySpeciesCreate(O, len). + JSTaggedValue newArray = + JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast(rawLen))); + // 8. ReturnIfAbrupt(A). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (!newArray.IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to create Object.", JSTaggedValue::Exception()); + } + JSHandle newArrayHandle(thread, newArray); + + // 9. Let k be 0. + // 10. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + // d. If kPresent is true, then + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + // iii. Let mappedValue be Call(callbackfn, T, «kValue, k, O»). + // iv. ReturnIfAbrupt(mappedValue). + // v. Let status be CreateDataPropertyOrThrow (A, Pk, mappedValue). + // vi. ReturnIfAbrupt(status). + // e. Increase k by 1. + uint32_t k = 0; + uint32_t len = static_cast(rawLen); + if (thisObjVal->IsStableJSArray(thread)) { + JSStableArray::Map(newArrayHandle, thisObjHandle, argv, k, len); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle mapResultHandle(thread, JSTaggedValue::Undefined()); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + const uint32_t argsLength = 3; // 3: «kValue, k, O» + while (k < len) { + bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + JSHandle kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); + JSTaggedValue mapResult = JSFunction::Call(info); + if (!mapResult.IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + mapResultHandle.Update(mapResult); + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapResultHandle, SCheckMode::SKIP); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + k++; + } + + // 11. Return A. + return newArrayHandle.GetTaggedValue(); +} + +// 22.1.3.16 Array.prototype.pop ( ) +JSTaggedValue BuiltinsSharedArray::Pop(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Pop); + + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The pop method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSTaggedValue opResult = PopInner(argv, thisHandle, thisObjHandle); + return opResult; +} + +JSTaggedValue BuiltinsSharedArray::PopInner(EcmaRuntimeCallInfo *argv, JSHandle &thisHandle, + JSHandle &thisObjHandle) +{ + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { + return JSStableArray::Pop(JSHandle::Cast(thisHandle), argv); + } + + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 5. If len is zero, + // a. Let setStatus be Set(O, "length", 0, true). + // b. ReturnIfAbrupt(setStatus). + // c. Return undefined. + if (len == 0) { + JSHandle lengthValue(thread, JSTaggedValue(0)); + JSSharedArray::LengthSetter(thread, thisObjHandle, lengthValue, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return JSTaggedValue::Undefined(); + } + + // 6. Else len > 0, + // a. Let newLen be len–1. + // b. Let indx be ToString(newLen). + // c. Let element be Get(O, indx). + // d. ReturnIfAbrupt(element). + // e. Let deleteStatus be DeletePropertyOrThrow(O, indx). + // f. ReturnIfAbrupt(deleteStatus). + // g. Let setStatus be Set(O, "length", newLen, true). + // h. ReturnIfAbrupt(setStatus). + // i. Return element. + int64_t newLen = len - 1; + JSHandle indexHandle(thread, JSTaggedValue(newLen)); + JSHandle element = + JSTaggedValue::GetProperty(thread, thisObjVal, indexHandle, SCheckMode::SKIP).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, indexHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSSharedArray::LengthSetter(thread, thisObjHandle, indexHandle, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + return element.GetTaggedValue(); +} + +// 22.1.3.17 Array.prototype.push ( ...items ) +JSTaggedValue BuiltinsSharedArray::Push(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Push); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The push method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (thisHandle->IsStableJSArray(thread)) { + auto opResult = JSStableArray::Push(JSHandle::Cast(thisHandle), argv); + return opResult; + } + // 6. Let argCount be the number of elements in items. + uint32_t argc = argv->GetArgsNumber(); + + // 1. Let O be ToObject(this value). + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 7. If len + argCount > 253-1, throw a TypeError exception. + if ((len + static_cast(argc)) > base::MAX_SAFE_INTEGER) { + THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); + } + + // 8. Repeat, while items is not empty + // a. Remove the first element from items and let E be the value of the element. + // b. Let setStatus be Set(O, ToString(len), E, true). + // c. ReturnIfAbrupt(setStatus). + // d. Let len be len+1. + uint32_t k = 0; + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + while (k < argc) { + key.Update(JSTaggedValue(len)); + JSHandle kValue = GetCallArg(argv, k); + if (!kValue->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, key, kValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + len++; + } + + // 9. Let setStatus be Set(O, "length", len, true). + key.Update(JSTaggedValue(len)); + JSSharedArray::LengthSetter(thread, thisObjHandle, key, true); + // 10. ReturnIfAbrupt(setStatus). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 11. Return len. + return GetTaggedDouble(len); +} + +JSTaggedValue BuiltinsSharedArray::ReduceUnStableJSArray(JSThread *thread, JSHandle &thisHandle, + JSHandle &thisObjVal, int64_t k, int64_t len, JSMutableHandle &accumulator, + JSHandle &callbackFnHandle) +{ + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSTaggedValue callResult = JSTaggedValue::Undefined(); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + while (k < len) { + bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + JSHandle kValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + JSHandle thisArgHandle = globalConst->GetHandledUndefined(); + const uint32_t argsLength = 4; // 4: «accumulator, kValue, k, O» + JSHandle undefined = globalConst->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(accumulator.GetTaggedValue(), kValue.GetTaggedValue(), key.GetTaggedValue(), + thisObjVal.GetTaggedValue()); + callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + accumulator.Update(callResult); + } + k++; + } + return accumulator.GetTaggedValue(); +} + +// 22.1.3.18 Array.prototype.reduce ( callbackfn [ , initialValue ] ) +JSTaggedValue BuiltinsSharedArray::Reduce(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Reduce); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + uint32_t argc = argv->GetArgsNumber(); + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The reduce method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If len is 0 and initialValue is not present, throw a TypeError exception. + if (len == 0 && argc < 2) { // 2:2 means the number of parameters + THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); + } + + // 7. Let k be 0. + // 8. If initialValue is present, then + // a. Set accumulator to initialValue. + // 9. Else initialValue is not present, + // a. Let kPresent be false. + // b. Repeat, while kPresent is false and k < len + // i. Let Pk be ToString(k). + // ii. Let kPresent be HasProperty(O, Pk). + // iii. ReturnIfAbrupt(kPresent). + // iv. If kPresent is true, then + // 1. Let accumulator be Get(O, Pk). + // 2. ReturnIfAbrupt(accumulator). + // v. Increase k by 1. + // c. If kPresent is false, throw a TypeError exception. + int64_t k = 0; + JSMutableHandle accumulator(thread, JSTaggedValue::Undefined()); + if (argc == 2) { // 2:2 means the number of parameters + accumulator.Update(GetCallArg(argv, 1).GetTaggedValue()); + } else { + bool kPresent = false; + while (!kPresent && k < len) { + kPresent = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (kPresent) { + accumulator.Update(JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k).GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + k++; + } + if (!kPresent) { + THROW_TYPE_ERROR_AND_RETURN(thread, "accumulator can't be initialized.", JSTaggedValue::Exception()); + } + } + + if (thisObjVal->IsStableJSArray(thread)) { + JSStableArray::Reduce(thread, thisObjHandle, callbackFnHandle, accumulator, k, len); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + auto opResult = ReduceUnStableJSArray(thread, thisHandle, thisObjVal, k, len, accumulator, callbackFnHandle); + return opResult; +} + +// 22.1.3.21 Array.prototype.shift ( ) +JSTaggedValue BuiltinsSharedArray::Shift(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Shift); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The shift method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (thisHandle->IsStableJSArray(thread) && JSObject::IsArrayLengthWritable(thread, thisObjHandle)) { + auto opResult = JSStableArray::Shift(JSHandle::Cast(thisHandle), argv); + return opResult; + } + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 5. If len is zero, then + // a. Let setStatus be Set(O, "length", 0, true). + // b. ReturnIfAbrupt(setStatus). + // c. Return undefined. + if (len == 0) { + JSHandle zeroLenHandle(thread, JSTaggedValue(len)); + JSSharedArray::LengthSetter(thread, thisObjHandle, zeroLenHandle, false); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return JSTaggedValue::Undefined(); + } + + // 6. Let first be Get(O, "0"). + JSHandle firstKey(thread, JSTaggedValue(0)); + JSHandle firstValue = + JSTaggedValue::GetProperty(thread, thisObjVal, firstKey, SCheckMode::SKIP).GetValue(); + // 7. ReturnIfAbrupt(first). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 8. Let k be 1. + // 9. Repeat, while k < len + // a. Let from be ToString(k). + // b. Let to be ToString(k–1). + // c. Let fromPresent be HasProperty(O, from). + // d. ReturnIfAbrupt(fromPresent). + // e. If fromPresent is true, then + // i. Let fromVal be Get(O, from). + // ii. ReturnIfAbrupt(fromVal). + // iii. Let setStatus be Set(O, to, fromVal, true). + // iv. ReturnIfAbrupt(setStatus). + // f. Else fromPresent is false, + // i. Let deleteStatus be DeletePropertyOrThrow(O, to). + // ii. ReturnIfAbrupt(deleteStatus). + // g. Increase k by 1. + JSMutableHandle toKey(thread, JSTaggedValue::Undefined()); + int64_t k = 1; + while (k < len) { + bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + JSHandle fromValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, k - 1, fromValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } else { + toKey.Update(JSTaggedValue(k - 1)); + JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + k++; + } + // 10. Let deleteStatus be DeletePropertyOrThrow(O, ToString(len–1)). + JSHandle deleteKey(thread, JSTaggedValue(len - 1)); + JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, deleteKey); + // 11. ReturnIfAbrupt(deleteStatus). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 12. Let setStatus be Set(O, "length", len–1, true). + JSHandle newLenHandle(thread, JSTaggedValue(len - 1)); + JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true); + // 13. ReturnIfAbrupt(setStatus). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 14. Return first. + return firstValue.GetTaggedValue(); +} + +// 22.1.3.22 Array.prototype.slice (start, end) +JSTaggedValue BuiltinsSharedArray::Slice(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Slice); + ASSERT(argv); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The slice method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle msg0 = GetCallArg(argv, 0); + double argStart; + if (msg0->IsInt()) { + argStart = msg0->GetInt(); + } else { + // 5. Let relativeStart be ToInteger(start). + JSTaggedNumber argStartTemp = JSTaggedValue::ToInteger(thread, msg0); + // 6. ReturnIfAbrupt(relativeStart). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + argStart = argStartTemp.GetNumber(); + } + + // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len). + int64_t k = 0; + if (argStart < 0) { + double tempStart = len + argStart; + k = tempStart > 0 ? tempStart : 0; + } else { + k = argStart < len ? argStart : len; + } + + // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). + // 9. ReturnIfAbrupt(relativeEnd). + // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). + JSHandle msg1 = GetCallArg(argv, 1); + double argEnd = len; + if (!msg1->IsUndefined()) { + if (msg1->IsInt()) { + argEnd = msg1->GetInt(); + } else { + JSTaggedNumber argEndTemp = JSTaggedValue::ToInteger(thread, msg1); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + argEnd = argEndTemp.GetNumber(); + } + } + int64_t final = 0; + if (argEnd < 0) { + double tempFinal = len + argEnd; + final = tempFinal > 0 ? tempFinal : 0; + } else { + final = argEnd < len ? argEnd : len; + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 11. Let count be max(final – k, 0). + int64_t count = final > k ? (final - k) : 0; + + if (thisHandle->IsStableJSArray(thread) && !thisObjHandle->GetJSHClass()->HasConstructor() + && JSObject::GetPrototype(thisObjHandle).IsJSArray()) { + auto opResult = JSStableArray::Slice(thread, thisObjHandle, k, count); + return opResult; + } + + // 12. Let A be ArraySpeciesCreate(O, count). + JSTaggedValue newArray = + JSSharedArray::ArraySpeciesCreate(thread, thisObjHandle, JSTaggedNumber(static_cast(count))); + // 13. ReturnIfAbrupt(A). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (count == 0) { + return newArray; + } + JSHandle newArrayHandle(thread, newArray); + + // 14. Let n be 0. + // 15. Repeat, while k < final + // a. Let Pk be ToString(k). + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + // d. If kPresent is true, then + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + // iii. Let status be CreateDataPropertyOrThrow(A, ToString(n), kValue ). + // iv. ReturnIfAbrupt(status). + // e. Increase k by 1. + // f. Increase n by 1. + int64_t n = 0; + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle nKey(thread, JSTaggedValue::Undefined()); + while (k < final) { + key.Update(JSTaggedValue(k)); + bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, key); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + nKey.Update(JSTaggedValue(n)); + JSHandle kValueHandle = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, key); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, nKey, kValueHandle, SCheckMode::SKIP); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + k++; + n++; + } + + // 16. Let setStatus be Set(A, "length", n, true). + JSHandle newLenHandle(thread, JSTaggedValue(n)); + JSSharedArray::LengthSetter(thread, newArrayHandle, newLenHandle, true); + // 17. ReturnIfAbrupt(setStatus). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 18. Return A. + return newArrayHandle.GetTaggedValue(); +} + +// 22.1.3.24 Array.prototype.sort (comparefn) +JSTaggedValue BuiltinsSharedArray::Sort(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SharedArray, Sort); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. If comparefn is not undefined and IsCallable(comparefn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); + } + + // 2. Let obj be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The sort method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // Array sort + if (thisHandle->IsStableJSArray(thread) && callbackFnHandle->IsUndefined()) { + JSStableArray::Sort(thread, thisObjHandle, callbackFnHandle); + } else { + JSSharedArray::Sort(thread, JSHandle::Cast(thisObjHandle), callbackFnHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + return thisObjHandle.GetTaggedValue(); +} + +// 22.1.3.27 Array.prototype.toString ( ) +JSTaggedValue BuiltinsSharedArray::ToString(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ToString); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle thisHandle = GetThis(argv); + if (thisHandle->IsJSSharedArray()) { + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return ToStringImpl(argv, thread, thisHandle); + } else if (thisHandle->IsSharedTypedArray()) { + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return ToStringImpl(argv, thread, thisHandle); + } else if (thisHandle->IsTypedArray()) { + return ToStringImpl(argv, thread, thisHandle); + } else { + auto error = ContainerError::BindError(thread, "The toString method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } +} + +// 22.1.3.28 Array.prototype.unshift ( ...items ) +JSTaggedValue BuiltinsSharedArray::Unshift(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Unshift); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 5. Let argCount be the number of actual arguments. + int64_t argc = argv->GetArgsNumber(); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The unshift method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + int64_t len = ArrayHelper::GetArrayLength(thread, thisObjVal); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 6. If argCount > 0, then + // a. If len+ argCount > 253-1, throw a TypeError exception. + // b. Let k be len. + // c. Repeat, while k > 0, + // i. Let from be ToString(k–1). + // ii. Let to be ToString(k+argCount –1). + // iii. Let fromPresent be HasProperty(O, from). + // iv. ReturnIfAbrupt(fromPresent). + // v. If fromPresent is true, then + // 1. Let fromValue be Get(O, from). + // 2. ReturnIfAbrupt(fromValue). + // 3. Let setStatus be Set(O, to, fromValue, true). + // 4. ReturnIfAbrupt(setStatus). + // vi. Else fromPresent is false, + // 1. Let deleteStatus be DeletePropertyOrThrow(O, to). + // 2. ReturnIfAbrupt(deleteStatus). + // vii. Decrease k by 1. + if (argc > 0) { + if (len + argc > base::MAX_SAFE_INTEGER) { + THROW_TYPE_ERROR_AND_RETURN(thread, "out of range.", JSTaggedValue::Exception()); + } + JSMutableHandle fromKey(thread, JSTaggedValue::Undefined()); + JSMutableHandle toKey(thread, JSTaggedValue::Undefined()); + int64_t k = len; + while (k > 0) { + fromKey.Update(JSTaggedValue(k - 1)); + toKey.Update(JSTaggedValue(k + argc - 1)); + bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, fromKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (exists) { + JSHandle fromValue = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, fromKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, toKey, fromValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } else { + JSTaggedValue::DeletePropertyOrThrow(thread, thisObjVal, toKey); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + k--; + } + // d. Let j be 0. + // e. Let items be a List whose elements are, in left to right order, the arguments that were passed to this + // function invocation. + // f. Repeat, while items is not empty + // i. Remove the first element from items and let E be the value of that element. + // ii. Let setStatus be Set(O, ToString(j), E, true). + // iii. ReturnIfAbrupt(setStatus). + // iv. Increase j by 1. + int64_t j = 0; + while (j < argc) { + toKey.Update(JSTaggedValue(j)); + JSHandle toValue = GetCallArg(argv, j); + if (!toValue->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSSharedArray::FastSetPropertyByValue(thread, thisObjVal, toKey, toValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + j++; + } + } + + // 7. Let setStatus be Set(O, "length", len+argCount, true). + int64_t newLen = len + argc; + JSHandle newLenHandle(thread, JSTaggedValue(newLen)); + JSSharedArray::LengthSetter(thread, thisObjHandle, newLenHandle, true); + // 8. ReturnIfAbrupt(setStatus). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 9. Return len+argCount. + return GetTaggedDouble(newLen); +} + +// 22.1.3.29 Array.prototype.values ( ) +JSTaggedValue BuiltinsSharedArray::Values(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Values); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The values method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 1. Let O be ToObject(this value). + // 2. ReturnIfAbrupt(O). + JSHandle self = JSTaggedValue::ToObject(thread, GetThis(argv)); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 3. Return CreateArrayIterator(O, "value"). + JSHandle iter(factory->NewJSSharedArrayIterator(self, IterationKind::VALUE)); + return iter.GetTaggedValue(); +} +// 22.1.3.31 Array.prototype [ @@unscopables ] +JSTaggedValue BuiltinsSharedArray::Unscopables(EcmaRuntimeCallInfo *argv) +{ + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SharedArray, Unscopables); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + + JSHandle unscopableList = factory->CreateNullJSObject(); + + JSHandle trueVal(thread, JSTaggedValue::True()); + + JSHandle atKey((factory->NewFromASCII("at"))); + JSObject::CreateDataProperty(thread, unscopableList, atKey, trueVal); + + JSHandle copyWithKey = globalConst->GetHandledCopyWithinString(); + JSObject::CreateDataProperty(thread, unscopableList, copyWithKey, trueVal); + + JSHandle entriesKey = globalConst->GetHandledEntriesString(); + JSObject::CreateDataProperty(thread, unscopableList, entriesKey, trueVal); + + JSHandle fillKey = globalConst->GetHandledFillString(); + JSObject::CreateDataProperty(thread, unscopableList, fillKey, trueVal); + + JSHandle findKey = globalConst->GetHandledFindString(); + JSObject::CreateDataProperty(thread, unscopableList, findKey, trueVal); + + JSHandle findIndexKey = globalConst->GetHandledFindIndexString(); + JSObject::CreateDataProperty(thread, unscopableList, findIndexKey, trueVal); + + JSHandle findLastKey((factory->NewFromASCII("findLast"))); + JSObject::CreateDataProperty(thread, unscopableList, findLastKey, trueVal); + + JSHandle findLastIndexKey((factory->NewFromASCII("findLastIndex"))); + JSObject::CreateDataProperty(thread, unscopableList, findLastIndexKey, trueVal); + + JSHandle flatKey = globalConst->GetHandledFlatString(); + JSObject::CreateDataProperty(thread, unscopableList, flatKey, trueVal); + + JSHandle flatMapKey = globalConst->GetHandledFlatMapString(); + JSObject::CreateDataProperty(thread, unscopableList, flatMapKey, trueVal); + + JSHandle includesKey = globalConst->GetHandledIncludesString(); + JSObject::CreateDataProperty(thread, unscopableList, includesKey, trueVal); + + JSHandle keysKey = globalConst->GetHandledKeysString(); + JSObject::CreateDataProperty(thread, unscopableList, keysKey, trueVal); + + JSHandle valuesKey = globalConst->GetHandledValuesString(); + JSObject::CreateDataProperty(thread, unscopableList, valuesKey, trueVal); + + JSHandle toReversedKey((factory->NewFromASCII("toReversed"))); + JSObject::CreateDataProperty(thread, unscopableList, toReversedKey, trueVal); + + JSHandle toSortedKey((factory->NewFromASCII("toSorted"))); + JSObject::CreateDataProperty(thread, unscopableList, toSortedKey, trueVal); + + JSHandle toSplicedKey((factory->NewFromASCII("toSpliced"))); + JSObject::CreateDataProperty(thread, unscopableList, toSplicedKey, trueVal); + return unscopableList.GetTaggedValue(); +} + +// 23.1.3.13 Array.prototype.includes ( searchElement [ , fromIndex ] ) +JSTaggedValue BuiltinsSharedArray::Includes(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, Includes); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be ? ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The includes method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + uint32_t argc = argv->GetArgsNumber(); + JSHandle thisObjVal(thisObjHandle); + JSHandle searchElement = GetCallArg(argv, 0); + + // 2. Let len be ? LengthOfArrayLike(O). + int64_t len = ArrayHelper::GetLength(thread, thisObjVal); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 3. If len is 0, return false. + if (len == 0) { + return GetTaggedBoolean(false); + } + // 4. Let n be ? ToIntegerOrInfinity(fromIndex). + // 5. Assert: If fromIndex is undefined, then n is 0. + double fromIndex = 0; + if (argc > 1) { + JSHandle msg1 = GetCallArg(argv, 1); + JSTaggedNumber fromIndexTemp = JSTaggedValue::ToNumber(thread, msg1); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + fromIndex = base::NumberHelper::TruncateDouble(fromIndexTemp.GetNumber()); + } + + // 6. If n is +∞, return false. + // 7. Else if n is -∞, set n to 0. + if (fromIndex >= len) { + return GetTaggedBoolean(false); + } else if (fromIndex < -len) { + fromIndex = 0; + } + // 8. If n ≥ 0, then + // a. Let k be n. + // 9. Else, + // a. Let k be len + n. + // b. If k < 0, let k be 0. + int64_t from = (fromIndex >= 0) ? fromIndex : ((len + fromIndex) >= 0 ? len + fromIndex : 0); + + // 10. Repeat, while k < len, + // a. Let elementK be ? Get(O, ! ToString(!(k))). + // b. If SameValueZero(searchElement, elementK) is true, return true. + // c. Set k to k + 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle kValueHandle(thread, JSTaggedValue::Undefined()); + JSHandle fromStr; + while (from < len) { + JSHandle handledFrom(thread, JSTaggedValue(from)); + fromStr = JSTaggedValue::ToString(thread, handledFrom); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(fromStr.GetTaggedValue()); + kValueHandle.Update(JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, key).GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (JSTaggedValue::SameValueZero(searchElement.GetTaggedValue(), kValueHandle.GetTaggedValue())) { + return GetTaggedBoolean(true); + } + from++; + } + // 11. Return false. + return GetTaggedBoolean(false); +} + +// 23.1.3.1 Array.prototype.at ( index ) +JSTaggedValue BuiltinsSharedArray::At(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, At); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The at method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + [[maybe_unused]] ConcurrentApiScope scope(thread, thisHandle.GetTaggedValue().GetTaggedObject()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (thisHandle->IsStableJSArray(thread)) { + auto opResult = JSStableArray::At(JSHandle::Cast(thisHandle), argv); + return opResult; + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 2. Let len be ? LengthOfArrayLike(O). + int64_t len = ArrayHelper::GetLength(thread, thisObjVal); + // ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 3. Let index be ? ToIntegerOrInfinity(index). + JSTaggedNumber index = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); + // ReturnIfAbrupt(index). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 4. If relativeIndex ≥ 0, then + // a. Let k be relativeIndex. + // 5. Else, + // a. Let k be len + relativeIndex. + int64_t relativeIndex = index.GetNumber(); + int64_t k = 0; + if (relativeIndex >= 0) { + k = relativeIndex; + } else { + k = len + relativeIndex; + } + + // 6. If k < 0 or k ≥ len, return undefined. + if (k < 0 || k >= len) { + // Return undefined. + return JSTaggedValue::Undefined(); + } + // 7. Return ? Get(O, ! ToString(𝔽(k))). + JSHandle element = JSSharedArray::FastGetPropertyByValue(thread, thisObjVal, k); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return element.GetTaggedValue(); +} + +// Array.prototype.shrinkTo ( arrayLength ) +JSTaggedValue BuiltinsSharedArray::ShrinkTo(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ShrinkTo); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + if (argv->GetArgsNumber() != 1) { + auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameter."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The ShrinkTo method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + JSHandle newLengthValue = GetCallArg(argv, 0); + if (!newLengthValue->IsInt()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + auto newLength = JSTaggedValue::ToUint32(thread, newLengthValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (JSTaggedNumber(newLengthValue.GetTaggedValue()).GetNumber() != newLength) { + auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + int64_t len = ArrayHelper::GetLength(thread, thisHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (newLength >= len) { + return JSTaggedValue::Undefined(); + } + JSSharedArray::LengthSetter(thread, thisObjHandle, newLengthValue, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return JSTaggedValue::Undefined(); +} + +// Array.prototype.ExtendTo ( arrayLength, initialValue ) +JSTaggedValue BuiltinsSharedArray::ExtendTo(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedArray, ShrinkTo); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + if (argv->GetArgsNumber() < COUNT_LENGTH_AND_INIT) { + auto error = ContainerError::ParamError(thread, "Parameter error.Not enough parameters."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsJSSharedArray()) { + auto error = ContainerError::BindError(thread, "The ExtendTo method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + [[maybe_unused]] ConcurrentApiScope scope( + thread, thisHandle.GetTaggedValue().GetTaggedObject()); + JSHandle newLengthValue = GetCallArg(argv, 0); + if (!newLengthValue->IsInt()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + auto newLength = JSTaggedValue::ToUint32(thread, newLengthValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (JSTaggedNumber(newLengthValue.GetTaggedValue()).GetNumber() != newLength) { + auto error = ContainerError::ParamError(thread, "Parameter error.Invalid array length."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + + int64_t length = ArrayHelper::GetLength(thread, thisHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (newLength <= length) { + return JSTaggedValue::Undefined(); + } + + JSHandle initValue = GetCallArg(argv, 1); + if (!initValue->IsSharedType()) { + auto error = ContainerError::ParamError(thread, "Parameter error.Only accept sendable value."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + for (uint32_t k = length; k < newLength; k++) { + key.Update(JSTaggedValue(k)); + JSObject::CreateDataPropertyOrThrow(thread, thisObjHandle, key, initValue, SCheckMode::SKIP); + } + key.Update(JSTaggedValue(newLength)); + JSSharedArray::LengthSetter(thread, thisObjHandle, key, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return JSTaggedValue::Undefined(); +} + +JSTaggedValue BuiltinsSharedArray::ToStringImpl(EcmaRuntimeCallInfo *argv, JSThread *thread, + const JSHandle &thisHandle) +{ + auto ecmaVm = thread->GetEcmaVM(); + // 1. Let array be ToObject(this value). + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + JSHandle thisObjVal(thisObjHandle); + + // 2. Let func be Get(array, "join"). + JSHandle joinKey = thread->GlobalConstants()->GetHandledJoinString(); + JSHandle callbackFnHandle = JSTaggedValue::GetProperty(thread, thisObjVal, joinKey).GetValue(); + + // 3. ReturnIfAbrupt(func). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 4. If IsCallable(func) is false, let func be the intrinsic function %ObjProto_toString% (19.1.3.6). + if (!callbackFnHandle->IsCallable()) { + JSHandle env = ecmaVm->GetGlobalEnv(); + JSHandle objectPrototype = env->GetObjectFunctionPrototype(); + JSHandle toStringKey = thread->GlobalConstants()->GetHandledToStringString(); + callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + const uint32_t argsLength = argv->GetArgsNumber(); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(argsLength, 0, argv, 0); + auto opResult = JSFunction::Call(info); + return opResult; +} +} // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_shared_array.h b/ecmascript/builtins/builtins_shared_array.h new file mode 100644 index 0000000000000000000000000000000000000000..8902ca4b9e700eb2df196a94df9df8338ebd59d2 --- /dev/null +++ b/ecmascript/builtins/builtins_shared_array.h @@ -0,0 +1,237 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_BUILTINS_BUILTINS_SHARED_ARRAY_H +#define ECMASCRIPT_BUILTINS_BUILTINS_SHARED_ARRAY_H + +#include "ecmascript/base/builtins_base.h" + +// List of functions in Shared Array, excluding the '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsSharedArray::func refers to the native implementation of SharedArray[name]. +// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available. +#define BUILTIN_SHARED_ARRAY_FUNCTIONS(V) \ + /* SharedArray.from ( items [ , mapfn [ , thisArg ] ] ) */ \ + V("from", From, 1, INVALID) \ + V("create", Create, 2, INVALID) + // fixme(hzzhouzebin) Support later. + // /* SharedArray.IsArray ( arg ) */ \ + // V("IsArray", IsArray, 1, INVALID) \ + // /* SharedArray.of ( ...items ) */ \ + // V("of", Of, 0, INVALID) + +// List of functions in SharedArray.prototype, excluding the constructor and '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsSharedArray::func refers to the native implementation of SharedArray.prototype[name]. +#define BUILTIN_SHARED_ARRAY_PROTOTYPE_FUNCTIONS(V) \ + /* SharedArray.prototype.at ( index ) */ \ + V("at", At, 1, INVALID) \ + /* SharedArray.prototype.concat ( ...items ) */ \ + V("concat", Concat, 1, INVALID) \ + /* SharedArray.prototype.entries ( ) */ \ + V("entries", Entries, 0, INVALID) \ + /* SharedArray.prototype.fill ( value [ , start [ , end ] ] ) */ \ + V("fill", Fill, 1, INVALID) \ + /* SharedArray.prototype.filter ( callbackfn [ , thisArg ] ) */ \ + V("filter", Filter, 1, INVALID) \ + /* SharedArray.prototype.find ( predicate [ , thisArg ] ) */ \ + V("find", Find, 1, INVALID) \ + /* SharedArray.prototype.findIndex ( predicate [ , thisArg ] ) */ \ + V("findIndex", FindIndex, 1, INVALID) \ + /* SharedArray.prototype.forEach ( callbackfn [ , thisArg ] ) */ \ + V("forEach", ForEach, 1, INVALID) \ + /* SharedArray.prototype.includes ( searchElement [ , fromIndex ] ) */ \ + V("includes", Includes, 1, INVALID) \ + /* SharedArray.prototype.indexOf ( searchElement [ , fromIndex ] ) */ \ + V("indexOf", IndexOf, 1, INVALID) \ + /* SharedArray.prototype.join ( separator ) */ \ + V("join", Join, 1, INVALID) \ + /* SharedArray.prototype.keys ( ) */ \ + V("keys", Keys, 0, INVALID) \ + /* SharedArray.prototype.map ( callbackfn [ , thisArg ] ) */ \ + V("map", Map, 1, INVALID) \ + /* SharedArray.prototype.pop ( ) */ \ + V("pop", Pop, 0, INVALID) \ + /* SharedArray.prototype.push ( ...items ) */ \ + V("push", Push, 1, INVALID) \ + /* SharedArray.prototype.reduce ( callbackfn [ , initialValue ] ) */ \ + V("reduce", Reduce, 1, INVALID) \ + /* SharedArray.prototype.shift ( ) */ \ + V("shift", Shift, 0, INVALID) \ + /* SharedArray.prototype.slice ( start, end ) */ \ + V("slice", Slice, 2, INVALID) \ + /* SharedArray.prototype.sort ( comparefn ) */ \ + V("sort", Sort, 1, INVALID) \ + /* SharedArray.prototype.toString ( ) */ \ + V("toString", ToString, 0, INVALID) \ + /* SharedArray.prototype.values ( ) */ \ + /* SharedArray.prototype.unshift ( ...items ) */ \ + V("unshift", Unshift, 1, INVALID) \ + V("values", Values, 0, INVALID) \ + V("shrinkTo", ShrinkTo, 0, INVALID) \ + V("extendTo", ExtendTo, 0, INVALID) + // fixme(hzzhouzebin) Support later. + // /* SharedArray.prototype.with ( index, value ) */ \ + // V("with", With, 2, INVALID) \ + // /* SharedArray.prototype.reduceRight ( callbackfn [ , initialValue ] ) */ \ + // V("reduceRight", ReduceRight, 1, INVALID) \ + // /* SharedArray.prototype.reverse ( ) */ \ + // V("reverse", Reverse, 0, INVALID) \ + // /* SharedArray.prototype.copyWithin ( target, start [ , end ] ) */ \ + // V("copyWithin", CopyWithin, 2, INVALID) \ + // /* SharedArray.prototype.every ( callbackfn [ , thisArg ] ) */ \ + // V("every", Every, 1, INVALID) \ + // /* SharedArray.prototype.findLast ( predicate [ , thisArg ] ) */ \ + // V("findLast", FindLast, 1, INVALID) \ + // /* SharedArray.prototype.findLastIndex ( predicate [ , thisArg ] ) */ \ + // V("findLastIndex", FindLastIndex, 1, INVALID) \ + // /* SharedArray.prototype.lastIndexOf ( searchElement [ , fromIndex ] ) */ \ + // V("lastIndexOf", LastIndexOf, 1, INVALID) \ + // /* SharedArray.prototype.some ( callbackfn [ , thisArg ] ) */ \ + // V("some", Some, 1, INVALID) \ + // /* SharedArray.prototype.splice ( start, deleteCount, ...items ) */ \ + // V("splice", Splice, 2, INVALID) \ + // /* SharedArray.prototype.toLocaleString ( [ reserved1 [ , reserved2 ] ] ) */ \ + // V("toLocaleString", ToLocaleString, 0, INVALID) \ + // /* SharedArray.prototype.toReversed ( ) */ \ + // V("toReversed", ToReversed, 0, INVALID) \ + // /* SharedArray.prototype.toSorted ( comparefn ) */ \ + // V("toSorted", ToSorted, 1, INVALID) \ + // /* SharedArray.prototype.toSpliced ( start, skipCount, ...items ) */ \ + // V("toSpliced", ToSpliced, 2, INVALID) + +namespace panda::ecmascript::builtins { +class BuiltinsSharedArray : public base::BuiltinsBase { +public: + static JSTaggedValue ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue From(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Create(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Species(EcmaRuntimeCallInfo *argv); + + // prototype + static JSTaggedValue Concat(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Entries(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Fill(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Filter(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Find(EcmaRuntimeCallInfo *argv); + static JSTaggedValue FindIndex(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv); + static JSTaggedValue IndexOf(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Join(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Keys(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Map(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Pop(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Push(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Reduce(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Shift(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Sort(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ToString(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Unshift(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Values(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Unscopables(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Includes(EcmaRuntimeCallInfo *argv); + static JSTaggedValue At(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ShrinkTo(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ExtendTo(EcmaRuntimeCallInfo *argv); + + // Excluding the '@@' internal properties + static Span GetSharedArrayFunctions() + { + return Span(SENDABLE_ARRAY_FUNCTIONS); + } + + // Excluding the constructor and '@@' internal properties. + static Span GetSharedArrayPrototypeFunctions() + { + return Span(SENDABLE_ARRAY_PROTOTYPE_FUNCTIONS); + } + + static size_t GetNumPrototypeInlinedProperties() + { + // 4 : 4 More inlined entries in SharedArray.prototype for the following functions/accessors: + // (1) 'length' accessor + // (2) SharedArray.prototype.constructor, i.e. Array() + // (3) SharedArray.prototype[@@iterator]() + // (4) SharedArray.prototype[@@unscopables]() + return GetSharedArrayPrototypeFunctions().Size() + 4; + } + static JSTaggedValue ReduceUnStableJSArray(JSThread *thread, JSHandle &thisHandle, + JSHandle &thisObjVal, int64_t k, int64_t len, JSMutableHandle &accumulator, + JSHandle &callbackFnHandle); + + static JSTaggedValue FilterUnStableJSArray(JSThread *thread, JSHandle &thisArgHandle, + JSHandle &thisObjVal, int64_t k, int64_t len, uint32_t toIndex, + JSHandle newArrayHandle, JSHandle &callbackFnHandle); + + static Span> GetPrototypeProperties() + { + return Span>(ARRAY_PROTOTYPE_PROPERTIES); + } + static Span> GetFunctionProperties() + { + return Span>(ARRAY_FUNCTION_PROPERTIES); + } +private: + static JSTaggedValue PopInner(EcmaRuntimeCallInfo *argv, JSHandle &thisHandle, + JSHandle &thisObjHandle); +#define BUILTIN_SENDABLE_ARRAY_FUNCTION_ENTRY(name, method, length, id) \ + base::BuiltinFunctionEntry::Create(name, BuiltinsSharedArray::method, length, kungfu::BuiltinsStubCSigns::id), + + static constexpr std::array SENDABLE_ARRAY_FUNCTIONS = { + BUILTIN_SHARED_ARRAY_FUNCTIONS(BUILTIN_SENDABLE_ARRAY_FUNCTION_ENTRY) + }; + static constexpr std::array SENDABLE_ARRAY_PROTOTYPE_FUNCTIONS = { + BUILTIN_SHARED_ARRAY_PROTOTYPE_FUNCTIONS(BUILTIN_SENDABLE_ARRAY_FUNCTION_ENTRY) + }; +#undef BUILTIN_SENDABLE_ARRAY_FUNCTION_ENTRY + + static JSTaggedValue IndexOfStable( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle); + static JSTaggedValue IndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle); + static JSTaggedValue IndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisObjVal, + int64_t length, int64_t fromIndex); + + static JSTaggedValue LastIndexOfStable( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle); + static JSTaggedValue LastIndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisHandle); + static JSTaggedValue LastIndexOfSlowPath( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisObjVal, int64_t fromIndex); + static JSTaggedValue ToStringImpl( + EcmaRuntimeCallInfo *argv, JSThread *thread, const JSHandle &thisObjVal); +#define ARRAY_PROPERTIES_PAIR(name, func, length, id) \ + std::pair(name, false), + static constexpr std::array ARRAY_PROTOTYPE_PROPERTIES = { + std::pair("length", false), + std::pair("constructor", false), + BUILTIN_SHARED_ARRAY_PROTOTYPE_FUNCTIONS(ARRAY_PROPERTIES_PAIR) + std::pair("[Symbol.iterator]", false), + std::pair("[Symbol.unscopables]", false) + }; + static constexpr std::array ARRAY_FUNCTION_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + BUILTIN_SHARED_ARRAY_FUNCTIONS(ARRAY_PROPERTIES_PAIR) + std::pair("[Symbol.species]", true), + }; +#undef ARRAY_PROPERTIES_PAIR +}; +} // namespace panda::ecmascript::builtins + +#endif // ECMASCRIPT_BUILTINS_BUILTINS_SHARED_ARRAY_H diff --git a/ecmascript/builtins/builtins_shared_map.cpp b/ecmascript/builtins/builtins_shared_map.cpp new file mode 100644 index 0000000000000000000000000000000000000000..7a49fb712ee5bc80113e93324fa47aea4f2e2f95 --- /dev/null +++ b/ecmascript/builtins/builtins_shared_map.cpp @@ -0,0 +1,329 @@ +/* + * 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. + */ + +#include "ecmascript/builtins/builtins_shared_map.h" + +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/linked_hash_table.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/shared_objects/concurrent_api_scope.h" +#include "ecmascript/shared_objects/js_shared_map.h" +#include "ecmascript/shared_objects/js_shared_map_iterator.h" + +namespace panda::ecmascript::builtins { +JSTaggedValue BuiltinsSharedMap::Constructor(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Constructor); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 1. If NewTarget is undefined, throw exception + JSHandle newTarget = GetNewTarget(argv); + if (newTarget->IsUndefined()) { + JSTaggedValue error = containers::ContainerError::BusinessError( + thread, containers::ErrorFlag::IS_NULL_ERROR, "The ArkTS Map's constructor cannot be directly invoked."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + // 2.Let Map be OrdinaryCreateFromConstructor(NewTarget, "%MapPrototype%", «‍[[MapData]]» ). + JSHandle constructor = GetConstructor(argv); + ASSERT(constructor->IsJSSharedFunction() && constructor.GetTaggedValue().IsInSharedHeap()); + JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), newTarget); + ASSERT(obj.GetTaggedValue().IsInSharedHeap()); + // 3.returnIfAbrupt() + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle map = JSHandle::Cast(obj); + + // 4.Set map’s [[MapData]] internal slot to a new empty List. + JSHandle linkedMap = LinkedHashMap::Create(thread, + LinkedHashMap::MIN_CAPACITY, MemSpaceKind::SHARED); + map->SetLinkedMap(thread, linkedMap); + // add data into set from iterable + // 5.If iterable is not present, let iterable be undefined. + // 6.If iterable is either undefined or null, let iter be undefined. + JSHandle iterable = GetCallArg(argv, 0); + if (iterable->IsUndefined() || iterable->IsNull()) { + return map.GetTaggedValue(); + } + if (!iterable->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "iterable is not object", JSTaggedValue::Exception()); + } + // Let adder be Get(map, "set"). + JSHandle adderKey = thread->GlobalConstants()->GetHandledSetString(); + JSHandle adder = JSObject::GetProperty(thread, JSHandle(map), adderKey).GetValue(); + // ReturnIfAbrupt(adder). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, adder.GetTaggedValue()); + return AddEntriesFromIterable(thread, obj, iterable, adder, factory); +} + +JSTaggedValue BuiltinsSharedMap::Set(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Set); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The set method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle key = GetCallArg(argv, 0); + JSHandle value = GetCallArg(argv, 1); + JSHandle map(self); + JSSharedMap::Set(thread, map, key, value); + return map.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedMap::Clear(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Clear); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The clear method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle map(self); + JSSharedMap::Clear(thread, map); + return JSTaggedValue::Undefined(); +} + +JSTaggedValue BuiltinsSharedMap::Delete(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Delete); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The delete method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle map(self); + JSHandle key = GetCallArg(argv, 0); + bool flag = JSSharedMap::Delete(thread, map, key); + return GetTaggedBoolean(flag); +} + +JSTaggedValue BuiltinsSharedMap::Has(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Has); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self(GetThis(argv)); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The has method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSSharedMap *jsMap = JSSharedMap::Cast(self.GetTaggedValue().GetTaggedObject()); + JSHandle key = GetCallArg(argv, 0); + bool flag = jsMap->Has(thread, key.GetTaggedValue()); + return GetTaggedBoolean(flag); +} + +JSTaggedValue BuiltinsSharedMap::Get(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Get); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self(GetThis(argv)); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The get method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSSharedMap *jsMap = JSSharedMap::Cast(self.GetTaggedValue().GetTaggedObject()); + JSHandle key = GetCallArg(argv, 0); + JSTaggedValue value = jsMap->Get(thread, key.GetTaggedValue()); + return value; +} + +JSTaggedValue BuiltinsSharedMap::ForEach(EcmaRuntimeCallInfo *argv) +{ + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SharedMap, ForEach); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The forEach method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + [[maybe_unused]] ConcurrentApiScope scope(thread, self.GetTaggedValue().GetTaggedObject()); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); + JSHandle map(self); + JSHandle func(GetCallArg(argv, 0)); + if (!func->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not Callable", JSTaggedValue::Exception()); + } + JSHandle thisArg = GetCallArg(argv, 1); + JSMutableHandle hashMap(thread, map->GetLinkedMap()); + const uint32_t argsLength = 3; + int index = 0; + int totalElements = hashMap->NumberOfElements() + hashMap->NumberOfDeletedElements(); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + // Repeat for each e that is an element of entries, in original insertion order + while (index < totalElements) { + JSHandle key(thread, hashMap->GetKey(index++)); + if (!key->IsHole()) { + JSHandle value(thread, hashMap->GetValue(index - 1)); + EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo( + thread, func, thisArg, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(value.GetTaggedValue(), key.GetTaggedValue(), map.GetTaggedValue()); + JSTaggedValue ret = JSFunction::Call(info); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret); + } + } + + return JSTaggedValue::Undefined(); +} + +JSTaggedValue BuiltinsSharedMap::Species(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Species); + return GetThis(argv).GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedMap::GetSize(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, GetSize); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self(GetThis(argv)); + if (!self->IsJSSharedMap()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not SharedMap", JSTaggedValue::Exception()); + } + JSSharedMap *jsMap = JSSharedMap::Cast(self.GetTaggedValue().GetTaggedObject()); + uint32_t size = jsMap->GetSize(thread); + return JSTaggedValue(size); +} + +JSTaggedValue BuiltinsSharedMap::Entries(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Entries); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The entries method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle iter = JSSharedMapIterator::CreateMapIterator(thread, self, IterationKind::KEY_AND_VALUE); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return iter.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedMap::Keys(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Keys); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The keys method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle iter = JSSharedMapIterator::CreateMapIterator(thread, self, IterationKind::KEY); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return iter.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedMap::Values(EcmaRuntimeCallInfo *argv) +{ + BUILTINS_API_TRACE(argv->GetThread(), SharedMap, Values); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedMap()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The values method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle iter = JSSharedMapIterator::CreateMapIterator(thread, self, IterationKind::VALUE); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return iter.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedMap::AddEntriesFromIterable(JSThread *thread, const JSHandle &target, + const JSHandle &iterable, const JSHandle &adder, ObjectFactory *factory) +{ + BUILTINS_API_TRACE(thread, SharedMap, AddEntriesFromIterable); + // If IsCallable(adder) is false, throw a TypeError exception + if (!adder->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "adder is not callable", adder.GetTaggedValue()); + } + // Let iter be GetIterator(iterable). + JSHandle iter(JSIterator::GetIterator(thread, iterable)); + // ReturnIfAbrupt(iter). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, iter.GetTaggedValue()); + JSHandle keyIndex(thread, JSTaggedValue(0)); + JSHandle valueIndex(thread, JSTaggedValue(1)); + JSHandle next = JSIterator::IteratorStep(thread, iter); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, next.GetTaggedValue()); + while (!next->IsFalse()) { + // Let nextValue be IteratorValue(next). + JSHandle nextValue(JSIterator::IteratorValue(thread, next)); + // ReturnIfAbrupt(nextValue). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, next.GetTaggedValue()); + + // If Type(nextItem) is not Object + if (!nextValue->IsECMAObject()) { + JSHandle typeError = factory->GetJSError(ErrorType::TYPE_ERROR, "nextItem is not Object"); + JSHandle record( + factory->NewCompletionRecord(CompletionRecordType::THROW, JSHandle(typeError))); + JSTaggedValue ret = JSIterator::IteratorClose(thread, iter, record).GetTaggedValue(); + if (!thread->HasPendingException()) { + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, typeError.GetTaggedValue(), ret); + } + return ret; + } + // Let k be Get(nextItem, "0"). + JSHandle key = JSTaggedValue::GetProperty(thread, nextValue, keyIndex).GetValue(); + // If k is an abrupt completion, return IteratorClose(iter, k). + if (thread->HasPendingException()) { + return JSIterator::IteratorCloseAndReturn(thread, iter); + } + // Let v be Get(nextItem, "1"). + JSHandle value = JSTaggedValue::GetProperty(thread, nextValue, valueIndex).GetValue(); + // If v is an abrupt completion, return IteratorClose(iter, v). + if (thread->HasPendingException()) { + return JSIterator::IteratorCloseAndReturn(thread, iter); + } + const uint32_t argsLength = 2; // 2: key and value pair + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, adder, JSHandle(target), undefined, argsLength); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, next.GetTaggedValue()); + info->SetCallArg(key.GetTaggedValue(), value.GetTaggedValue()); + JSFunction::Call(info); + // If status is an abrupt completion, return IteratorClose(iter, status). + if (thread->HasPendingException()) { + return JSIterator::IteratorCloseAndReturn(thread, iter); + } + // Let next be IteratorStep(iter). + next = JSIterator::IteratorStep(thread, iter); + // ReturnIfAbrupt(next). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, next.GetTaggedValue()); + } + return target.GetTaggedValue(); +} +} // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_shared_map.h b/ecmascript/builtins/builtins_shared_map.h new file mode 100644 index 0000000000000000000000000000000000000000..96c9af28f2563fb88d8e1da6cc0d3cda58b780ea --- /dev/null +++ b/ecmascript/builtins/builtins_shared_map.h @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_BUILTINS_BUILTINS_SHAREAD_MAP_H +#define ECMASCRIPT_BUILTINS_BUILTINS_SHAREAD_MAP_H + +#include "ecmascript/base/builtins_base.h" +#include "ecmascript/ecma_runtime_call_info.h" + +// List of functions in Map.prototype, excluding the constructor and '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsMap::func refers to the native implementation of Map.prototype[name]. +// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available. +#define BUILTIN_MAP_PROTOTYPE_FUNCTIONS(V) \ + /* Map.prototype.clear ( ) */ \ + V("clear", Clear, 0, MapClear) \ + /* Map.prototype.delete ( key ) */ \ + V("delete", Delete, 1, MapDelete) \ + /* Map.prototype.entries ( ) */ \ + V("entries", Entries, 0, MapEntries) \ + /* Map.prototype.forEach ( callbackfn [ , thisArg ] ) */ \ + V("forEach", ForEach, 1, MapForEach) \ + /* Map.prototype.get ( key ) */ \ + V("get", Get, 1, INVALID) \ + /* Map.prototype.has ( key ) */ \ + V("has", Has, 1, MapHas) \ + /* Map.prototype.keys ( ) */ \ + V("keys", Keys, 0, MapKeys) \ + /* Map.prototype.set ( key, value ) */ \ + V("set", Set, 2, MapSet) \ + /* Map.prototype.values ( ) */ \ + V("values", Values, 0, MapValues) + +namespace panda::ecmascript::builtins { +class BuiltinsSharedMap : public base::BuiltinsBase { +public: + static JSTaggedValue Constructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Species(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Clear(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Delete(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Entries(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Get(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Has(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Keys(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Set(EcmaRuntimeCallInfo *argv); + static JSTaggedValue GetSize(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Values(EcmaRuntimeCallInfo *argv); + static JSTaggedValue AddEntriesFromIterable(JSThread *thread, const JSHandle &target, + const JSHandle &iterable, + const JSHandle &adder, ObjectFactory *factory); + + // Excluding the constructor and '@@' internal properties. + static Span GetMapPrototypeFunctions() + { + return Span(MAP_PROTOTYPE_FUNCTIONS); + } + + static size_t GetNumPrototypeInlinedProperties() + { + // 4 : 4 more inline properties in Map.prototype + // (1) Map.prototype.constructor + // (2) Map.prototype [ @@toStringTag ] + // (3) Map.prototype [ @@iterator ] + // (4) get Map.prototype.size + return GetMapPrototypeFunctions().Size() + 4; + } + + static Span> GetPrototypeProperties() + { + return Span>(MAP_PROTOTYPE_PROPERTIES); + } + + static Span> GetFunctionProperties() + { + return Span>(MAP_FUNCTION_PROPERTIES); + } +private: +#define BUILTIN_MAP_FUNCTION_ENTRY(name, func, length, id) \ + base::BuiltinFunctionEntry::Create(name, BuiltinsSharedMap::func, length, kungfu::BuiltinsStubCSigns::id), + + static constexpr std::array MAP_PROTOTYPE_FUNCTIONS = { + BUILTIN_MAP_PROTOTYPE_FUNCTIONS(BUILTIN_MAP_FUNCTION_ENTRY) + }; + +#undef BUILTIN_MAP_FUNCTION_ENTRY + +#define MAP_PROPERTIES_PAIR(name, func, length, id) \ + std::pair(name, false), + + static constexpr std::array MAP_PROTOTYPE_PROPERTIES = { + std::pair("constructor", false), + BUILTIN_MAP_PROTOTYPE_FUNCTIONS(MAP_PROPERTIES_PAIR) + std::pair("[Symbol.toStringTag]", false), + std::pair("size", true), + std::pair("[Symbol.iterator]", false) + }; + + static constexpr std::array MAP_FUNCTION_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + std::pair("[Symbol.species]", true), + }; +#undef MAP_PROPERTIES_PAIR +}; +} // namespace panda::ecmascript::builtins +#endif // ECMASCRIPT_BUILTINS_BUILTINS_SHAREAD_MAP_H diff --git a/ecmascript/builtins/builtins_shared_set.cpp b/ecmascript/builtins/builtins_shared_set.cpp new file mode 100755 index 0000000000000000000000000000000000000000..04541e9983b9f245c68e90bbdb561f93cf72ad9f --- /dev/null +++ b/ecmascript/builtins/builtins_shared_set.cpp @@ -0,0 +1,275 @@ +/* + * 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. + */ + +#include "ecmascript/builtins/builtins_shared_set.h" + +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/interpreter/interpreter.h" + +#include "ecmascript/linked_hash_table.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/shared_objects/concurrent_api_scope.h" +#include "ecmascript/shared_objects/js_shared_set.h" +#include "ecmascript/shared_objects/js_shared_set_iterator.h" +#include "ecmascript/tagged_array-inl.h" + +namespace panda::ecmascript::builtins { +JSTaggedValue BuiltinsSharedSet::Constructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, Constructor); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 1. If NewTarget is undefined, throw exception + JSHandle newTarget = GetNewTarget(argv); + if (newTarget->IsUndefined()) { + JSTaggedValue error = containers::ContainerError::BusinessError( + thread, containers::ErrorFlag::IS_NULL_ERROR, "The ArkTS Set's constructor cannot be directly invoked."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + // 2.Let set be OrdinaryCreateFromConstructor(NewTarget, "%SetPrototype%", «‍[[SetData]]» ). + JSHandle constructor = GetConstructor(argv); + ASSERT(constructor->IsJSSharedFunction() && constructor.GetTaggedValue().IsInSharedHeap()); + JSHandle obj = factory->NewJSObjectByConstructor(JSHandle(constructor), newTarget); + ASSERT(obj.GetTaggedValue().IsInSharedHeap()); + // 3.returnIfAbrupt() + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle set = JSHandle::Cast(obj); + // 3.ReturnIfAbrupt(set). + // 4.Set set’s [[SetData]] internal slot to a new empty List. + JSHandle linkedSet = LinkedHashSet::Create(thread, + LinkedHashSet::MIN_CAPACITY, MemSpaceKind::SHARED); + set->SetLinkedSet(thread, linkedSet); + // add data into set from iterable + // 5.If iterable is not present, let iterable be undefined. + // 6.If iterable is either undefined or null, let iter be undefined. + JSHandle iterable(GetCallArg(argv, 0)); + // 8.If iter is undefined, return set + if (iterable->IsUndefined() || iterable->IsNull()) { + return set.GetTaggedValue(); + } + // Let adder be Get(set, "add"). + JSHandle adderKey(thread->GlobalConstants()->GetHandledAddString()); + JSHandle setHandle(set); + JSHandle adder = JSObject::GetProperty(thread, setHandle, adderKey).GetValue(); + // ReturnIfAbrupt(adder). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, adder.GetTaggedValue()); + // If IsCallable(adder) is false, throw a TypeError exception + if (!adder->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "adder is not callable", adder.GetTaggedValue()); + } + // Let iter be GetIterator(iterable). + JSHandle iter(JSIterator::GetIterator(thread, iterable)); + // ReturnIfAbrupt(iter). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, iter.GetTaggedValue()); + // values in iterator_result may be a JSArray, values[0] = key values[1]=value, used valueIndex to get value from + // jsarray + JSHandle valueIndex(thread, JSTaggedValue(1)); + JSHandle next = JSIterator::IteratorStep(thread, iter); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, next.GetTaggedValue()); + while (!next->IsFalse()) { + // Let nextValue be IteratorValue(next). + JSHandle nextValue(JSIterator::IteratorValue(thread, next)); + // ReturnIfAbrupt(nextValue). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, nextValue.GetTaggedValue()); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo(thread, adder, setHandle, undefined, 1); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, nextValue.GetTaggedValue()); + info->SetCallArg(nextValue.GetTaggedValue()); + if (nextValue->IsArray(thread)) { + auto prop = JSTaggedValue::GetProperty(thread, nextValue, valueIndex).GetValue(); + info->SetCallArg(prop.GetTaggedValue()); + } + JSFunction::Call(info); + // Let status be Call(adder, set, «nextValue.[[value]]»). + if (thread->HasPendingException()) { + return JSIterator::IteratorCloseAndReturn(thread, iter); + } + // Let next be IteratorStep(iter). + next = JSIterator::IteratorStep(thread, iter); + // ReturnIfAbrupt(next). + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, next.GetTaggedValue()); + } + return set.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedSet::Add(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, Add); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedSet()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The add method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle value(GetCallArg(argv, 0)); + JSHandle set(self); + JSSharedSet::Add(thread, set, value); + return set.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedSet::Clear(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, Clear); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedSet()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The clear method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle set(self); + JSSharedSet::Clear(thread, set); + return JSTaggedValue::Undefined(); +} + +JSTaggedValue BuiltinsSharedSet::Delete(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, Delete); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedSet()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The delete method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle set(self); + JSHandle value = GetCallArg(argv, 0); + bool flag = JSSharedSet::Delete(thread, set, value); + return GetTaggedBoolean(flag); +} + +JSTaggedValue BuiltinsSharedSet::Has(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, Has); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedSet()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The has method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSSharedSet* jsSet = JSSharedSet::Cast(self.GetTaggedValue().GetTaggedObject()); + JSHandle value = GetCallArg(argv, 0); + bool flag = jsSet->Has(thread, value.GetTaggedValue()); + return GetTaggedBoolean(flag); +} + +JSTaggedValue BuiltinsSharedSet::ForEach(EcmaRuntimeCallInfo *argv) +{ + JSThread *thread = argv->GetThread(); + BUILTINS_API_TRACE(thread, SharedSet, ForEach); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedSet()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The forEach method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + [[maybe_unused]] ConcurrentApiScope scope(thread, self.GetTaggedValue().GetTaggedObject()); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); + + JSHandle set(self); + JSHandle func(GetCallArg(argv, 0)); + if (!func->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "callback is not callable", JSTaggedValue::Exception()); + } + JSHandle thisArg = GetCallArg(argv, 1); + JSMutableHandle hashSet(thread, set->GetLinkedSet()); + const uint32_t argsLength = 3; + int index = 0; + int totalElements = hashSet->NumberOfElements() + hashSet->NumberOfDeletedElements(); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + // Repeat for each e that is an element of entries, in original insertion order + while (index < totalElements) { + JSHandle key(thread, hashSet->GetKey(index++)); + if (!key->IsHole()) { + EcmaRuntimeCallInfo *info = EcmaInterpreter::NewRuntimeCallInfo( + thread, func, thisArg, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(key.GetTaggedValue(), key.GetTaggedValue(), set.GetTaggedValue()); + JSTaggedValue ret = JSFunction::Call(info); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret); + } + } + return JSTaggedValue::Undefined(); +} + +JSTaggedValue BuiltinsSharedSet::Species(EcmaRuntimeCallInfo *argv) +{ + return GetThis(argv).GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedSet::GetSize(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, GetSize); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self(GetThis(argv)); + if (!self->IsJSSharedSet()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "obj is not SharedSet", JSTaggedValue::Exception()); + } + JSSharedSet* jsSet = JSSharedSet::Cast(self.GetTaggedValue().GetTaggedObject()); + uint32_t size = jsSet->GetSize(thread); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue(0)); + return JSTaggedValue(size); +} + +JSTaggedValue BuiltinsSharedSet::Entries(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, Entries); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedSet()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The entries method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle iter = JSSharedSetIterator::CreateSetIterator(thread, self, IterationKind::KEY_AND_VALUE); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Undefined()); + return iter.GetTaggedValue(); +} + +JSTaggedValue BuiltinsSharedSet::Values(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedSet, Values); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle self = GetThis(argv); + if (!self->IsJSSharedSet()) { + auto error = containers::ContainerError::BusinessError(thread, containers::ErrorFlag::BIND_ERROR, + "The values method cannot be bound."); + THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, JSTaggedValue::Exception()); + } + JSHandle iter = JSSharedSetIterator::CreateSetIterator(thread, self, IterationKind::VALUE); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Undefined()); + return iter.GetTaggedValue(); +} +} // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_shared_set.h b/ecmascript/builtins/builtins_shared_set.h new file mode 100755 index 0000000000000000000000000000000000000000..5c8f65211f84069d1b808e5a9df2bce703035809 --- /dev/null +++ b/ecmascript/builtins/builtins_shared_set.h @@ -0,0 +1,115 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_BUILTINS_BUILTINS_SHARED_SET_H +#define ECMASCRIPT_BUILTINS_BUILTINS_SHARED_SET_H + +#include "ecmascript/base/builtins_base.h" +#include "ecmascript/ecma_runtime_call_info.h" + +// List of functions in Set, excluding the constructor and '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsSet::func refers to the native implementation of Set.prototype[name]. +// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available. +// The following functions are not listed: +// - Set.prototype.keys ( ), which is strictly equal to Set.prototype.values +#define BUILTIN_SET_PROTOTYPE_FUNCTIONS(V) \ + /* Set.prototype.add ( value ) */ \ + V("add", Add, 1, SetAdd) \ + /* Set.prototype.clear ( ) */ \ + V("clear", Clear, 0, SetClear) \ + /* Set.prototype.delete ( value ) */ \ + V("delete", Delete, 1, SetDelete) \ + /* Set.prototype.entries ( ) */ \ + V("entries", Entries, 0, SetEntries) \ + /* Set.prototype.forEach ( callbackfn [ , thisArg ] ) */ \ + V("forEach", ForEach, 1, SetForEach) \ + /* Set.prototype.has ( value ) */ \ + V("has", Has, 1, SetHas) \ + /* Set.prototype.values ( ) */ \ + V("values", Values, 0, SetValues) + +namespace panda::ecmascript::builtins { +class BuiltinsSharedSet : public base::BuiltinsBase { +public: + static JSTaggedValue Constructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Species(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Add(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Clear(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Delete(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Entries(EcmaRuntimeCallInfo *argv); + static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Has(EcmaRuntimeCallInfo *argv); + static JSTaggedValue GetSize(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Values(EcmaRuntimeCallInfo *argv); + + // Excluding the '@@' internal properties + static Span GetSetPrototypeFunctions() + { + return Span(SET_PROTOTYPE_FUNCTIONS); + } + + static size_t GetNumPrototypeInlinedProperties() + { + // 5 : 5 more inline properties in Set.prototype + // (1) Set.prototype.constructor + // (2) Set.prototype [ @@toStringTag ] + // (3) Set.prototype [ @@iterator ] + // (4) get Set.prototype.size + // (5) Set.prototype.keys, which is not included in BuiltinsSharedSet::GetSetPrototypeFunctions() + return GetSetPrototypeFunctions().Size() + 5; + } + + static Span> GetPrototypeProperties() + { + return Span>(SET_PROTOTYPE_PROPERTIES); + } + + static Span> GetFunctionProperties() + { + return Span>(SET_FUNCTION_PROPERTIES); + } +private: +#define BUILTIN_SET_FUNCTION_ENTRY(name, func, length, id) \ + base::BuiltinFunctionEntry::Create(name, BuiltinsSharedSet::func, length, kungfu::BuiltinsStubCSigns::id), + + static constexpr std::array SET_PROTOTYPE_FUNCTIONS = { + BUILTIN_SET_PROTOTYPE_FUNCTIONS(BUILTIN_SET_FUNCTION_ENTRY) + }; + +#undef BUILTIN_SET_FUNCTION_ENTRY + +#define SET_PROPERTIES_PAIR(name, func, length, id) \ + std::pair(name, false), + + static constexpr std::array SET_PROTOTYPE_PROPERTIES = { + std::pair("constructor", false), + BUILTIN_SET_PROTOTYPE_FUNCTIONS(SET_PROPERTIES_PAIR) + std::pair("keys", false), + std::pair("[Symbol.toStringTag]", false), + std::pair("size", true), + std::pair("[Symbol.iterator]", false) + }; + + static constexpr std::array SET_FUNCTION_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + std::pair("[Symbol.species]", true), + }; +#undef SET_PROPERTIES_PAIR +}; +} // namespace panda::ecmascript::builtins +#endif // ECMASCRIPT_BUILTINS_BUILTINS_SHARED_SET_H diff --git a/ecmascript/builtins/builtins_shared_typedarray.cpp b/ecmascript/builtins/builtins_shared_typedarray.cpp new file mode 100755 index 0000000000000000000000000000000000000000..e250ecc0d77d28658d2bce03d56662494ae98b28 --- /dev/null +++ b/ecmascript/builtins/builtins_shared_typedarray.cpp @@ -0,0 +1,1664 @@ +/* + * 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. + */ + +#include "ecmascript/builtins/builtins_shared_typedarray.h" + +#include +#include "ecmascript/base/typed_array_helper-inl.h" +#include "ecmascript/base/typed_array_helper.h" +#include "ecmascript/builtins/builtins_array.h" +#include "ecmascript/builtins/builtins_arraybuffer.h" +#include "ecmascript/ecma_runtime_call_info.h" +#include "ecmascript/ecma_string-inl.h" +#include "ecmascript/element_accessor-inl.h" +#include "ecmascript/global_env.h" +#include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/js_array.h" +#include "ecmascript/js_array_iterator.h" +#include "ecmascript/js_function.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_iterator.h" +#include "ecmascript/js_stable_array.h" +#include "ecmascript/js_tagged_number.h" +#include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/object_fast_operator-inl.h" +#include "ecmascript/shared_objects/js_shared_typed_array.h" + +namespace panda::ecmascript::builtins { +using TypedArrayHelper = base::TypedArrayHelper; +using BuiltinsArray = builtins::BuiltinsArray; +using BuiltinsArrayBuffer = builtins::BuiltinsArrayBuffer; + +// 22.2.1 +JSTaggedValue BuiltinsSharedTypedArray::TypedArrayBaseConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, BaseConstructor); + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "TypedArray Constructor cannot be called.", + JSTaggedValue::Exception()); +} + +JSTaggedValue BuiltinsSharedTypedArray::Int8ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Int8ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedInt8ArrayString(), DataViewType::INT8); +} + +JSTaggedValue BuiltinsSharedTypedArray::Uint8ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint8ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedUint8ArrayString(), DataViewType::UINT8); +} + +JSTaggedValue BuiltinsSharedTypedArray::Uint8ClampedArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint8ClampedArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedUint8ClampedArrayString(), DataViewType::UINT8_CLAMPED); +} + +JSTaggedValue BuiltinsSharedTypedArray::Int16ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Int16ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedInt16ArrayString(), DataViewType::INT16); +} + +JSTaggedValue BuiltinsSharedTypedArray::Uint16ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint16ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedUint16ArrayString(), DataViewType::UINT16); +} + +JSTaggedValue BuiltinsSharedTypedArray::Int32ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Int32ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedInt32ArrayString(), DataViewType::INT32); +} + +JSTaggedValue BuiltinsSharedTypedArray::Uint32ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Uint32ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedUint32ArrayString(), DataViewType::UINT32); +} + +JSTaggedValue BuiltinsSharedTypedArray::Float32ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Float32ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedFloat32ArrayString(), DataViewType::FLOAT32); +} + +JSTaggedValue BuiltinsSharedTypedArray::Float64ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Float64ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedFloat64ArrayString(), DataViewType::FLOAT64); +} + +JSTaggedValue BuiltinsSharedTypedArray::BigInt64ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, BigInt64ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedBigInt64ArrayString(), DataViewType::BIGINT64); +} + +JSTaggedValue BuiltinsSharedTypedArray::BigUint64ArrayConstructor(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, BigUint64ArrayConstructor); + JSThread *thread = argv->GetThread(); + return TypedArrayHelper::SharedTypedArrayConstructor(argv, + thread->GlobalConstants()->GetHandledSharedBigUint64ArrayString(), DataViewType::BIGUINT64); +} + +// 22.2.2.1 %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] ) +JSTaggedValue BuiltinsSharedTypedArray::From(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, From); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + // 1. Let C be the this value. + // 2. If IsConstructor(C) is false, throw a TypeError exception. + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsConstructor()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the this value is not a Constructor.", JSTaggedValue::Exception()); + } + + JSHandle thisArgHandle = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); + // 3. If mapfn is undefined, let mapping be false. + // 4. Else, + // a. If IsCallable(mapfn) is false, throw a TypeError exception. + // b. Let mapping be true. + bool mapping = false; + JSHandle mapfn = GetCallArg(argv, 1); + if (!mapfn->IsUndefined()) { + if (!mapfn->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the mapfn is not callable.", JSTaggedValue::Exception()); + } + mapping = true; + } + + // 5. Let usingIterator be ? GetMethod(source, @@iterator). + JSHandle source = GetCallArg(argv, 0); + JSHandle iteratorSymbol = env->GetIteratorSymbol(); + JSHandle usingIterator = JSObject::GetMethod(thread, source, iteratorSymbol); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle arrIter = JSObject::GetMethod(thread, env->GetArrayProtoValuesFunction(), iteratorSymbol); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle typedArrIter = JSObject::GetMethod(thread, env->GetTypedArrayPrototype(), iteratorSymbol); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + bool isArrIter = JSTaggedValue::SameValue(usingIterator, arrIter); + bool isTypedArrIter = JSTaggedValue::SameValue(usingIterator, typedArrIter); + bool isNativeFunc = true; + if (source->IsTypedArray() && !typedArrIter->IsUndefined()) { + JSHandle typedArrIterator = JSIterator::GetIterator(thread, source, typedArrIter); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle nextKey(thread->GlobalConstants()->GetHandledNextString()); + JSHandle typedArrIterNext(JSObject::GetMethod(thread, typedArrIterator, nextKey)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (typedArrIterNext->IsJSFunction()) { + JSTaggedValue method = JSHandle::Cast(typedArrIterNext)->GetMethod(); + Method *target = Method::Cast(method.GetTaggedObject()); + isNativeFunc = target->IsNativeWithCallField(); + } + } + // 6. If usingIterator is not undefined, then + // a. Let values be ? IterableToList(source, usingIterator). + // b. Let len be the number of elements in values. + // c. Let targetObj be ? TypedArrayCreate(C, « len »). + if (!usingIterator->IsUndefined() && !(isArrIter || (isTypedArrIter && isNativeFunc))) { + CVector> vec; + JSHandle iterator = JSIterator::GetIterator(thread, source, usingIterator); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle next(thread, JSTaggedValue::True()); + while (!next->IsFalse()) { + next = JSIterator::IteratorStep(thread, iterator); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (!next->IsFalse()) { + JSHandle nextValue = JSIterator::IteratorValue(thread, next); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, nextValue.GetTaggedValue()); + vec.push_back(nextValue); + } + } + uint32_t len = vec.size(); + JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() }; + JSHandle targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // d. Let k be 0. + // e. Repeat, while k < len + // i. Let Pk be ! ToString(k). + // ii. Let kValue be the first element of values and remove that element from values. + // iii. If mapping is true, then + // 1. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »). + // iv. Else, let mappedValue be kValue. + // v. Perform ? Set(targetObj, Pk, mappedValue, true). + // vi. Set k to k + 1. + JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + JSMutableHandle mapValue(thread, JSTaggedValue::Undefined()); + const uint32_t argsLength = 2; + uint32_t k = 0; + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + while (k < len) { + tKey.Update(JSTaggedValue(k)); + JSHandle kValue = vec[k]; + if (mapping) { + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + mapValue.Update(callResult); + } else { + mapValue.Update(kValue.GetTaggedValue()); + } + ObjectFastOperator::FastSetPropertyByIndex(thread, targetObj.GetTaggedValue(), k, + mapValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + } + // f. Assert: values is now an empty List. + // g. Return targetObj. + return targetObj.GetTaggedValue(); + } + + // 7. NOTE: source is not an Iterable so assume it is already an array-like object. + // 8. Let arrayLike be ! ToObject(source). + JSHandle arrayLikeObj = JSTaggedValue::ToObject(thread, source); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle arrayLike(arrayLikeObj); + // 9. Let len be ? LengthOfArrayLike(arrayLike). + JSHandle lengthKey = thread->GlobalConstants()->GetHandledLengthString(); + JSHandle lenResult = JSTaggedValue::GetProperty(thread, arrayLike, lengthKey).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSTaggedNumber tLen = JSTaggedValue::ToLength(thread, lenResult); + // 6. ReturnIfAbrupt(relativeTarget). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + int64_t len = tLen.GetNumber(); + + // 10. Let targetObj be ? TypedArrayCreate(C, « len »). + JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()}; + JSHandle targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 11. Let k be 0. + // 12. Repeat, while k < len + // a. Let Pk be ! ToString(k). + // b. Let kValue be ? Get(arrayLike, Pk). + // c. If mapping is true, then + // i. Let mappedValue be ? Call(mapfn, thisArg, « kValue, k »). + // d. Else, let mappedValue be kValue. + // e. Perform ? Set(targetObj, Pk, mappedValue, true). + // f. Set k to k + 1. + JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + const uint32_t argsLength = 2; + int64_t k = 0; + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + JSMutableHandle kValue(thread, JSTaggedValue::Undefined()); + JSHandle mapValue; + while (k < len) { + tKey.Update(JSTaggedValue(k)); + kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, arrayLike.GetTaggedValue(), + tKey.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (mapping) { + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, mapfn, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + mapValue = JSHandle(thread, callResult); + } else { + mapValue = kValue; + } + ObjectFastOperator::FastSetPropertyByIndex(thread, targetObj.GetTaggedValue(), k, mapValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + } + // 13. Return targetObj. + return targetObj.GetTaggedValue(); +} + +// 22.2.2.2 %TypedArray%.of ( ...items ) +JSTaggedValue BuiltinsSharedTypedArray::Of(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Of); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let len be the actual number of arguments passed to this function. + uint32_t len = argv->GetArgsNumber(); + // 2. Let items be the List of arguments passed to this function. + // 3. Let C be the this value. + JSHandle thisHandle = GetThis(argv); + // 4. If IsConstructor(C) is false, throw a TypeError exception. + if (!thisHandle->IsConstructor()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the this value is not a Constructor.", JSTaggedValue::Exception()); + } + // 5. Let newObj be TypedArrayCreate(C, « len »). + JSTaggedType args[1] = { JSTaggedValue(len).GetRawData() }; + JSHandle newObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, args); + // 6. ReturnIfAbrupt(newObj). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 7. Let k be 0. + // 8. Repeat, while k < len + // a. Let kValue be items[k]. + // b. Let Pk be ! ToString(k). + // c. Perform ? Set(newObj, Pk, kValue, true). + // d. ReturnIfAbrupt(status). + // e. Set k to k + 1. + JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + uint32_t k = 0; + while (k < len) { + tKey.Update(JSTaggedValue(k)); + JSHandle kKey(JSTaggedValue::ToString(thread, tKey)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle kValue = GetCallArg(argv, k); + JSTaggedValue::SetProperty(thread, JSHandle::Cast(newObj), kKey, kValue, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + } + // 9. Return newObj. + return newObj.GetTaggedValue(); +} + +// 22.2.2.4 +JSTaggedValue BuiltinsSharedTypedArray::Species(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Species); + // 1. Return the this value. + return GetThis(argv).GetTaggedValue(); +} + +// prototype +// 22.2.3.1 get %TypedArray%.prototype.buffer +JSTaggedValue BuiltinsSharedTypedArray::GetBuffer(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetBuffer); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, throw a TypeError exception. + if (!thisHandle->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception()); + } + // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot. + JSHandle typedArray = JSHandle::Cast(thisHandle); + JSTaggedValue buffer = JSTypedArray::GetOffHeapBuffer(thread, typedArray); + // 5. Return buffer. + return buffer; +} + +// 22.2.3.2 +JSTaggedValue BuiltinsSharedTypedArray::GetByteLength(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetByteLength); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, throw a TypeError exception. + if (!thisHandle->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception()); + } + // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot. + JSHandle typeArrayObj = JSHandle::Cast(thisHandle); + JSTaggedValue buffer = typeArrayObj->GetViewedArrayBufferOrByteArray(); + // 5. If IsDetachedBuffer(buffer) is true, return 0. + if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) { + return JSTaggedValue(0); + } + // 6. Let size be the value of O’s [[ByteLength]] internal slot. + // 7. Return size. + return JSTaggedValue(typeArrayObj->GetByteLength()); +} + +// 22.2.3.3 +JSTaggedValue BuiltinsSharedTypedArray::GetByteOffset(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetByteOffset); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, throw a TypeError exception. + if (!thisHandle->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception()); + } + // 4. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot. + JSHandle typeArrayObj = JSHandle::Cast(thisHandle); + JSTaggedValue buffer = typeArrayObj->GetViewedArrayBufferOrByteArray(); + // 5. If IsDetachedBuffer(buffer) is true, return 0. + if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) { + return JSTaggedValue(0); + } + // 6. Let offset be the value of O’s [[ByteOffset]] internal slot. + uint32_t offset = typeArrayObj->GetByteOffset(); + // 7. Return offset. + return JSTaggedValue(offset); +} + +// 22.2.3.5 +JSTaggedValue BuiltinsSharedTypedArray::CopyWithin(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, CopyWithin); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::CopyWithin(argv); +} + +// 22.2.3.6 +JSTaggedValue BuiltinsSharedTypedArray::Entries(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Entries); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. Let valid be ValidateTypedArray(O). + TypedArrayHelper::ValidateTypedArray(thread, thisHandle); + // 3. ReturnIfAbrupt(valid). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread()); + JSHandle self(thisHandle); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 4. Return CreateArrayIterator(O, "key+value"). + JSHandle iter(factory->NewJSSharedArrayIterator(self, IterationKind::KEY_AND_VALUE)); + return iter.GetTaggedValue(); +} + +// 22.2.3.7 +JSTaggedValue BuiltinsSharedTypedArray::Every(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Every); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + uint32_t len = JSHandle::Cast(thisObjHandle)->GetArrayLength(); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 7. Let k be 0. + // 8. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + // d. If kPresent is true, then + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + // iii. Let testResult be ToBoolean(Call(callbackfn, T, «kValue, k, O»)). + // iv. ReturnIfAbrupt(testResult). + // v. If testResult is false, return false. + // e. Increase k by 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + const uint32_t argsLength = 3; + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + uint32_t k = 0; + while (k < len) { + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + bool boolResult = callResult.ToBoolean(); + if (!boolResult) { + return GetTaggedBoolean(false); + } + k++; + } + + // 9. Return true. + return GetTaggedBoolean(true); +} + +// 22.2.3.8 +JSTaggedValue BuiltinsSharedTypedArray::Fill(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Fill); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::Fill(argv); +} + +// 22.2.3.9 %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] ) +JSTaggedValue BuiltinsSharedTypedArray::Filter(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Filter); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. Let valid be ValidateTypedArray(O). + TypedArrayHelper::ValidateTypedArray(thread, thisHandle); + // 3. ReturnIfAbrupt(valid). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle thisObj(thisHandle); + // 4. Let len be the value of O’s [[ArrayLength]] internal slot. + uint32_t len = thisObj->GetArrayLength(); + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 10. Let kept be a new empty List. + JSHandle kept(factory->NewTaggedArray(len)); + + // 11. Let k be 0. + // 12. Let captured be 0. + // 13. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kValue be Get(O, Pk). + // c. ReturnIfAbrupt(kValue). + // d. Let selected be ToBoolean(Call(callbackfn, T, «kValue, k, O»)). + // e. ReturnIfAbrupt(selected). + // f. If selected is true, then + // i. Append kValue to the end of kept. + // ii. Increase captured by 1. + // g. Increase k by 1. + int32_t captured = 0; + JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + JSMutableHandle kValue(thread, JSTaggedValue::Undefined()); + for (uint32_t k = 0; k < len; k++) { + tKey.Update(JSTaggedValue(k)); + kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(), + tKey.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, + undefined, 3); // 3: «kValue, k, O» + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), tKey.GetTaggedValue(), thisHandle.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (callResult.ToBoolean()) { + kept->Set(thread, captured, kValue); + captured++; + } + } + // es11 9. Let A be ? TypedArraySpeciesCreate(O, « captured »). + JSTaggedType args[1] = {JSTaggedValue(captured).GetRawData()}; + JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args); + // 15. ReturnIfAbrupt(A). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 16. Let n be 0. + // 17. For each element e of kept + // a. Let status be Set(A, ToString(n), e, true ). + // b. ReturnIfAbrupt(status). + // c. Increase n by 1. + JSMutableHandle valueHandle(thread, JSTaggedValue::Undefined()); + JSMutableHandle ntKey(thread, JSTaggedValue::Undefined()); + for (int32_t n = 0; n < captured; n++) { + valueHandle.Update(kept->Get(n)); + ntKey.Update(JSTaggedValue(n)); + ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(), + ntKey.GetTaggedValue(), valueHandle.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + // 18. Return A. + return newArrObj.GetTaggedValue(); +} + +// 22.2.3.10 +JSTaggedValue BuiltinsSharedTypedArray::Find(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Find); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::Find(argv); +} + +// 22.2.3.11 +JSTaggedValue BuiltinsSharedTypedArray::FindIndex(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, FindIndex); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::FindIndex(argv); +} + +// 22.2.3.12 +JSTaggedValue BuiltinsSharedTypedArray::ForEach(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, ForEach); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be ToLength(Get(O, "length")). + uint32_t len = JSHandle::Cast(thisObjHandle)->GetArrayLength(); + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + + // 7. Let k be 0. + // 8. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kPresent be HasProperty(O, Pk). + // c. ReturnIfAbrupt(kPresent). + // d. If kPresent is true, then + // i. Let kValue be Get(O, Pk). + // ii. ReturnIfAbrupt(kValue). + // iii. Let funcResult be Call(callbackfn, T, «kValue, k, O»). + // iv. ReturnIfAbrupt(funcResult). + // e. Increase k by 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + const uint32_t argsLength = 3; + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + uint32_t k = 0; + while (k < len) { + JSHandle kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + key.Update(JSTaggedValue(k)); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisObjVal.GetTaggedValue()); + JSTaggedValue funcResult = JSFunction::Call(info); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); + k++; + } + + // 9. Return undefined. + return JSTaggedValue::Undefined(); +} + +// 22.2.3.13 +JSTaggedValue BuiltinsSharedTypedArray::IndexOf(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, IndexOf); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::IndexOf(argv); +} + +// 22.2.3.14 +JSTaggedValue BuiltinsSharedTypedArray::Join(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Join); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle thisHandle = GetThis(argv); + + if (!thisHandle->IsSharedTypedArray() && !thisHandle->IsTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + + uint32_t length = JSHandle::Cast(thisHandle)->GetArrayLength(); + + JSHandle sepHandle = GetCallArg(argv, 0); + int sep = ','; + uint32_t sepLength = 1; + JSHandle sepStringHandle; + if (!sepHandle->IsUndefined()) { + if (sepHandle->IsString()) { + sepStringHandle = JSHandle::Cast(sepHandle); + } else { + sepStringHandle = JSTaggedValue::ToString(thread, sepHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + if (EcmaStringAccessor(sepStringHandle).IsUtf8() && EcmaStringAccessor(sepStringHandle).GetLength() == 1) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + sep = EcmaStringAccessor(sepStringHandle).Get(0); + } else if (EcmaStringAccessor(sepStringHandle).GetLength() == 0) { + sep = BuiltinsSharedTypedArray::SeparatorFlag::MINUS_TWO; + sepLength = 0; + } else { + sep = BuiltinsSharedTypedArray::SeparatorFlag::MINUS_ONE; + sepLength = EcmaStringAccessor(sepStringHandle).GetLength(); + } + } + if (length == 0) { + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + return globalConst->GetEmptyString(); + } + size_t allocateLength = 0; + bool isOneByte = (sep != BuiltinsSharedTypedArray::SeparatorFlag::MINUS_ONE) || + EcmaStringAccessor(sepStringHandle).IsUtf8(); + CVector> vec; + JSMutableHandle elementHandle(thread, JSTaggedValue::Undefined()); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + for (uint32_t k = 0; k < length; k++) { + JSTaggedValue element = JSTypedArray::GetProperty(thread, thisHandle, k).GetValue().GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (!element.IsUndefinedOrNull() && !element.IsHole()) { + if (!element.IsString()) { + elementHandle.Update(element); + JSHandle strElement = JSTaggedValue::ToString(thread, elementHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + element = strElement.GetTaggedValue(); + } + auto nextStr = EcmaString::Cast(element.GetTaggedObject()); + JSHandle nextStrHandle(thread, nextStr); + vec.push_back(nextStrHandle); + isOneByte = EcmaStringAccessor(nextStr).IsUtf8() ? isOneByte : false; + allocateLength += EcmaStringAccessor(nextStr).GetLength(); + } else { + vec.push_back(JSHandle(globalConst->GetHandledEmptyString())); + } + } + allocateLength += sepLength * (length - 1); + if (allocateLength <= 1) { + // sep unused, set isOneByte to default(true) + isOneByte = true; + } + auto newString = EcmaStringAccessor::CreateLineString(thread->GetEcmaVM(), allocateLength, isOneByte); + int current = 0; + DISALLOW_GARBAGE_COLLECTION; + for (uint32_t k = 0; k < length; k++) { + if (k > 0) { + if (sep >= 0) { + EcmaStringAccessor(newString).Set(current, static_cast(sep)); + } else if (sep != BuiltinsSharedTypedArray::SeparatorFlag::MINUS_TWO) { + EcmaStringAccessor::ReadData( + newString, *sepStringHandle, current, allocateLength - static_cast(current), sepLength); + } + current += static_cast(sepLength); + } + JSHandle nextStr = vec[k]; + int nextLength = static_cast(EcmaStringAccessor(nextStr).GetLength()); + EcmaStringAccessor::ReadData(newString, *nextStr, current, + allocateLength - static_cast(current), nextLength); + current += nextLength; + } + ASSERT_PRINT( + isOneByte == EcmaStringAccessor::CanBeCompressed(newString), "isOneByte does not match the real value!"); + return JSTaggedValue(newString); +} + +// 22.2.3.15 +JSTaggedValue BuiltinsSharedTypedArray::Keys(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Keys); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. Let valid be ValidateTypedArray(O). + TypedArrayHelper::ValidateTypedArray(thread, thisHandle); + // 3. ReturnIfAbrupt(valid). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread()); + JSHandle self(thisHandle); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 4. Return CreateArrayIterator(O, "key"). + JSHandle iter(factory->NewJSSharedArrayIterator(self, IterationKind::KEY)); + return iter.GetTaggedValue(); +} + +// 22.2.3.17 +JSTaggedValue BuiltinsSharedTypedArray::GetLength(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, GetLength); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, throw a TypeError exception. + if (!thisHandle->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception()); + } + // 4. Assert: O has [[ViewedArrayBuffer]] and [[ArrayLength]] internal slots. + // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot. + JSTaggedValue buffer = JSHandle::Cast(thisHandle)->GetViewedArrayBufferOrByteArray(); + // 6. If IsDetachedBuffer(buffer) is true, return 0. + if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer)) { + return JSTaggedValue(0); + } + // 7. Let length be the value of O’s [[ArrayLength]] internal slot. + uint32_t length = JSHandle(thisHandle)->GetArrayLength(); + // 8. Return length. + return JSTaggedValue(length); +} + +// 22.2.3.18 %TypedArray%.prototype.map ( callbackfn [ , thisArg ] ) +JSTaggedValue BuiltinsSharedTypedArray::Map(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Map); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. Let valid be ValidateTypedArray(O). + TypedArrayHelper::ValidateTypedArray(thread, thisHandle); + // 3. ReturnIfAbrupt(valid). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle thisObj(thisHandle); + // 4. Let len be the value of O’s [[ArrayLength]] internal slot. + uint32_t len = thisObj->GetArrayLength(); + // 5. If IsCallable(callbackfn) is false, throw a TypeError exception. + JSHandle callbackfnHandle = GetCallArg(argv, 0); + if (!callbackfnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "the callbackfun is not callable.", JSTaggedValue::Exception()); + } + // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. + JSHandle thisArgHandle = GetCallArg(argv, 1); + // es11 5. Let A be ? TypedArraySpeciesCreate(O, « len »). + JSTaggedType args[1] = {JSTaggedValue(len).GetRawData()}; + JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args); // 1: one arg. + // 11. ReturnIfAbrupt(A). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 12. Let k be 0. + // 13. Repeat, while k < len + // a. Let Pk be ToString(k). + // b. Let kValue be Get(O, Pk). + // c. ReturnIfAbrupt(kValue). + // d. Let mappedValue be Call(callbackfn, T, «kValue, k, O»). + // e. ReturnIfAbrupt(mappedValue). + // f. Let status be Set(A, Pk, mappedValue, true ). + // g. ReturnIfAbrupt(status). + // h. Increase k by 1. + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle mapValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle kValue(thread, JSTaggedValue::Undefined()); + const uint32_t argsLength = 3; + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + for (uint32_t k = 0; k < len; k++) { + key.Update(JSTaggedValue(k)); + kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(), + key.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + EcmaRuntimeCallInfo *info = + EcmaInterpreter::NewRuntimeCallInfo(thread, callbackfnHandle, thisArgHandle, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(kValue.GetTaggedValue(), key.GetTaggedValue(), thisHandle.GetTaggedValue()); + JSTaggedValue callResult = JSFunction::Call(info); + mapValue.Update(callResult); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(), + key.GetTaggedValue(), mapValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + + // 14. Return A. + return newArrObj.GetTaggedValue(); +} + +// 22.2.3.19 +JSTaggedValue BuiltinsSharedTypedArray::Reduce(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Reduce); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::Reduce(argv); +} + +// 22.2.3.21 +JSTaggedValue BuiltinsSharedTypedArray::Reverse(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Reverse); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // 2. ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + // 3. Let len be O.[[ArrayLength]] + int64_t len = JSHandle::Cast(thisHandle)->GetArrayLength(); + + // 4. ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 5. Let middle be floor(len/2). + int64_t middle = std::floor(len / 2); + + // 6. Let lower be 0. + int64_t lower = 0; + + // 7. Repeat, while lower ≠ middle, + // a. Let upper be len - lower - 1. + // b. Let upperP be ! ToString(𝔽(upper)). + // c. Let lowerP be ! ToString(𝔽(lower)). + // d. Let lowerValue be ! Get(O, lowerP). + // e. Let upperValue be ! Get(O, upperP). + // f. Perform ! Set(O, lowerP, upperValue, true). + // g. Perform ! Set(O, upperP, lowerValue, true). + // h. Set lower to lower + 1. + JSMutableHandle lowerP(thread, JSTaggedValue::Undefined()); + JSMutableHandle upperP(thread, JSTaggedValue::Undefined()); + JSHandle lowerValueHandle(thread, JSTaggedValue::Undefined()); + JSHandle upperValueHandle(thread, JSTaggedValue::Undefined()); + while (lower != middle) { + int64_t upper = len - lower - 1; + lowerP.Update(JSTaggedValue(lower)); + upperP.Update(JSTaggedValue(upper)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + lowerValueHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, lowerP); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + upperValueHandle = JSArray::FastGetPropertyByValue(thread, thisObjVal, upperP); + JSArray::FastSetPropertyByValue(thread, thisObjVal, lowerP, upperValueHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSArray::FastSetPropertyByValue(thread, thisObjVal, upperP, lowerValueHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + lower++; + } + + // 8. Return O . + return thisObjHandle.GetTaggedValue(); +} + +// 22.2.3.22 %TypedArray%.prototype.set ( overloaded [ , offset ]) +JSTaggedValue BuiltinsSharedTypedArray::Set(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Set); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Assert: array is any ECMAScript language value other than an Object with a [[TypedArrayName]] internal slot. + // If it is such an Object, the definition in 22.2.3.22.2 applies. + // 2. Let target be the this value. + JSHandle target = GetThis(argv); + // 3. If Type(target) is not Object, throw a TypeError exception. + if (!target->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception()); + } + JSHandle targetObj(target); + // 4. If target does not have a [[TypedArrayName]] internal slot, throw a TypeError exception. + if (!target->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.", + JSTaggedValue::Exception()); + } + + // 5. Assert: target has a [[ViewedArrayBuffer]] internal slot. + // 6. Let targetOffset be ToInteger (offset). + const JSHandle srcOffset = GetCallArg(argv, 1); + uint64_t targetOffset = 0; + if (srcOffset->IsInt()) { + if (srcOffset->GetInt() < 0) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.", + JSTaggedValue::Exception()); + } + targetOffset = static_cast(srcOffset->GetInt()); + } else { + JSTaggedNumber tTargetOffset = JSTaggedValue::ToInteger(thread, srcOffset); + // 7. ReturnIfAbrupt(targetOffset). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + double rawTargetOffset = tTargetOffset.GetNumber(); + // 8. If targetOffset < 0, throw a RangeError exception. + if (rawTargetOffset < 0) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset of This value is less than 0.", + JSTaggedValue::Exception()); + } else if (rawTargetOffset == base::POSITIVE_INFINITY) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The targetOffset is infinty, which is greater than targetLength.", + JSTaggedValue::Exception()); + } else { + targetOffset = static_cast(rawTargetOffset); + } + } + // 9. Let targetBuffer be the value of target’s [[ViewedArrayBuffer]] internal slot. + JSHandle targetBuffer(thread, targetObj->GetViewedArrayBufferOrByteArray()); + // 10. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception. + if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.", + JSTaggedValue::Exception()); + } + // 11. Let targetLength be the value of target’s [[ArrayLength]] internal slot. + // 12. Let targetName be the String value of target’s [[TypedArrayName]] internal slot. + // 13. Let targetElementSize be the Number value of the Element Size value specified in Table 49 for targetName. + // 14. Let targetType be the String value of the Element Type value in Table 49 for targetName. + // 15. Let targetByteOffset be the value of target’s [[ByteOffset]] internal slot. + uint32_t targetLength = targetObj->GetArrayLength(); + DataViewType targetType = TypedArrayHelper::GetType(targetObj); + uint32_t targetElementSize = TypedArrayHelper::GetSizeFromType(targetType); + uint32_t targetByteOffset = targetObj->GetByteOffset(); + + JSHandle argArray = GetCallArg(argv, 0); + + // 22.2.3.22.1 %TypedArray%.prototype.set (array [ , offset ] ) + if (!argArray->IsTypedArray()) { + if (argArray->IsStableJSArray(thread)) { + uint32_t length = JSHandle::Cast(argArray)->GetArrayLength(); + JSHandle argObj(argArray); + uint32_t elemLength = ElementAccessor::GetElementsLength(argObj); + // Load On Demand check + if (elemLength >= length) { + return JSStableArray::FastCopyFromArrayToTypedArray(thread, targetObj, targetType, + targetOffset, length, argObj); + } + } + // 16. Let src be ToObject(array). + JSHandle src = JSTaggedValue::ToObject(thread, argArray); + // 17. ReturnIfAbrupt(src). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 18. Let srcLength be ToLength(Get(src, "length")). + JSHandle lengthKey = thread->GlobalConstants()->GetHandledLengthString(); + JSHandle lenResult(thread, + ObjectFastOperator::FastGetPropertyByValue(thread, + JSHandle::Cast(src).GetTaggedValue(), + lengthKey.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSTaggedNumber tSrcLen = JSTaggedValue::ToLength(thread, lenResult); + // 19. ReturnIfAbrupt(srcLength). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + uint64_t srcLen = static_cast(tSrcLen.GetNumber()); + // 20. If srcLength + targetOffset > targetLength, throw a RangeError exception. + if (srcLen + targetOffset > targetLength) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.", + JSTaggedValue::Exception()); + } + // 21. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset. + ASSERT((targetOffset * static_cast(targetElementSize) + + static_cast(targetByteOffset)) <= static_cast(UINT32_MAX)); + uint32_t targetByteIndex = static_cast(targetOffset * targetElementSize + targetByteOffset); + // 22. Let k be 0. + // 23. Let limit be targetByteIndex + targetElementSize × srcLength. + uint32_t k = 0; + ASSERT((static_cast(targetElementSize) * srcLen + + static_cast(targetByteIndex)) <= static_cast(UINT32_MAX)); + uint32_t limit = targetByteIndex + targetElementSize * srcLen; + // 24. Repeat, while targetByteIndex < limit + // a. Let Pk be ToString(k). + // b. If target.[[ContentType]] is BigInt, set value to ? ToBigInt(value). + // c. Otherwise, set value to ? ToNumber(value). + // d. If IsDetachedBuffer(targetBuffer) is true, throw a TypeError exception. + // e. Perform SetValueInBuffer(targetBuffer, targetByteIndex, targetType, kNumber). + // f. Set k to k + 1. + // g. Set targetByteIndex to targetByteIndex + targetElementSize. + JSMutableHandle tKey(thread, JSTaggedValue::Hole()); + JSMutableHandle kValue(thread, JSTaggedValue::Hole()); + JSMutableHandle kNumberHandle(thread, JSTaggedValue::Hole()); + ContentType contentType = JSHandle::Cast(target)->GetContentType(); + while (targetByteIndex < limit) { + tKey.Update(JSTaggedValue(k)); + JSHandle kKey(JSTaggedValue::ToString(thread, tKey)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + kValue.Update(ObjectFastOperator::FastGetPropertyByValue( + thread, JSHandle::Cast(src).GetTaggedValue(), kKey.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (BuiltinsArrayBuffer::IsDetachedBuffer(targetBuffer.GetTaggedValue())) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The targetBuffer of This value is detached buffer.", + JSTaggedValue::Exception()); + } + if (contentType == ContentType::BigInt) { + kNumberHandle.Update(JSTaggedValue::ToBigInt(thread, kValue)); + } else { + kNumberHandle.Update(JSTaggedValue::ToNumber(thread, kValue)); + } + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex, + targetType, kNumberHandle, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + k++; + targetByteIndex = targetByteIndex + targetElementSize; + } + // 25. Return undefined. + return JSTaggedValue::Undefined(); + } + + // 22.2.3.22.2 %TypedArray%.prototype.set(typedArray [, offset ] ) + JSHandle typedArray(argArray); + // 12. Let srcBuffer be the value of typedArray’s [[ViewedArrayBuffer]] internal slot. + // 13. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. + JSTaggedValue srcBuffer = typedArray->GetViewedArrayBufferOrByteArray(); + JSHandle srcBufferHandle(thread, srcBuffer); + if (BuiltinsArrayBuffer::IsDetachedBuffer(srcBuffer)) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of typedArray is detached buffer.", + JSTaggedValue::Exception()); + } + + ContentType objContentType = JSHandle::Cast(target)->GetContentType(); + ContentType argArrayContentType = JSHandle::Cast(argArray)->GetContentType(); + if (argArrayContentType != objContentType) { + THROW_TYPE_ERROR_AND_RETURN(thread, + "argArrayContentType is not equal objContentType.", + JSTaggedValue::Exception()); + } + // 18. Let srcName be the String value of typedArray’s [[TypedArrayName]] internal slot. + // 19. Let srcType be the String value of the Element Type value in Table 49 for srcName . + // 20. Let srcElementSize be the Number value of the Element Size value specified in Table 49 for srcName. + // 21. Let srcLength be the value of typedArray’s [[ArrayLength]] internal slot. + // 22. Let srcByteOffset be the value of typedArray’s [[ByteOffset]] internal slot. + JSHandle srcName(thread, typedArray->GetTypedArrayName()); + DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName); + uint32_t srcElementSize = TypedArrayHelper::GetSizeFromType(srcType); + uint32_t srcLength = typedArray->GetArrayLength(); + uint32_t srcByteOffset = typedArray->GetByteOffset(); + // 23. If srcLength + targetOffset > targetLength, throw a RangeError exception. + if (srcLength + targetOffset > targetLength) { + THROW_RANGE_ERROR_AND_RETURN(thread, "The sum of srcLength and targetOffset is greater than targetLength.", + JSTaggedValue::Exception()); + } + // 24. If SameValue(srcBuffer, targetBuffer) is true, then + // a. Let srcBuffer be CloneArrayBuffer(targetBuffer, srcByteOffset, %ArrayBuffer%). + // b. NOTE: %ArrayBuffer% is used to clone targetBuffer because is it known to not have any observable + // side-effects. + // c. ReturnIfAbrupt(srcBuffer). + // d. Let srcByteIndex be 0. + // 25. Else, let srcByteIndex be srcByteOffset. + uint32_t srcByteIndex = 0; + if (JSTaggedValue::SameValue(srcBufferHandle.GetTaggedValue(), targetBuffer.GetTaggedValue())) { + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + srcBuffer = + BuiltinsArrayBuffer::CloneArrayBuffer(thread, targetBuffer, srcByteOffset, env->GetArrayBufferFunction()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + srcBufferHandle = JSHandle(thread, srcBuffer); + srcByteIndex = 0; + } else { + srcByteIndex = srcByteOffset; + } + // 26. Let targetByteIndex be targetOffset × targetElementSize + targetByteOffset. + ASSERT((targetOffset * static_cast(targetElementSize) + + static_cast(targetByteOffset)) <= static_cast(UINT32_MAX)); + uint32_t targetByteIndex = static_cast(targetOffset) * targetElementSize + targetByteOffset; + // 27. Let limit be targetByteIndex + targetElementSize × srcLength. + ASSERT((static_cast(targetElementSize) * static_cast(srcLength) + + static_cast(targetByteIndex)) <= static_cast(UINT32_MAX)); + uint32_t limit = targetByteIndex + targetElementSize * srcLength; + uint32_t count = (limit - targetByteIndex) > 0 ? (limit - targetByteIndex) : 0; + // 28. If SameValue(srcType, targetType) is false, then + // a. Repeat, while targetByteIndex < limit + // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, srcType). + // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, targetType, value). + // iii. Set srcByteIndex to srcByteIndex + srcElementSize. + // iv. Set targetByteIndex to targetByteIndex + targetElementSize. + JSMutableHandle value(thread, JSTaggedValue::Undefined()); + if (srcType != targetType) { + while (targetByteIndex < limit) { + JSTaggedValue taggedData = + BuiltinsArrayBuffer::GetValueFromBuffer(thread, srcBufferHandle.GetTaggedValue(), + srcByteIndex, srcType, true); + value.Update(taggedData); + BuiltinsArrayBuffer::SetValueInBuffer(thread, targetBuffer.GetTaggedValue(), targetByteIndex, + targetType, value, true); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + srcByteIndex = srcByteIndex + srcElementSize; + targetByteIndex = targetByteIndex + targetElementSize; + } + } else if (count > 0) { + // 29. Else, + // a. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that preserves + // the bit-level encoding of the source data. + // b. Repeat, while targetByteIndex < limit + // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8"). + // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value). + // iii. Set srcByteIndex to srcByteIndex + 1. + // iv. Set targetByteIndex to targetByteIndex + 1. + void *srcBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(srcBufferHandle.GetTaggedValue(), srcByteIndex); + void *targetBuf = BuiltinsArrayBuffer::GetDataPointFromBuffer(targetBuffer.GetTaggedValue(), targetByteIndex); + if (memcpy_s(targetBuf, srcLength * srcElementSize, srcBuf, srcLength * srcElementSize) != EOK) { + LOG_FULL(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + } + // 30. Return undefined. + return JSTaggedValue::Undefined(); +} // namespace panda::ecmascript::builtins + +// 22.2.3.23 %TypedArray%.prototype.slice ( start, end ) +JSTaggedValue BuiltinsSharedTypedArray::Slice(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Slice); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. Let valid be ValidateTypedArray(O). + TypedArrayHelper::ValidateTypedArray(thread, thisHandle); + // 3. ReturnIfAbrupt(valid). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + JSHandle thisObj(thisHandle); + // 4. Let len be the value of O’s [[ArrayLength]] internal slot. + uint32_t len = thisObj->GetArrayLength(); + + // 5. Let relativeStart be ToInteger(start). + JSTaggedNumber tRelativeStart = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); + // 6. ReturnIfAbrupt(relativeStart). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + double relativeStart = tRelativeStart.GetNumber(); + // 7. If relativeStart < 0, let k be max((len + relativeStart),0); else let k be min(relativeStart, len). + + uint32_t k = relativeStart < 0 ? + std::max((static_cast(len) + relativeStart), 0.0) : + std::min(relativeStart, static_cast(len)); + // 8. If end is undefined, let relativeEnd be len; else let relativeEnd be ToInteger(end). + double relativeEnd = len; + JSHandle end = GetCallArg(argv, 1); + if (!end->IsUndefined()) { + JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end); + // 9. ReturnIfAbrupt(relativeEnd). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + relativeEnd = tRelativeEnd.GetNumber(); + } + + // 10. If relativeEnd < 0, let final be max((len + relativeEnd),0); else let final be min(relativeEnd, len). + + uint32_t final = relativeEnd < 0 ? + std::max((static_cast(len) + relativeEnd), 0.0) : + std::min(relativeEnd, static_cast(len)); + // 11. Let count be max(final – k, 0). + uint32_t count = final > k ? (final - k) : 0; + // es11 9. Let A be ? TypedArraySpeciesCreate(O, « count »). + JSTaggedType args[1] = {JSTaggedValue(count).GetRawData()}; + JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, args); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 17. Let srcName be the String value of O’s [[TypedArrayName]] internal slot. + // 18. Let srcType be the String value of the Element Type value in Table 49 for srcName. + JSHandle srcName(thread, thisObj->GetTypedArrayName()); + DataViewType srcType = JSTypedArray::GetTypeFromName(thread, srcName); + // 19. Let targetName be the String value of A’s [[TypedArrayName]] internal slot. + // 20. Let targetType be the String value of the Element Type value in Table 49 for targetName. + JSHandle targetName(thread, JSTypedArray::Cast(*newArrObj)->GetTypedArrayName()); + DataViewType targetType = JSTypedArray::GetTypeFromName(thread, targetName); + // 21. If SameValue(srcType, targetType) is false, then + // a. Let n be 0. + // b. Repeat, while k < final + // i. Let Pk be ToString(k). + // ii. Let kValue be Get(O, Pk). + // iii. ReturnIfAbrupt(kValue). + // iv. Let status be Set(A, ToString(n), kValue, true ). + // v. ReturnIfAbrupt(status). + // vi. Increase k by 1. + // vii. Increase n by 1. + JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); + JSMutableHandle kValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle ntKey(thread, JSTaggedValue::Undefined()); + if (srcType != targetType) { + uint32_t n = 0; + while (k < final) { + tKey.Update(JSTaggedValue(k)); + kValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisHandle.GetTaggedValue(), + tKey.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + ntKey.Update(JSTaggedValue(n)); + ObjectFastOperator::FastSetPropertyByValue(thread, newArrObj.GetTaggedValue(), + ntKey.GetTaggedValue(), kValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + n++; + k++; + } + } else if (count > 0) { + // 22. Else if count > 0, + // a. Let srcBuffer be the value of O’s [[ViewedArrayBuffer]] internal slot. + // b. If IsDetachedBuffer(srcBuffer) is true, throw a TypeError exception. + JSTaggedValue srcBuffer = thisObj->GetViewedArrayBufferOrByteArray(); + if (BuiltinsArrayBuffer::IsDetachedBuffer(srcBuffer)) { + THROW_TYPE_ERROR_AND_RETURN(thread, "The ArrayBuffer of this value is detached buffer.", + JSTaggedValue::Exception()); + } + // c. Let targetBuffer be the value of A’s [[ViewedArrayBuffer]] internal slot. + JSTaggedValue targetBuffer = JSTypedArray::Cast(*newArrObj)->GetViewedArrayBufferOrByteArray(); + // d. Let elementSize be the Number value of the Element Size value specified in Table 49 for srcType. + uint32_t elementSize = TypedArrayHelper::GetSizeFromType(srcType); + // e. NOTE: If srcType and targetType are the same the transfer must be performed in a manner that + // preserves the bit-level encoding of the source data. + // f. Let srcByteOffset be the value of O’s[[ByteOffset]] internal slot. + uint32_t srcByteOffset = thisObj->GetByteOffset(); + // h. Let srcByteIndex be (k × elementSize) + srcByteOffset. + uint32_t srcByteIndex = k * elementSize + srcByteOffset; + // g. Let targetByteIndex be A.[[ByteOffset]]. + uint32_t targetByteIndex = JSTypedArray::Cast(*newArrObj)->GetByteOffset(); + // i. Repeat, while targetByteIndex < count × elementSize + // i. Let value be GetValueFromBuffer(srcBuffer, srcByteIndex, "Uint8"). + // ii. Perform SetValueInBuffer (targetBuffer, targetByteIndex, "Uint8", value). + // iii. Increase srcByteIndex by 1. + // iv. Increase targetByteIndex by 1. + uint8_t *srcBuf = (uint8_t *)BuiltinsArrayBuffer::GetDataPointFromBuffer(srcBuffer, srcByteIndex); + uint8_t *targetBuf = (uint8_t *)BuiltinsArrayBuffer::GetDataPointFromBuffer(targetBuffer, targetByteIndex); + if (srcBuffer != targetBuffer && memmove_s( + targetBuf, elementSize * count, srcBuf, elementSize * count) != EOK) { + LOG_FULL(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + while (srcBuffer == targetBuffer && count--) { + if (memcpy_s(targetBuf, elementSize, srcBuf, elementSize) != EOK) { + LOG_FULL(FATAL) << "memcpy_s failed"; + UNREACHABLE(); + } + srcBuf += elementSize; + targetBuf += elementSize; + } + } + // 23. Return A. + return newArrObj.GetTaggedValue(); +} + +// 22.2.3.24 +JSTaggedValue BuiltinsSharedTypedArray::Some(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Some); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::Some(argv); +} + +// 22.2.3.25 +JSTaggedValue BuiltinsSharedTypedArray::Sort(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Sort); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let obj be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + if (!thisHandle->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle thisObjVal(thisObjHandle); + + JSHandle buffer; + buffer = JSHandle(thread, TypedArrayHelper::ValidateTypedArray(thread, thisHandle)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + uint32_t len = JSHandle::Cast(thisObjHandle)->GetArrayLength(); + + JSHandle callbackFnHandle = GetCallArg(argv, 0); + if (!callbackFnHandle->IsUndefined() && !callbackFnHandle->IsCallable()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); + } + JSMutableHandle presentValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle middleValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle previousValue(thread, JSTaggedValue::Undefined()); + JSMutableHandle key1(thread, JSTaggedValue::Undefined()); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); + JSMutableHandle key2(thread, JSTaggedValue::Undefined()); + for (uint32_t i = 1; i < len; i++) { + uint32_t beginIndex = 0; + uint32_t endIndex = i; + key.Update(JSTaggedValue(i)); + presentValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(), + key.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + while (beginIndex < endIndex) { + uint32_t middleIndex = beginIndex + (endIndex - beginIndex) / 2; // 2 : half + key1.Update(JSTaggedValue(middleIndex)); + middleValue.Update(ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(), + key1.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + int32_t compareResult = TypedArrayHelper::SortCompare(thread, callbackFnHandle, buffer, + middleValue, presentValue); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + compareResult > 0 ? (endIndex = middleIndex) : (beginIndex = middleIndex + 1); + } + + if (endIndex < i) { + for (uint32_t j = i; j > endIndex; j--) { + key2.Update(JSTaggedValue(j - 1)); + previousValue.Update( + ObjectFastOperator::FastGetPropertyByValue(thread, thisObjHandle.GetTaggedValue(), + key2.GetTaggedValue())); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), j, + previousValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + ObjectFastOperator::FastSetPropertyByIndex(thread, thisObjHandle.GetTaggedValue(), endIndex, + presentValue.GetTaggedValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + } + } + return thisObjHandle.GetTaggedValue(); +} + +// 22.2.3.26 %TypedArray%.prototype.subarray( [ begin [ , end ] ] ) +JSTaggedValue BuiltinsSharedTypedArray::Subarray(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Subarray); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, throw a TypeError exception. + if (!thisHandle->IsECMAObject()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value is not an object.", JSTaggedValue::Exception()); + } + JSHandle thisObj(thisHandle); + // 3. If O does not have a [[TypedArrayName]] internal slot, throw a TypeError exception. + if (!thisHandle->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "This value does not have a [[TypedArrayName]] internal slot.", + JSTaggedValue::Exception()); + } + // 4. Assert: O has a [[ViewedArrayBuffer]] internal slot. + // 6. Let srcLength be the value of O’s [[ArrayLength]] internal slot. + uint32_t srcLength = thisObj->GetArrayLength(); + // 7. Let relativeBegin be ToInteger(begin). + JSTaggedNumber tRelativeBegin = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); + // 8. ReturnIfAbrupt(relativeBegin). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + double relativeBegin = tRelativeBegin.GetNumber(); + + uint32_t beginIndex = 0; + // 9. If relativeBegin < 0, let beginIndex be max((srcLength + relativeBegin), 0); else let beginIndex be + // min(relativeBegin, srcLength). + if (relativeBegin < 0) { + double tempBeginIndex = relativeBegin + static_cast(srcLength); + beginIndex = tempBeginIndex > 0 ? static_cast(tempBeginIndex) : 0; + } else { + beginIndex = relativeBegin < static_cast(srcLength) ? + static_cast(relativeBegin) : srcLength; + } + + // 10. If end is undefined, let relativeEnd be srcLength; else, let relativeEnd be ToInteger(end). + double relativeEnd = srcLength; + JSHandle end = GetCallArg(argv, 1); + if (!end->IsUndefined()) { + JSTaggedNumber tRelativeEnd = JSTaggedValue::ToInteger(thread, end); + // 11. ReturnIfAbrupt(relativeEnd). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + relativeEnd = tRelativeEnd.GetNumber(); + } + // 12. If relativeEnd < 0, let endIndex be max((srcLength + relativeEnd), 0); else let endIndex be + // min(relativeEnd, srcLength). + uint32_t endIndex; + if (relativeEnd < 0) { + double tempEndIndex = relativeEnd + static_cast(srcLength); + endIndex = tempEndIndex > 0 ? static_cast(tempEndIndex) : 0; + } else { + endIndex = relativeEnd < static_cast(srcLength) ? + static_cast(relativeEnd) : srcLength; + } + // 13. Let newLength be max(endIndex – beginIndex, 0). + uint32_t newLength = endIndex > beginIndex ? (endIndex - beginIndex) : 0; + // 14. Let constructorName be the String value of O’s [[TypedArrayName]] internal slot. + // 15. Let elementSize be the Number value of the Element Size value specified in Table 49 for constructorName. + // 16. Let srcByteOffset be the value of O’s [[ByteOffset]] internal slot. + // 17. Let beginByteOffset be srcByteOffset + beginIndex × elementSize. + JSHandle constructorName(thread, thisObj->GetTypedArrayName()); + DataViewType elementType = JSTypedArray::GetTypeFromName(thread, constructorName); + uint32_t elementSize = TypedArrayHelper::GetSizeFromType(elementType); + uint32_t srcByteOffset = thisObj->GetByteOffset(); + ASSERT((static_cast(srcByteOffset) + static_cast(beginIndex) * + static_cast(elementSize)) <= static_cast(UINT32_MAX)); + uint32_t beginByteOffset = srcByteOffset + beginIndex * elementSize; + JSTaggedValue buffer = JSTypedArray::GetOffHeapBuffer(thread, thisObj); + // 21. Let argumentsList be «buffer, beginByteOffset, newLength». + // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot. + // 22. Return Construct(constructor, argumentsList). + const uint32_t argsLength = 3; + JSTaggedType args[argsLength] = { + buffer.GetRawData(), + JSTaggedValue(beginByteOffset).GetRawData(), + JSTaggedValue(newLength).GetRawData() + }; + JSHandle newArr = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, argsLength, args); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return newArr.GetTaggedValue(); +} + +// 22.2.3.29 +JSTaggedValue BuiltinsSharedTypedArray::Values(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Values); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. Let valid be ValidateTypedArray(O). + TypedArrayHelper::ValidateTypedArray(thread, thisHandle); + // 3. ReturnIfAbrupt(valid). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(argv->GetThread()); + JSHandle self(thisHandle); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + // 4. Return CreateArrayIterator(O, "value"). + JSHandle iter(factory->NewJSSharedArrayIterator(self, IterationKind::VALUE)); + return iter.GetTaggedValue(); +} + +// 22.2.3.31 +JSTaggedValue BuiltinsSharedTypedArray::ToStringTag(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, ToStringTag); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + // 1. Let O be the this value. + JSHandle thisHandle = GetThis(argv); + // 2. If Type(O) is not Object, return undefined. + if (!thisHandle->IsECMAObject()) { + return JSTaggedValue::Undefined(); + } + // 3. If O does not have a [[TypedArrayName]] internal slot, return undefined. + if (!thisHandle->IsSharedTypedArray()) { + return JSTaggedValue::Undefined(); + } + // 4. Let name be the value of O’s [[TypedArrayName]] internal slot. + JSTaggedValue name = JSHandle::Cast(thisHandle)->GetTypedArrayName(); + // 5. Assert: name is a String value. + ASSERT(name.IsString()); + // 6. Return name. + return name; +} + +// 23.2.3.1 +JSTaggedValue BuiltinsSharedTypedArray::At(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, At); + JSThread *thread = argv->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + // 1. Let O be ToObject(this value). + JSHandle thisHandle = GetThis(argv); + // 2. Perform ? ValidateTypedArray(O). + if (!thisHandle->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + JSHandle thisObjHandle = JSTaggedValue::ToObject(thread, thisHandle); + // ReturnIfAbrupt(O). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 3. Let len be O.[[ArrayLength]]. + uint32_t len = JSHandle::Cast(thisObjHandle)->GetArrayLength(); + // ReturnIfAbrupt(len). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + + // 4. Let relativeIndex be ? ToIntegerOrInfinity(index). + JSTaggedNumber indexVal = JSTaggedValue::ToInteger(thread, GetCallArg(argv, 0)); + // ReturnIfAbrupt(indexVal). + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + int64_t relativeIndex = indexVal.GetNumber(); + int64_t k = 0; + // 5. If relativeIndex ≥ 0, then Let k be relativeIndex. + // 6. Else, Let k be len + relativeIndex. + k = relativeIndex >= 0 ? relativeIndex : static_cast(len) + relativeIndex; + // 7. If k < 0 or k ≥ len, return undefined. + if (k < 0 || k >= len) { + return JSTaggedValue::Undefined(); + } + // 8. Return ! Get(O, ! ToString(𝔽(k))). + JSHandle kValue = JSTypedArray::GetProperty(thread, thisHandle, k).GetValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + return kValue.GetTaggedValue(); +} + +// es12 23.2.3.13 +JSTaggedValue BuiltinsSharedTypedArray::Includes(EcmaRuntimeCallInfo *argv) +{ + ASSERT(argv); + BUILTINS_API_TRACE(argv->GetThread(), SharedTypedArray, Includes); + if (!GetThis(argv)->IsSharedTypedArray()) { + THROW_TYPE_ERROR_AND_RETURN(argv->GetThread(), "This is not a TypedArray.", JSTaggedValue::Exception()); + } + return BuiltinsArray::Includes(argv); +} +} // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_shared_typedarray.h b/ecmascript/builtins/builtins_shared_typedarray.h new file mode 100755 index 0000000000000000000000000000000000000000..1298eab9921e5fbc097805b615ca12728d28c5e3 --- /dev/null +++ b/ecmascript/builtins/builtins_shared_typedarray.h @@ -0,0 +1,301 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_BUILTINS_BUILTINS_SHARED_TYPEDARRAY_H +#define ECMASCRIPT_BUILTINS_BUILTINS_SHARED_TYPEDARRAY_H + +#include "ecmascript/base/builtins_base.h" + +#define TYPED_ARRAY_TYPES(V) \ + V(Int8Array) \ + V(Uint8Array) \ + V(Uint8ClampedArray) \ + V(Int16Array) \ + V(Uint16Array) \ + V(Int32Array) \ + V(Uint32Array) \ + V(Float32Array) \ + V(Float64Array) \ + V(BigInt64Array) \ + V(BigUint64Array) + +// All types of %TypedArray%. +// V(Type, ctorName, TYPE, bytesPerElement) where JSType::JS_##TYPE is the type index. +#define BUILTIN_SHARED_TYPED_ARRAY_TYPES(V) \ + V(Int8Array, SharedInt8Array, INT8_ARRAY, 1) \ + V(Uint8Array, SharedUint8Array, UINT8_ARRAY, 1) \ + V(Uint8ClampedArray, SharedUint8ClampedArray, UINT8_CLAMPED_ARRAY, 1) \ + V(Int16Array, SharedInt16Array, INT16_ARRAY, 2) \ + V(Uint16Array, SharedUint16Array, UINT16_ARRAY, 2) \ + V(Int32Array, SharedInt32Array, INT32_ARRAY, 4) \ + V(Uint32Array, SharedUint32Array, UINT32_ARRAY, 4) \ + V(Float32Array, SharedFloat32Array, FLOAT32_ARRAY, 4) \ + V(Float64Array, SharedFloat64Array, FLOAT64_ARRAY, 8) \ + V(BigInt64Array, SharedBigInt64Array, BIGINT64_ARRAY, 8) \ + V(BigUint64Array, SharedBigUint64Array, BIGUINT64_ARRAY, 8) + +// List of functions in %TypedArray%, excluding the '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsSharedTypedArray::func refers to the native implementation of %TypedArray%[name]. +// kungfu::BuiltinsStubCSigns::stubIndex refers to the builtin stub index, or INVALID if no stub available. +#define BUILTIN_SHARED_TYPED_ARRAY_FUNCTIONS(V) \ + /* %TypedArray%.from ( source [ , mapfn [ , thisArg ] ] ) */ \ + V("from", From, 1, INVALID) \ + /* %TypedArray%.of ( ...items ) */ \ + V("of", Of, 0, INVALID) + +// List of get accessors in %TypedArray%.prototype, excluding the '@@' properties. +// V(name, func, stubIndex) +// where BuiltinsSharedTypedArray::func refers to the native implementation. +#define BUILTIN_SHARED_TYPED_ARRAY_PROTOTYPE_GETTERS(V) \ + V("buffer", GetBuffer, INVALID) /* get %TypedArray%.prototype.buffer */ \ + V("byteLength", GetByteLength, TypedArrayGetByteLength) /* get %TypedArray%.prototype.byteLength */ \ + V("byteOffset", GetByteOffset, TypedArrayGetByteOffset) /* get %TypedArray%.prototype.byteOffset */ \ + V("length", GetLength, INVALID) /* get %TypedArray%.prototype.length */ + +// List of functions in %TypedArray%.prototype, excluding the constructor and '@@' properties. +// V(name, func, length, stubIndex) +// where BuiltinsSharedTypedArray::func refers to the native implementation of %TypedArray%.prototype[name]. +// The following functions are not included: +// - %TypedArray%.prototype.toString ( ), which is strictly equal to Array.prototype.toString +#define BUILTIN_SHARED_TYPED_ARRAY_PROTOTYPE_FUNCTIONS(V) \ + /* %TypedArray%.prototype.at ( index ) */ \ + V("at", At, 1, INVALID) \ + /* %TypedArray%.prototype.copyWithin ( target, start [ , end ] ) */ \ + V("copyWithin", CopyWithin, 2, INVALID) \ + /* %TypedArray%.prototype.entries ( ) */ \ + V("entries", Entries, 0, INVALID) \ + /* %TypedArray%.prototype.every ( callbackfn [ , thisArg ] ) */ \ + V("every", Every, 1, INVALID) \ + /* %TypedArray%.prototype.fill ( value [ , start [ , end ] ] ) */ \ + V("fill", Fill, 1, INVALID) \ + /* %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] ) */ \ + V("filter", Filter, 1, INVALID) \ + /* %TypedArray%.prototype.find ( predicate [ , thisArg ] ) */ \ + V("find", Find, 1, INVALID) \ + /* %TypedArray%.prototype.findIndex ( predicate [ , thisArg ] ) */ \ + V("findIndex", FindIndex, 1, INVALID) \ + /* %TypedArray%.prototype.forEach ( callbackfn [ , thisArg ] ) */ \ + V("forEach", ForEach, 1, INVALID) \ + /* %TypedArray%.prototype.includes ( searchElement [ , fromIndex ] ) */ \ + V("includes", Includes, 1, INVALID) \ + /* %TypedArray%.prototype.indexOf ( searchElement [ , fromIndex ] ) */ \ + V("indexOf", IndexOf, 1, INVALID) \ + /* %TypedArray%.prototype.join ( separator ) */ \ + V("join", Join, 1, INVALID) \ + /* %TypedArray%.prototype.keys ( ) */ \ + V("keys", Keys, 0, INVALID) \ + /* %TypedArray%.prototype.map ( callbackfn [ , thisArg ] ) */ \ + V("map", Map, 1, INVALID) \ + /* %TypedArray%.prototype.reduce ( callbackfn [ , initialValue ] ) */ \ + V("reduce", Reduce, 1, INVALID) \ + /* %TypedArray%.prototype.reverse ( ) */ \ + V("reverse", Reverse, 0, INVALID) \ + /* %TypedArray%.prototype.set ( source [ , offset ] ) */ \ + V("set", Set, 1, INVALID) \ + /* %TypedArray%.prototype.slice ( start, end ) */ \ + V("slice", Slice, 2, TypedArraySlice) \ + /* %TypedArray%.prototype.some ( callbackfn [ , thisArg ] ) */ \ + V("some", Some, 1, INVALID) \ + /* %TypedArray%.prototype.sort ( comparefn ) */ \ + V("sort", Sort, 1, INVALID) \ + /* %TypedArray%.prototype.subarray ( begin, end ) */ \ + V("subarray", Subarray, 2, TypedArraySubArray) \ + /* %TypedArray%.prototype.values ( ) */ \ + V("values", Values, 0, INVALID) + +namespace panda::ecmascript::builtins { +class BuiltinsSharedTypedArray : public base::BuiltinsBase { +public: + enum SeparatorFlag : int { MINUS_ONE = -1, MINUS_TWO = -2 }; + // 22.2.1 + static JSTaggedValue TypedArrayBaseConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Int8ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Uint8ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Uint8ClampedArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Int16ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Uint16ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Int32ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Uint32ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Float32ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue Float64ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue BigInt64ArrayConstructor(EcmaRuntimeCallInfo *argv); + static JSTaggedValue BigUint64ArrayConstructor(EcmaRuntimeCallInfo *argv); + + // 22.2.1.2.1 + static JSTaggedValue AllocateTypedArray(EcmaRuntimeCallInfo *argv); + + // 22.2.2.1 + static JSTaggedValue From(EcmaRuntimeCallInfo *argv); + // 22.2.2.2 + static JSTaggedValue Of(EcmaRuntimeCallInfo *argv); + // 22.2.2.4 + static JSTaggedValue Species(EcmaRuntimeCallInfo *argv); + + // prototype + // 22.2.3.1 + static JSTaggedValue GetBuffer(EcmaRuntimeCallInfo *argv); + // 22.2.3.2 + static JSTaggedValue GetByteLength(EcmaRuntimeCallInfo *argv); + // 22.2.3.3 + static JSTaggedValue GetByteOffset(EcmaRuntimeCallInfo *argv); + // 22.2.3.5 + static JSTaggedValue CopyWithin(EcmaRuntimeCallInfo *argv); + // 22.2.3.6 + static JSTaggedValue Entries(EcmaRuntimeCallInfo *argv); + // 22.2.3.7 + static JSTaggedValue Every(EcmaRuntimeCallInfo *argv); + // 22.2.3.8 + static JSTaggedValue Fill(EcmaRuntimeCallInfo *argv); + // 22.2.3.9 + static JSTaggedValue Filter(EcmaRuntimeCallInfo *argv); + // 22.2.3.10 + static JSTaggedValue Find(EcmaRuntimeCallInfo *argv); + // 22.2.3.11 + static JSTaggedValue FindIndex(EcmaRuntimeCallInfo *argv); + // 22.2.3.12 + static JSTaggedValue ForEach(EcmaRuntimeCallInfo *argv); + // 22.2.3.13 + static JSTaggedValue IndexOf(EcmaRuntimeCallInfo *argv); + // 22.2.3.14 + static JSTaggedValue Join(EcmaRuntimeCallInfo *argv); + // 22.2.3.15 + static JSTaggedValue Keys(EcmaRuntimeCallInfo *argv); + // 22.2.3.17 + static JSTaggedValue GetLength(EcmaRuntimeCallInfo *argv); + // 22.2.3.18 + static JSTaggedValue Map(EcmaRuntimeCallInfo *argv); + // 22.2.3.19 + static JSTaggedValue Reduce(EcmaRuntimeCallInfo *argv); + // 22.2.3.21 + static JSTaggedValue Reverse(EcmaRuntimeCallInfo *argv); + // 22.2.3.22 + static JSTaggedValue Set(EcmaRuntimeCallInfo *argv); + // 22.2.3.23 + static JSTaggedValue Slice(EcmaRuntimeCallInfo *argv); + // 22.2.3.24 + static JSTaggedValue Some(EcmaRuntimeCallInfo *argv); + // 22.2.3.25 + static JSTaggedValue Sort(EcmaRuntimeCallInfo *argv); + // 22.2.3.26 + static JSTaggedValue Subarray(EcmaRuntimeCallInfo *argv); + // 22.2.3.29 + static JSTaggedValue Values(EcmaRuntimeCallInfo *argv); + // 22.2.3.31 + static JSTaggedValue ToStringTag(EcmaRuntimeCallInfo *argv); + // es12 23.2.3.13 + static JSTaggedValue Includes(EcmaRuntimeCallInfo *argv); + // 23.2.3.1 + static JSTaggedValue At(EcmaRuntimeCallInfo *argv); + static const uint32_t MAX_ARRAY_INDEX = std::numeric_limits::max(); + + // Excluding the '@@' internal properties + static Span GetTypedArrayFunctions() + { + return Span(TYPED_ARRAY_FUNCTIONS); + } + + // Excluding the '@@' internal properties + static Span GetTypedArrayPrototypeAccessors() + { + return Span(TYPED_ARRAY_PROTOTYPE_ACCESSORS); + } + + // Excluding the constructor and '@@' internal properties. + static Span GetTypedArrayPrototypeFunctions() + { + return Span(TYPED_ARRAY_PROTOTYPE_FUNCTIONS); + } + + static size_t GetNumPrototypeInlinedProperties() + { + // 4 : 4 more inline properties in %TypedArray%.prototype for the following functions/accessors: + // (1) %TypedArray%.prototype.constructor + // (2) %TypedArray%.prototype.toString, which is strictly equal to Array.prototype.toString + // (3) %TypedArray%.prototype[@@iterator] + // (4) %TypedArray%.prototype[@@toStringTag] + return GetTypedArrayPrototypeFunctions().Size() + + GetTypedArrayPrototypeAccessors().Size() + 4; + } + + static Span> GetPrototypeProperties() + { + return Span>(TYPED_ARRAY_PROTOTYPE_PROPERTIES); + } + + static Span> GetFunctionProperties() + { + return Span>(TYPED_ARRAY_FUNCTION_PROPERTIES); + } + + static Span> GetSpecificFunctionProperties() + { + return Span>(SPECIFIC_TYPED_ARRAY_FUNCTION_PROPERTIES); + } + +private: +#define BUILTIN_TYPED_ARRAY_FUNCTION_ENTRY(name, func, length, id) \ + base::BuiltinFunctionEntry::Create(name, BuiltinsSharedTypedArray::func, length, kungfu::BuiltinsStubCSigns::id), +#define BUILTIN_TYPED_ARRAY_ACCESSOR_ENTRY(name, func, id) \ + base::BuiltinFunctionEntry::Create( \ + name, BuiltinsSharedTypedArray::func, 0, kungfu::BuiltinsStubCSigns::id), + + static constexpr std::array TYPED_ARRAY_FUNCTIONS = { + BUILTIN_SHARED_TYPED_ARRAY_FUNCTIONS(BUILTIN_TYPED_ARRAY_FUNCTION_ENTRY) + }; + static constexpr std::array TYPED_ARRAY_PROTOTYPE_ACCESSORS = { + BUILTIN_SHARED_TYPED_ARRAY_PROTOTYPE_GETTERS(BUILTIN_TYPED_ARRAY_ACCESSOR_ENTRY) + }; + static constexpr std::array TYPED_ARRAY_PROTOTYPE_FUNCTIONS = { + BUILTIN_SHARED_TYPED_ARRAY_PROTOTYPE_FUNCTIONS(BUILTIN_TYPED_ARRAY_FUNCTION_ENTRY) + }; + +#define TYPED_ARRAY_PROPERTIES_PAIR(name, func, length, id) \ + std::pair(name, false), + + static constexpr std::array TYPED_ARRAY_PROTOTYPE_PROPERTIES = { + std::pair("constructor", false), + BUILTIN_SHARED_TYPED_ARRAY_PROTOTYPE_FUNCTIONS(TYPED_ARRAY_PROPERTIES_PAIR) + std::pair("buffer", true), + std::pair("byteLength", true), + std::pair("byteOffset", true), + std::pair("length", true), + std::pair("toString", false), + std::pair("[Symbol.iterator]", false), + std::pair("[Symbol.toStringTag]", false), + }; + + static constexpr std::array TYPED_ARRAY_FUNCTION_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + BUILTIN_SHARED_TYPED_ARRAY_FUNCTIONS(TYPED_ARRAY_PROPERTIES_PAIR) + std::pair("[Symbol.species]", true), + }; + + static constexpr std::array SPECIFIC_TYPED_ARRAY_FUNCTION_PROPERTIES = { + std::pair("length", false), + std::pair("name", false), + std::pair("prototype", false), + std::pair("BYTES_PER_ELEMENT", false), + }; +#undef TYPED_ARRAY_PROPERTIES_PAIR + +#undef BUILTIN_TYPED_ARRAY_FUNCTION_ENTRY +#undef BUILTIN_TYPED_ARRAY_ACCESSOR_ENTRY +}; +} // namespace panda::ecmascript::builtins + +#endif // ECMASCRIPT_BUILTINS_BUILTINS_SHARED_TYPEDARRAY_H diff --git a/ecmascript/builtins/builtins_string.cpp b/ecmascript/builtins/builtins_string.cpp index 4a56a1aeb40a639526b88b8892b25bb63d4fce8d..999e68dd3688e179d7072bdb49d27391f3710265 100644 --- a/ecmascript/builtins/builtins_string.cpp +++ b/ecmascript/builtins/builtins_string.cpp @@ -39,9 +39,11 @@ #include "ecmascript/js_regexp.h" #include "ecmascript/js_string_iterator.h" #include "ecmascript/js_tagged_value-inl.h" +#include "ecmascript/js_tagged_value.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/object_factory.h" #include "ecmascript/property_detector-inl.h" +#include "ecmascript/shared_objects/js_shared_array.h" #include "ecmascript/tagged_array-inl.h" #include "ecmascript/tagged_array.h" #ifdef ARK_SUPPORT_INTL @@ -633,11 +635,15 @@ JSTaggedValue BuiltinsString::Match(EcmaRuntimeCallInfo *argv) JSHandle re(regexp); JSHandle pattern(thread, re->GetOriginalSource()); JSHandle flags(thread, re->GetOriginalFlags()); - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, thisTag, - RegExpExecResultCache::MATCH_TYPE, regexp, - JSTaggedValue(0)); - if (!cacheResult.IsUndefined()) { - return cacheResult; + bool isFastPath = BuiltinsRegExp::IsFastRegExp(thread, regexp); + if (isFastPath) { + uint32_t lastIndex = static_cast(BuiltinsRegExp::GetLastIndex(thread, regexp, true)); + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, thisTag, + RegExpExecResultCache::MATCH_TYPE, regexp, + JSTaggedValue(lastIndex)); + if (!cacheResult.IsUndefined()) { + return cacheResult; + } } } if (!regexp->IsUndefined() && !regexp->IsNull()) { @@ -786,6 +792,7 @@ JSTaggedValue BuiltinsString::IsWellFormed(EcmaRuntimeCallInfo *argv) } else { position = position + codeUnitCount; } + thread->CheckSafepointIfSuspended(); } return JSTaggedValue::True(); } @@ -876,6 +883,7 @@ JSTaggedValue BuiltinsString::ToWellFormed(EcmaRuntimeCallInfo *argv) } } position = position + codeUnitCount; + thread->CheckSafepointIfSuspended(); } const char16_t *constChar16tData = r.data(); auto *char16tData = const_cast(constChar16tData); @@ -1028,18 +1036,19 @@ JSTaggedValue BuiltinsString::Replace(EcmaRuntimeCallInfo *argv) ObjectFactory *factory = ecmaVm->GetFactory(); if (searchTag->IsJSRegExp() && replaceTag->IsString()) { - if (BuiltinsRegExp::IsValidRegularExpression(thread, searchTag) == JSTaggedValue::False()) { - THROW_SYNTAX_ERROR_AND_RETURN(thread, "Regular expression too large", JSTaggedValue::Exception()); - } JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetRegExpCache()); JSHandle re(searchTag); JSHandle pattern(thread, re->GetOriginalSource()); JSHandle flags(thread, re->GetOriginalFlags()); - JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, pattern, flags, thisTag, - RegExpExecResultCache::REPLACE_TYPE, searchTag, - replaceTag.GetTaggedValue()); - if (!cacheResult.IsUndefined()) { - return cacheResult; + bool isFastPath = BuiltinsRegExp::IsFastRegExp(thread, searchTag); + if (isFastPath) { + uint32_t lastIndex = static_cast(BuiltinsRegExp::GetLastIndex(thread, searchTag, true)); + JSTaggedValue cacheResult = cacheTable->FindCachedResult(thread, thisTag, + RegExpExecResultCache::REPLACE_TYPE, searchTag, JSTaggedValue(lastIndex), + replaceTag.GetTaggedValue()); + if (!cacheResult.IsUndefined()) { + return cacheResult; + } } } @@ -1266,6 +1275,7 @@ JSTaggedValue BuiltinsString::ReplaceAll(EcmaRuntimeCallInfo *argv) stringBuilder = stringBuilder + stringPrefixString + stringRealReplaceStr; endOfLastMatch = pos + searchLength; pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, searchString, pos + advanceBy); + thread->CheckSafepointIfSuspended(); } if (endOfLastMatch < static_cast(EcmaStringAccessor(thisString).GetLength())) { @@ -1465,6 +1475,7 @@ JSTaggedValue BuiltinsString::GetSubstitution(JSThread *thread, const JSHandleCheckSafepointIfSuspended(); } LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -1481,6 +1492,11 @@ JSTaggedValue BuiltinsString::Search(EcmaRuntimeCallInfo *argv) JSHandle thisTag(JSTaggedValue::RequireObjectCoercible(thread, GetThis(argv))); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle regexp = BuiltinsString::GetCallArg(argv, 0); + if (thisTag->IsString() && regexp->IsECMAObject()) { + if (BuiltinsRegExp::IsFastRegExp(thread, regexp)) { + return BuiltinsRegExp::RegExpSearchFast(thread, regexp, thisTag); + } + } JSHandle searchTag = thread->GetEcmaVM()->GetGlobalEnv()->GetSearchSymbol(); JSHandle undefined = globalConst->GetHandledUndefined(); if (!regexp->IsUndefined() && !regexp->IsNull()) { @@ -1563,6 +1579,13 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle seperatorTag = BuiltinsString::GetCallArg(argv, 0); JSHandle limitTag = BuiltinsString::GetCallArg(argv, 1); + + if (thisTag->IsString() && seperatorTag->IsECMAObject()) { + // this condition need change, all regexp should use RegExpSplit + if (BuiltinsRegExp::IsFastRegExp(thread, seperatorTag)) { + return BuiltinsRegExp::RegExpSplit(thread, seperatorTag, thisTag, limitTag, true); + } + } if (thisTag->IsString() && seperatorTag->IsString()) { JSHandle thisString(thisTag); JSHandle seperatorString(seperatorTag); @@ -1644,16 +1667,41 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv) JSTaggedValue BuiltinsString::CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm, const JSHandle &thisString, uint32_t thisLength, uint32_t lim) { + bool isUtf8 = EcmaStringAccessor(thisString).IsUtf8(); + bool canBeCompressed = false; + if (EcmaStringAccessor(thisString).IsLineString() || EcmaStringAccessor(thisString).IsConstantString()) { + canBeCompressed = EcmaStringAccessor::CanBeCompressed(*thisString); + } + bool isOneByte = isUtf8 & canBeCompressed; + JSHandle seperatorString = thread->GetEcmaVM()->GetFactory()->GetEmptyString(); + if (lim == UINT32_MAX - 1) { + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetStringSplitResultCache()); + JSTaggedValue cacheResult = StringSplitResultCache::FindCachedResult(thread, cacheTable, thisString, + seperatorString, isOneByte); + if (cacheResult != JSTaggedValue::Undefined()) { + JSHandle resultArray(JSArray::CreateArrayFromList(thread, + JSHandle(thread, cacheResult))); + return resultArray.GetTaggedValue(); + } + } uint32_t actualLength = std::min(thisLength, lim); - JSHandle resultArray(JSArray::ArrayCreate(thread, JSTaggedNumber(actualLength))); - RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle array = factory->NewTaggedArray(actualLength); for (uint32_t i = 0; i < actualLength; ++i) { - EcmaString *elementString = EcmaStringAccessor::FastSubString(ecmaVm, thisString, i, 1); - JSHandle elementTag(thread, elementString); + EcmaString *elementString = EcmaStringAccessor::GetSubString(ecmaVm, thisString, i, 1); // Perform CreateDataProperty(A, "0", S), CreateDataProperty's fast path - JSObject::CreateDataProperty(thread, resultArray, i, elementTag); + if (isOneByte) { + array->Set(thread, i, JSTaggedValue(elementString)); + } else { + array->Set(thread, i, JSTaggedValue(elementString)); + } ASSERT_PRINT(!thread->HasPendingException(), "CreateDataProperty can't throw exception"); } + JSHandle resultArray = JSArray::CreateArrayFromList(thread, array); + if (lim == UINT32_MAX - 1) { + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetStringSplitResultCache()); + StringSplitResultCache::SetCachedResult(thread, cacheTable, thisString, seperatorString, array); + } return resultArray.GetTaggedValue(); } @@ -1708,6 +1756,7 @@ JSTaggedValue BuiltinsString::CreateArrayThisStringAndSeperatorStringAreNotEmpty } index = pos + static_cast(seperatorLength); pos = EcmaStringAccessor::IndexOf(ecmaVm, thisString, seperatorString, index); + thread->CheckSafepointIfSuspended(); } uint32_t posArrLength = posArray.size(); arrayLength = lim > posArrLength ? posArrLength + 1 : posArrLength; @@ -2282,6 +2331,7 @@ JSTaggedValue BuiltinsString::StringToList(JSThread *thread, JSHandle newStr = factory->NewFromUtf16Literal(&c, 1); ElementAccessor::Set(thread, newArrayHandle, index, newStr, true); index++; + thread->CheckSafepointIfSuspended(); } JSHandle(newArrayHandle)->SetArrayLength(thread, totalElements); @@ -2290,6 +2340,43 @@ JSTaggedValue BuiltinsString::StringToList(JSThread *thread, JSHandle &str) +{ + JSHandle cacheTable(thread->GetCurrentEcmaContext()->GetStringToListResultCache()); + JSTaggedValue cacheResult = StringToListResultCache::FindCachedResult(thread, cacheTable, str); + if (cacheResult != JSTaggedValue::Undefined()) { + JSHandle resultArray( + JSSharedArray::CreateArrayFromList(thread, JSHandle(thread, cacheResult))); + return resultArray.GetTaggedValue(); + } + + JSTaggedValue newSharedArray = JSSharedArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue(); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle newSharedArrayHandle(thread, newSharedArray); + JSHandle iteratedString(str); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle oldElements(thread, newSharedArrayHandle->GetElements()); + uint32_t totalElements = EcmaStringAccessor(iteratedString).GetLength(); + JSHandle elements = + (oldElements->GetLength() < totalElements) + ? factory->ExtendArray(oldElements, totalElements, JSTaggedValue::Hole(), MemSpaceType::SHARED_OLD_SPACE) + : oldElements; + uint32_t index = 0; + newSharedArrayHandle->SetElements(thread, elements); + while (index < totalElements) { + uint16_t c = EcmaStringAccessor(iteratedString).Get(index); + JSHandle newStr = factory->NewFromUtf16Literal(&c, 1); + ElementAccessor::Set(thread, newSharedArrayHandle, index, newStr, true); + index++; + thread->CheckSafepointIfSuspended(); + } + JSHandle(newSharedArrayHandle)->SetArrayLength(thread, totalElements); + + StringToListResultCache::SetCachedResult(thread, cacheTable, str, elements); + newSharedArrayHandle->GetJSHClass()->SetExtensible(false); + return newSharedArrayHandle.GetTaggedValue(); +} + JSTaggedValue StringSplitResultCache::CreateCacheTable(const JSThread *thread) { int length = CACHE_SIZE * ENTRY_SIZE; @@ -2300,7 +2387,7 @@ JSTaggedValue StringSplitResultCache::CreateCacheTable(const JSThread *thread) JSTaggedValue StringSplitResultCache::FindCachedResult(const JSThread *thread, const JSHandle &cache, const JSHandle &thisString, - const JSHandle &pattern) + const JSHandle &pattern, bool isOneByte) { uint32_t hash = EcmaStringAccessor(thisString).GetHashcode(); uint32_t entry = hash & (CACHE_SIZE - 1); @@ -2318,8 +2405,12 @@ JSTaggedValue StringSplitResultCache::FindCachedResult(const JSThread *thread, JSHandle cacheArray(thread, cache->Get(index + ARRAY_INDEX)); uint32_t arrayLength = cacheArray->GetLength(); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle copyArray = factory->NewAndCopyTaggedArray(cacheArray, - arrayLength, arrayLength); + JSHandle copyArray; + if (isOneByte) { + copyArray = factory->NewAndCopyTaggedArraySkipBarrier(cacheArray, arrayLength, arrayLength); + } else { + copyArray = factory->NewAndCopyTaggedArray(cacheArray, arrayLength, arrayLength); + } return copyArray.GetTaggedValue(); } return JSTaggedValue::Undefined(); diff --git a/ecmascript/builtins/builtins_string.h b/ecmascript/builtins/builtins_string.h index 6757229938881e7bdfa23a47f47c1796f6f338df..adb3b838a5d49674de284bc673fa6a2388d7f24d 100644 --- a/ecmascript/builtins/builtins_string.h +++ b/ecmascript/builtins/builtins_string.h @@ -58,7 +58,7 @@ /* String.prototype.lastIndexOf ( searchString [ , position ] ) */ \ V("lastIndexOf", LastIndexOf, 1, INVALID) \ /* String.prototype.localeCompare ( that [ , reserved1 [ , reserved2 ] ] ) */ \ - V("localeCompare", LocaleCompare, 1, LocaleCompare) \ + V("localeCompare", LocaleCompare, 1, StringLocaleCompare) \ /* String.prototype.match ( regexp ) */ \ V("match", Match, 1, INVALID) \ /* String.prototype.matchAll ( regexp ) */ \ @@ -254,6 +254,7 @@ public: return GetStringPrototypeFunctions().Size() + 3; } static JSTaggedValue StringToList(JSThread *thread, JSHandle &str); + static JSTaggedValue StringToSList(JSThread *thread, JSHandle &str); private: #define BUILTIN_STRING_FUNCTION_ENTRY(name, method, length, builtinId) \ @@ -270,7 +271,7 @@ private: static JSTaggedValue Pad(EcmaRuntimeCallInfo *argv, bool isStart); static int32_t ConvertDoubleToInt(double d); static JSTaggedValue CreateArrayFromString(JSThread *thread, EcmaVM *ecmaVm, - const JSHandle &thisString, uint32_t thisLength, uint32_t lim); + const JSHandle &thisString, uint32_t thisLength, uint32_t lim = UINT32_MAX - 1); static JSTaggedValue CreateArrayBySplitString(JSThread *thread, EcmaVM *ecmaVm, const JSHandle &thisString, const JSHandle &seperatorString, uint32_t thisLength, uint32_t seperatorLength, uint32_t lim); @@ -298,7 +299,7 @@ public: } static JSTaggedValue CreateCacheTable(const JSThread *thread); static JSTaggedValue FindCachedResult(const JSThread *thread, const JSHandle &cache, - const JSHandle &string, const JSHandle &pattern); + const JSHandle &string, const JSHandle &pattern, bool isOneByte = false); static void SetCachedResult(const JSThread *thread, const JSHandle &cache, const JSHandle &string, const JSHandle &pattern, const JSHandle &result); diff --git a/ecmascript/builtins/builtins_typedarray.h b/ecmascript/builtins/builtins_typedarray.h index e89ecd6a5c68967ce5237e1e9c27cf0baf82cb6d..bc4d8a9ddc67e60d3cec74942bef9421b0715d40 100644 --- a/ecmascript/builtins/builtins_typedarray.h +++ b/ecmascript/builtins/builtins_typedarray.h @@ -82,7 +82,7 @@ /* %TypedArray%.prototype.fill ( value [ , start [ , end ] ] ) */ \ V("fill", Fill, 1, INVALID) \ /* %TypedArray%.prototype.filter ( callbackfn [ , thisArg ] ) */ \ - V("filter", Filter, 1, INVALID) \ + V("filter", Filter, 1, TypedArrayFilter) \ /* %TypedArray%.prototype.find ( predicate [ , thisArg ] ) */ \ V("find", Find, 1, INVALID) \ /* %TypedArray%.prototype.findIndex ( predicate [ , thisArg ] ) */ \ @@ -114,7 +114,7 @@ /* %TypedArray%.prototype.set ( source [ , offset ] ) */ \ V("set", Set, 1, INVALID) \ /* %TypedArray%.prototype.slice ( start, end ) */ \ - V("slice", Slice, 2, INVALID) \ + V("slice", Slice, 2, TypedArraySlice) \ /* %TypedArray%.prototype.some ( callbackfn [ , thisArg ] ) */ \ V("some", Some, 1, INVALID) \ /* %TypedArray%.prototype.sort ( comparefn ) */ \ diff --git a/ecmascript/builtins/shared_builtins.cpp b/ecmascript/builtins/shared_builtins.cpp index b9344cf978a260982fc808b56202d53ece52c935..ada596b86a6e99e217797769919aa9cf09991865 100644 --- a/ecmascript/builtins/shared_builtins.cpp +++ b/ecmascript/builtins/shared_builtins.cpp @@ -17,14 +17,34 @@ #include "ecmascript/builtins/builtins_function.h" #include "ecmascript/builtins/builtins_object.h" +#include "ecmascript/builtins/builtins_symbol.h" +#include "ecmascript/builtins/builtins_sendable_arraybuffer.h" #include "ecmascript/builtins/builtins_shared_function.h" #include "ecmascript/builtins/builtins_shared_object.h" +#include "ecmascript/builtins/builtins_shared_map.h" +#include "ecmascript/builtins/builtins_shared_set.h" +#include "ecmascript/builtins/builtins_shared_typedarray.h" +#include "ecmascript/shared_objects/js_shared_array.h" +#include "ecmascript/shared_objects/js_sendable_arraybuffer.h" +#include "ecmascript/shared_objects/js_shared_map.h" +#include "ecmascript/shared_objects/js_shared_object.h" +#include "ecmascript/shared_objects/js_shared_set.h" +#include "ecmascript/shared_objects/js_shared_typed_array.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/symbol_table.h" +#include "ecmascript/builtins/builtins_shared_array.h" namespace panda::ecmascript { using BuiltinsSharedObject = builtins::BuiltinsSharedObject; using BuiltinsSharedFunction = builtins::BuiltinsSharedFunction; using Function = builtins::BuiltinsFunction; using Object = builtins::BuiltinsObject; +using BuiltinsSharedSet = builtins::BuiltinsSharedSet; +using BuiltinsSharedMap = builtins::BuiltinsSharedMap; +using BuiltinsSharedArray = builtins::BuiltinsSharedArray; +using BuiltinsSharedTypedArray = builtins::BuiltinsSharedTypedArray; +using BuiltinsSendableArrayBuffer = builtins::BuiltinsSendableArrayBuffer; void Builtins::InitializeSObjectAndSFunction(const JSHandle &env) const { @@ -32,23 +52,28 @@ void Builtins::InitializeSObjectAndSFunction(const JSHandle &env) con // SharedObject.prototype[hclass] JSHandle sobjPrototypeHClass = CreateSObjectPrototypeHClass(); // SharedObject.prototype - JSHandle sObjFuncPrototype = + JSHandle sObjPrototype = factory_->NewSharedOldSpaceJSObject(sobjPrototypeHClass); - JSHandle sObjFuncPrototypeVal(sObjFuncPrototype); + JSHandle sObjPrototypeVal(sObjPrototype); // SharedObject.prototype_or_hclass auto emptySLayout = thread_->GlobalConstants()->GetHandledEmptySLayoutInfo(); JSHandle sObjIHClass = - factory_->NewSEcmaHClass(JSSharedObject::SIZE, 0, JSType::JS_SHARED_OBJECT, sObjFuncPrototypeVal, + factory_->NewSEcmaHClass(JSSharedObject::SIZE, 0, JSType::JS_SHARED_OBJECT, sObjPrototypeVal, emptySLayout); // SharedFunction.prototype_or_hclass - JSHandle sFuncPrototypeHClass = CreateSFunctionPrototypeHClass(sObjFuncPrototypeVal); + JSHandle sFuncPrototypeHClass = CreateSFunctionPrototypeHClass(sObjPrototypeVal); // SharedFunction.prototype JSHandle sFuncPrototype = factory_->NewSFunctionByHClass( reinterpret_cast(Function::FunctionPrototypeInvokeSelf), sFuncPrototypeHClass, FunctionKind::NORMAL_FUNCTION); InitializeSFunction(env, sFuncPrototype); - InitializeSObject(env, sObjIHClass, sObjFuncPrototype, sFuncPrototype); - env->SetSObjectFunctionPrototype(thread_, sObjFuncPrototype); + InitializeSObject(env, sObjIHClass, sObjPrototype, sFuncPrototype); + InitializeSSet(env, sObjPrototype, sFuncPrototype); + InitializeSMap(env, sObjPrototype, sFuncPrototype); + InitializeSharedArray(env, sObjPrototype, sFuncPrototype); + InitializeSTypedArray(env, sObjPrototype, sFuncPrototype); + InitializeSArrayBuffer(env, sObjPrototype, sFuncPrototype); + env->SetSObjectFunctionPrototype(thread_, sObjPrototype); } void Builtins::CopySObjectAndSFunction(const JSHandle &env, const JSTaggedValue &srcEnv) const @@ -63,7 +88,7 @@ void Builtins::CopySObjectAndSFunction(const JSHandle &env, const JST } void Builtins::InitializeSObject(const JSHandle &env, const JSHandle &sObjIHClass, - const JSHandle &sObjFuncPrototype, + const JSHandle &sObjPrototype, const JSHandle &sFuncPrototype) const { [[maybe_unused]] EcmaHandleScope scope(thread_); @@ -83,9 +108,9 @@ void Builtins::InitializeSObject(const JSHandle &env, const JSHandle< } // sObject.prototype method fieldIndex = 0; // constructor - sObjFuncPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, sObjectFunction.GetTaggedValue()); + sObjPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, sObjectFunction.GetTaggedValue()); for (const base::BuiltinFunctionEntry &entry : Object::GetObjectPrototypeFunctions()) { - SetSFunction(env, sObjFuncPrototype, entry.GetName(), entry.GetEntrypoint(), fieldIndex++, entry.GetLength(), + SetSFunction(env, sObjPrototype, entry.GetName(), entry.GetEntrypoint(), fieldIndex++, entry.GetLength(), entry.GetBuiltinStubId()); } // B.2.2.1 sObject.prototype.__proto__ @@ -93,7 +118,199 @@ void Builtins::InitializeSObject(const JSHandle &env, const JSHandle< CreateSGetterSetter(env, Object::ProtoGetter, "__proto__", FunctionLength::ZERO); JSHandle protoSetter = CreateSGetterSetter(env, Object::ProtoSetter, "__proto__", FunctionLength::ONE); - SetSAccessor(sObjFuncPrototype, fieldIndex, protoGetter, protoSetter); + SetSAccessor(sObjPrototype, fieldIndex, protoGetter, protoSetter); +} + +void Builtins::InitializeSArrayBuffer(const JSHandle &env, const JSHandle &sObjPrototype, + const JSHandle &sFuncPrototype) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + // SendableArrayBuffer.prototype + JSHandle arrayBufferPrototypeHClass = CreateSArrayBufferPrototypeHClass(sObjPrototype); + JSHandle arrayBufferPrototype = + factory_->NewSharedOldSpaceJSObjectWithInit(arrayBufferPrototypeHClass); + + JSHandle arrayBufferPrototypeValue(arrayBufferPrototype); + + // SendableArrayBuffer.prototype_or_hclass + auto emptySLayout = globalConst->GetHandledEmptySLayoutInfo(); + JSHandle arrayBufferIHClass = factory_->NewSEcmaHClass( + JSSendableArrayBuffer::SIZE, 0, JSType::JS_SENDABLE_ARRAY_BUFFER, arrayBufferPrototypeValue, emptySLayout); + + // SendableArrayBuffer = new Function() + JSHandle arrayBufferFuncHClass = CreateSArrayBufferFunctionHClass(sFuncPrototype); + + JSHandle arrayBufferFunction = + factory_->NewSFunctionByHClass(reinterpret_cast(BuiltinsSendableArrayBuffer::ArrayBufferConstructor), + arrayBufferFuncHClass, FunctionKind::BUILTIN_CONSTRUCTOR); + + InitializeSCtor(arrayBufferIHClass, arrayBufferFunction, "SendableArrayBuffer", FunctionLength::ONE); + JSHandle globalObject(thread_, env->GetGlobalObject()); + JSHandle nameString(factory_->NewFromUtf8("SendableArrayBuffer")); + PropertyDescriptor desc(thread_, JSHandle::Cast(arrayBufferFunction), true, false, true); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + RETURN_IF_ABRUPT_COMPLETION(thread_); + + // SendableArrayBuffer prototype method + uint32_t fieldIndex = 0; + SetSFunction(env, arrayBufferPrototype, "slice", + BuiltinsSendableArrayBuffer::Slice, fieldIndex++, FunctionLength::TWO); + + // 24.1.4.1 get SendableArrayBuffer.prototype.byteLength + JSHandle lengthGetter = + CreateSGetterSetter(env, BuiltinsSendableArrayBuffer::GetByteLength, "byteLength", FunctionLength::ZERO); + SetSAccessor( + JSHandle(arrayBufferPrototype), fieldIndex++, lengthGetter, globalConst->GetHandledUndefined()); + + // 24.1.4.4 SendableArrayBuffer.prototype[@@toStringTag] + JSHandle strTag(factory_->NewFromUtf8("SendableArrayBuffer")); + arrayBufferPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, strTag.GetTaggedValue()); + + // 24.1.3.3 get SendableArrayBuffer[@@species] + fieldIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX + 1; + JSHandle speciesGetter = + CreateSGetterSetter(env, BuiltinsSendableArrayBuffer::Species, "[Symbol.species]", FunctionLength::ZERO); + SetSAccessor( + JSHandle(arrayBufferFunction), fieldIndex++, speciesGetter, globalConst->GetHandledUndefined()); + + // SendableArrayBuffer method + for (const base::BuiltinFunctionEntry& entry: BuiltinsSendableArrayBuffer::GetArrayBufferFunctions()) { + SetSFunction(env, JSHandle(arrayBufferFunction), entry.GetName(), entry.GetEntrypoint(), fieldIndex++, + entry.GetLength(), entry.GetBuiltinStubId()); + } + + env->SetSendableArrayBufferPrototype(thread_, arrayBufferPrototype); + env->SetSBuiltininArrayBufferFunction(thread_, arrayBufferFunction); +} + +void Builtins::InitializeSSet(const JSHandle &env, const JSHandle &sObjPrototype, + const JSHandle &sFuncPrototype) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + // SharedSet.prototype + JSHandle setPrototypeHClass = CreateSSetPrototypeHClass(sObjPrototype); + JSHandle setPrototype = + factory_->NewSharedOldSpaceJSObjectWithInit(setPrototypeHClass); + + JSHandle setPrototypeValue(setPrototype); + // SharedSet.prototype_or_hclass + auto emptySLayout = globalConst->GetHandledEmptySLayoutInfo(); + JSHandle setIHClass = + factory_->NewSEcmaHClass(JSSharedSet::SIZE, 0, JSType::JS_SHARED_SET, setPrototypeValue, emptySLayout); + // SharedSet.hclass + JSHandle setFuncHClass = CreateSSetFunctionHClass(sFuncPrototype); + // SharedSet() = new Function() + JSHandle setFunction = + factory_->NewSFunctionByHClass(reinterpret_cast(BuiltinsSharedSet::Constructor), + setFuncHClass, FunctionKind::BUILTIN_CONSTRUCTOR); + + InitializeSCtor(setIHClass, setFunction, "SharedSet", FunctionLength::ZERO); + JSHandle globalObject(thread_, env->GetGlobalObject()); + JSHandle nameString(factory_->NewFromUtf8("SharedSet")); + PropertyDescriptor desc(thread_, JSHandle::Cast(setFunction), true, false, true); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + RETURN_IF_ABRUPT_COMPLETION(thread_); + + // "constructor" property on the prototype + uint32_t fieldIndex = 0; // constructor + setPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, setFunction.GetTaggedValue()); + + // SharedSet.prototype functions, excluding keys() + for (const base::BuiltinFunctionEntry &entry: BuiltinsSharedSet::GetSetPrototypeFunctions()) { + SetSFunction(env, setPrototype, entry.GetName(), entry.GetEntrypoint(), fieldIndex++, + entry.GetLength(), entry.GetBuiltinStubId()); + } + // SharedSet.prototype.keys, which is strictly equal to Set.prototype.values + JSHandle keys(factory_->NewFromASCII("keys")); + JSHandle values(factory_->NewFromASCII("values")); + JSHandle valuesFunc = + JSObject::GetMethod(thread_, JSHandle::Cast(setPrototype), values); + RETURN_IF_ABRUPT_COMPLETION(thread_); + setPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, valuesFunc.GetTaggedValue()); + + // @@ToStringTag + JSHandle strTag(factory_->NewFromUtf8("SharedSet")); + setPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, strTag.GetTaggedValue()); + + // 23.1.3.10get SharedSet.prototype.size + JSHandle sizeGetter = CreateSGetterSetter(env, BuiltinsSharedSet::GetSize, "size", + FunctionLength::ZERO); + SetSAccessor(setPrototype, fieldIndex++, sizeGetter, globalConst->GetHandledUndefined()); + + // %SetPrototype% [ @@iterator ] + setPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, valuesFunc.GetTaggedValue()); + + fieldIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX + 1; + // 23.1.2.2get SharedSet [ @@species ] + JSHandle speciesGetter = + CreateSGetterSetter(env, BuiltinsSharedSet::Species, "[Symbol.species]", FunctionLength::ZERO); + SetSAccessor(JSHandle(setFunction), fieldIndex, speciesGetter, globalConst->GetHandledUndefined()); + + env->SetSharedSetPrototype(thread_, setPrototype); + env->SetSBuiltininSetFunction(thread_, setFunction); +} + +void Builtins::InitializeSMap(const JSHandle &env, const JSHandle &sObjPrototype, + const JSHandle &sFuncPrototype) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + // SharedMap.prototype + JSHandle mapPrototypeHClass = CreateSMapPrototypeHClass(sObjPrototype); + JSHandle mapPrototype = + factory_->NewSharedOldSpaceJSObjectWithInit(mapPrototypeHClass); + JSHandle mapPrototypeValue(mapPrototype); + // SharedMap.prototype_or_hclass + auto emptySLayout = globalConst->GetHandledEmptySLayoutInfo(); + JSHandle mapIHClass = + factory_->NewSEcmaHClass(JSSharedMap::SIZE, 0, JSType::JS_SHARED_MAP, mapPrototypeValue, emptySLayout); + // SharedMap.hclass + JSHandle mapFuncHClass = CreateSMapFunctionHClass(sFuncPrototype); + // SharedMap() = new Function() + JSHandle mapFunction = + factory_->NewSFunctionByHClass(reinterpret_cast(BuiltinsSharedMap::Constructor), + mapFuncHClass, FunctionKind::BUILTIN_CONSTRUCTOR); + InitializeSCtor(mapIHClass, mapFunction, "SharedMap", FunctionLength::ZERO); + JSHandle globalObject(thread_, env->GetGlobalObject()); + JSHandle nameString(factory_->NewFromUtf8("SharedMap")); + PropertyDescriptor desc(thread_, JSHandle::Cast(mapFunction), true, false, true); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + RETURN_IF_ABRUPT_COMPLETION(thread_); + + // "constructor" property on the prototype + uint32_t fieldIndex = 0; // constructor + mapPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, mapFunction.GetTaggedValue()); + // SharedMap.prototype functions + for (const base::BuiltinFunctionEntry &entry: BuiltinsSharedMap::GetMapPrototypeFunctions()) { + SetSFunction(env, mapPrototype, entry.GetName(), entry.GetEntrypoint(), fieldIndex++, + entry.GetLength(), entry.GetBuiltinStubId()); + } + // @@ToStringTag + JSHandle strTag(factory_->NewFromUtf8("SharedMap")); + mapPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, strTag.GetTaggedValue()); + + // 23.1.3.10get SharedMap.prototype.size + JSHandle sizeGetter = CreateSGetterSetter(env, BuiltinsSharedMap::GetSize, "size", + FunctionLength::ZERO); + SetSAccessor(mapPrototype, fieldIndex++, sizeGetter, globalConst->GetHandledUndefined()); + + // %MapPrototype% [ @@iterator ] + JSHandle entries(factory_->NewFromASCII("entries")); + JSHandle entriesFunc = + JSObject::GetMethod(thread_, JSHandle::Cast(mapPrototype), entries); + RETURN_IF_ABRUPT_COMPLETION(thread_); + mapPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, entriesFunc.GetTaggedValue()); + + fieldIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX + 1; + // 23.1.2.2get SharedMap [ @@species ] + JSHandle speciesGetter = + CreateSGetterSetter(env, BuiltinsSharedMap::Species, "[Symbol.species]", FunctionLength::ZERO); + SetSAccessor(JSHandle(mapFunction), fieldIndex, speciesGetter, globalConst->GetHandledUndefined()); + + env->SetSharedMapPrototype(thread_, mapPrototype); + env->SetSBuiltininMapFunction(thread_, mapFunction); } void Builtins::InitializeSFunction(const JSHandle &env, @@ -147,7 +364,6 @@ void Builtins::InitializeSFunction(const JSHandle &env, Function::FunctionPrototypeHasInstance, fieldIndex++, FunctionLength::ONE); } - JSHandle Builtins::CreateSObjectFunctionHClass(const JSHandle &sFuncPrototype) const { uint32_t index = 0; @@ -219,7 +435,94 @@ JSHandle Builtins::CreateSFunctionHClass(const JSHandle &s return sobjPrototypeHClass; } -JSHandle Builtins::CreateSFunctionPrototypeHClass(const JSHandle &sObjFuncPrototypeVal) const +JSHandle Builtins::CreateSArrayBufferFunctionHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSendableArrayBuffer::GetFunctionProperties(); + uint32_t length = properties.size(); + JSHandle keyString; + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.species]") { + keyString = env->GetSpeciesSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + +JSHandle Builtins::CreateSSetFunctionHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedSet::GetFunctionProperties(); + uint32_t length = properties.size(); + JSHandle keyString; + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.species]") { + keyString = env->GetSpeciesSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + +JSHandle Builtins::CreateSMapFunctionHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedMap::GetFunctionProperties(); + uint32_t length = properties.size(); + JSHandle keyString; + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.species]") { + keyString = env->GetSpeciesSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + +JSHandle Builtins::CreateSFunctionPrototypeHClass(const JSHandle &sObjPrototypeVal) const { uint32_t index = 0; auto env = vm_->GetGlobalEnv(); @@ -241,12 +544,164 @@ JSHandle Builtins::CreateSFunctionPrototypeHClass(const JSHandleAddKey(thread_, index++, keyString.GetTaggedValue(), attributes); } JSHandle sobjPrototypeHClass = - factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, sObjFuncPrototypeVal, + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, sObjPrototypeVal, JSHandle(layout)); sobjPrototypeHClass->SetCallable(true); return sobjPrototypeHClass; } +JSHandle Builtins::CreateSArrayBufferPrototypeHClass(const JSHandle &sObjPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSendableArrayBuffer::GetPrototypeProperties(); + uint32_t length = properties.size(); + ASSERT(length == BuiltinsSendableArrayBuffer::GetNumPrototypeInlinedProperties()); + JSHandle layout = factory_->CreateSLayoutInfo(length); + JSHandle keyString; + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.toStringTag]") { + keyString = env->GetToStringTagSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sArrayBufferPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT, + JSHandle(sObjPrototype), + JSHandle(layout)); + return sArrayBufferPrototypeHClass; +} + +JSHandle Builtins::CreateSSetPrototypeHClass(const JSHandle &sObjPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedSet::GetPrototypeProperties(); + uint32_t length = properties.size(); + ASSERT(length == BuiltinsSharedSet::GetNumPrototypeInlinedProperties()); + JSHandle layout = factory_->CreateSLayoutInfo(length); + JSHandle keyString; + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.iterator]") { + keyString = env->GetIteratorSymbol(); + } else if (key == "[Symbol.toStringTag]") { + keyString = env->GetToStringTagSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sSetPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT, + JSHandle(sObjPrototype), + JSHandle(layout)); + return sSetPrototypeHClass; +} + +JSHandle Builtins::CreateSMapPrototypeHClass(const JSHandle &sObjPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedMap::GetPrototypeProperties(); + uint32_t length = properties.size(); + ASSERT(length == BuiltinsSharedMap::GetNumPrototypeInlinedProperties()); + JSHandle layout = factory_->CreateSLayoutInfo(length); + JSHandle keyString; + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.iterator]") { + keyString = env->GetIteratorSymbol(); + } else if (key == "[Symbol.toStringTag]") { + keyString = env->GetToStringTagSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sMapPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT, + JSHandle(sObjPrototype), + JSHandle(layout)); + return sMapPrototypeHClass; +} + +JSHandle Builtins::CreateSArrayPrototypeHClass(const JSHandle &sObjPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedArray::GetPrototypeProperties(); + uint32_t length = properties.size(); + ASSERT(length == BuiltinsSharedArray::GetNumPrototypeInlinedProperties()); + JSHandle layout = factory_->CreateSLayoutInfo(length); + JSHandle keyString; + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.iterator]") { + keyString = env->GetIteratorSymbol(); + } else if (key == "[Symbol.toStringTag]") { + keyString = env->GetToStringTagSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sArrayPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedArray::SIZE, length, JSType::JS_SHARED_ARRAY, + JSHandle(sObjPrototype), + JSHandle(layout)); + return sArrayPrototypeHClass; +} + +JSHandle Builtins::CreateSArrayFunctionHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedArray::GetFunctionProperties(); + uint32_t length = properties.size(); + JSHandle keyString; + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const auto &[key, isAccessor] : properties) { + LOG_ECMA(DEBUG) << "CreateSArrayFunctionHClass " << key; + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.species]") { + keyString = env->GetSpeciesSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + void Builtins::SetSFunctionName(const JSHandle &ctor, std::string_view name) const { JSHandle nameString(factory_->NewFromUtf8(name)); @@ -340,4 +795,342 @@ void Builtins::SharedStrictModeForbiddenAccessCallerArguments(const JSHandle(func), JSHandle(func)); } + +void Builtins::InitializeSSymbolAttributes(const JSHandle &env) +{ + JSHandle hasInstanceSymbol( + factory_->NewSWellKnownSymbolWithChar("Symbol.hasInstance")); + JSHandle isConcatSpreadableSymbol( + factory_->NewSWellKnownSymbolWithChar("Symbol.isConcatSpreadable")); + JSHandle toStringTagSymbol( + factory_->NewSWellKnownSymbolWithChar("Symbol.toStringTag")); + JSHandle asyncIteratorSymbol( + factory_->NewSPublicSymbolWithChar("Symbol.asyncIterator")); + JSHandle matchSymbol( + factory_->NewSPublicSymbolWithChar("Symbol.match")); + JSHandle matchAllSymbol( + factory_->NewSPublicSymbolWithChar("Symbol.matchAll")); + JSHandle searchSymbol( + factory_->NewSPublicSymbolWithChar("Symbol.search")); + JSHandle toPrimitiveSymbol( + factory_->NewSPublicSymbolWithChar("Symbol.toPrimitive")); + JSHandle unscopablesSymbol( + factory_->NewSPublicSymbolWithChar("Symbol.unscopables")); + JSHandle nativeBindingSymbol( + factory_->NewSPublicSymbolWithChar("Symbol.nativeBinding")); + + // Symbol attributes with detectors + // Create symbol string before create symbol to allocate symbol continuously + // Attention: Symbol serialization & deserialization are not supported now and + // the order of symbols and symbol-strings must be maintained too when + // Symbol serialization & deserialization are ready. +#define INIT_SYMBOL_STRING(name, description, key) \ + { \ + [[maybe_unused]] JSHandle string = factory_->NewFromUtf8(description); \ + } +DETECTOR_SYMBOL_LIST(INIT_SYMBOL_STRING) +#undef INIT_SYMBOL_STRING + +#define INIT_PUBLIC_SYMBOL(name, description, key) \ + JSHandle key##Symbol = factory_->NewSEmptySymbol(); \ + JSHandle key##String = factory_->NewFromUtf8(description); \ + key##Symbol->SetDescription(thread_, key##String.GetTaggedValue()); \ + key##Symbol->SetHashField(SymbolTable::Hash(key##String.GetTaggedValue())); +DETECTOR_SYMBOL_LIST(INIT_PUBLIC_SYMBOL) +#undef INIT_PUBLIC_SYMBOL + +#define REGISTER_SYMBOL(name, Name) \ + env->Set##Name##Symbol(thread_, name##Symbol); +BUILTIN_ALL_SYMBOLS(REGISTER_SYMBOL) +#undef REGISTER_SYMBOL +} + +void Builtins::InitializeSharedArray(const JSHandle &env, const JSHandle &sObjIHClass, + JSHandle &sFuncPrototype) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + // Arraybase.prototype + JSHandle arrBaseFuncInstanceHClass = CreateSArrayPrototypeHClass(sObjIHClass); + + // Array.prototype + JSHandle arrFuncPrototype = factory_->NewSharedOldSpaceJSObjectWithInit(arrBaseFuncInstanceHClass); + auto accessor = thread_->GlobalConstants()->GetSharedArrayLengthAccessor(); + int32_t protoFieldIndex = JSSharedArray::LENGTH_INLINE_PROPERTY_INDEX; // length + static_assert(JSSharedArray::LENGTH_INLINE_PROPERTY_INDEX == 0); + arrFuncPrototype->SetPropertyInlinedProps(thread_, protoFieldIndex++, accessor); + JSHandle arrFuncPrototypeValue(arrFuncPrototype); + + // Array.prototype_or_hclass + JSHandle layout = factory_->CreateSLayoutInfo(1); + PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(true, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + layout->AddKey(thread_, 0, thread_->GlobalConstants()->GetHandledLengthString().GetTaggedValue(), attributes); + JSHandle arrFuncInstanceHClass = factory_->NewSEcmaHClass( + JSSharedArray::SIZE, 1, JSType::JS_SHARED_ARRAY, arrFuncPrototypeValue, JSHandle::Cast(layout)); + arrFuncInstanceHClass->SetExtensible(false); + // SharedArray.hclass + JSHandle arrayFuncHClass = CreateSArrayFunctionHClass(sFuncPrototype); + arrayFuncHClass->SetExtensible(false); + // SharedArray() = new Function() + JSHandle arrayFunction = + factory_->NewSFunctionByHClass(reinterpret_cast(BuiltinsSharedArray::ArrayConstructor), arrayFuncHClass, + FunctionKind::BUILTIN_CONSTRUCTOR); + + InitializeSCtor(arrFuncInstanceHClass, arrayFunction, "SharedArray", FunctionLength::ZERO); + + arrFuncPrototype->SetPropertyInlinedProps(thread_, protoFieldIndex++, arrayFunction.GetTaggedValue()); + JSHandle globalObject(thread_, env->GetGlobalObject()); + JSHandle nameString(factory_->NewFromUtf8("SharedArray")); + PropertyDescriptor desc(thread_, JSHandle::Cast(arrayFunction), false, false, false); + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); + RETURN_IF_ABRUPT_COMPLETION(thread_); + for (const base::BuiltinFunctionEntry &entry : BuiltinsSharedArray::GetSharedArrayPrototypeFunctions()) { + SetSFunction(env, arrFuncPrototype, entry.GetName(), entry.GetEntrypoint(), protoFieldIndex++, + entry.GetLength(), entry.GetBuiltinStubId()); + } + + // %ArrayPrototype% [ @@iterator ] + JSHandle values(factory_->NewFromASCII("values")); + JSHandle valuesFunc = + JSObject::GetMethod(thread_, JSHandle::Cast(arrFuncPrototype), values); + RETURN_IF_ABRUPT_COMPLETION(thread_); + int32_t funcFieldIndex = 3; // 3: length, name, prototype + for (const base::BuiltinFunctionEntry &entry : BuiltinsSharedArray::GetSharedArrayFunctions()) { + SetSFunction(env, JSHandle(arrayFunction), entry.GetName(), entry.GetEntrypoint(), funcFieldIndex++, + entry.GetLength(), entry.GetBuiltinStubId()); + } + + // %SetPrototype% [ @@iterator ] + arrFuncPrototype->SetPropertyInlinedProps(thread_, protoFieldIndex++, valuesFunc.GetTaggedValue()); + + // 22.1.2.5 get %Array% [ @@species ] + JSHandle speciesGetter = + CreateSGetterSetter(env, BuiltinsSharedArray::Species, "[Symbol.species]", FunctionLength::ZERO); + SetSAccessor(JSHandle(arrayFunction), funcFieldIndex++, speciesGetter, + globalConst->GetHandledUndefined()); + + // Array.prototype [ @@unscopables ] + JSHandle unscopablesGetter = + CreateSGetterSetter(env, BuiltinsSharedArray::Unscopables, "[Symbol.unscopables]", FunctionLength::ZERO); + SetSAccessor(JSHandle(arrFuncPrototype), protoFieldIndex++, unscopablesGetter, + globalConst->GetHandledUndefined()); + arrBaseFuncInstanceHClass->SetExtensible(false); + env->SetSharedArrayFunction(thread_, arrayFunction); + env->SetSharedArrayPrototype(thread_, arrFuncPrototype); +} + +#define BUILTIN_SHARED_TYPED_ARRAY_DEFINE_INITIALIZE(Type, ctorName, TYPE, bytesPerElement) \ +void Builtins::InitializeS##Type(const JSHandle &env, const JSHandle &arrFuncClass) const \ +{ \ + [[maybe_unused]] EcmaHandleScope scope(thread_); \ + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); \ + auto emptySLayout = globalConst->GetHandledEmptySLayoutInfo(); \ + /* %SharedTypedArray%.prototype (where %SharedTypedArray% is one of Int8Array, Uint8Array, etc.) */ \ + JSHandle arrFuncPrototype = factory_->NewSharedOldSpaceJSObjectWithInit(arrFuncClass); \ + JSHandle arrFuncPrototypeValue(arrFuncPrototype); \ + /* %TypedArray%.prototype_or_hclass */ \ + JSHandle arrFuncInstanceHClass = factory_->NewSEcmaHClass( \ + JSSharedTypedArray::SIZE, 0, JSType::JS_SHARED_##TYPE, arrFuncPrototypeValue,emptySLayout); \ + JSHandle arrFuncInstanceHClassOnHeap = factory_->NewSEcmaHClass( \ + JSSharedTypedArray::SIZE, 0, JSType::JS_SHARED_##TYPE, arrFuncPrototypeValue, emptySLayout); \ + arrFuncInstanceHClassOnHeap->SetIsOnHeap(true); \ + arrFuncInstanceHClass->SetHasConstructor(false); \ + /* %SharedTypedArray% = new Function() */ \ + JSHandle specificTypedArrayFuncClass = JSHandle::Cast( \ + env->GetSharedSpecificTypedArrayFunctionClass()); \ + JSHandle arrayFunction = factory_->NewSFunctionByHClass( \ + reinterpret_cast(BuiltinsSharedTypedArray::Type##Constructor), specificTypedArrayFuncClass, \ + FunctionKind::BUILTIN_CONSTRUCTOR); \ + InitializeSCtor(arrFuncInstanceHClass, arrayFunction, #ctorName, FunctionLength::THREE); \ + JSHandle globalObject(thread_, env->GetGlobalObject()); \ + JSHandle nameString(factory_->NewFromUtf8(#ctorName)); \ + PropertyDescriptor desc(thread_, JSHandle::Cast(arrayFunction), false, false, false); \ + JSObject::DefineOwnProperty(thread_, globalObject, nameString, desc); \ + RETURN_IF_ABRUPT_COMPLETION(thread_); \ + uint32_t fieldIndex = 0; \ + arrFuncPrototype->SetPropertyInlinedProps(thread_, fieldIndex, JSTaggedValue(bytesPerElement)); \ + fieldIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX + 1; \ + JSHandle(arrayFunction)->SetPropertyInlinedProps(thread_, fieldIndex, \ + JSTaggedValue(bytesPerElement)); \ + env->Set##ctorName##Function(thread_, arrayFunction); \ + env->Set##ctorName##FunctionPrototype(thread_, arrFuncPrototypeValue); \ +} +BUILTIN_SHARED_TYPED_ARRAY_TYPES(BUILTIN_SHARED_TYPED_ARRAY_DEFINE_INITIALIZE) +#undef BUILTIN_SHARED_TYPED_ARRAY_DEFINE_INITIALIZE + +void Builtins::InitializeSTypedArray(const JSHandle &env, const JSHandle &sObjPrototype, + const JSHandle &sFuncPrototype) const +{ + [[maybe_unused]] EcmaHandleScope scope(thread_); + const GlobalEnvConstants *globalConst = thread_->GlobalConstants(); + // SharedTypedArray.prototype + JSHandle typedArrFuncPrototypeHClass = CreateSTypedArrayPrototypeHClass(sObjPrototype); + JSHandle typedArrFuncPrototype = factory_->NewSharedOldSpaceJSObjectWithInit(typedArrFuncPrototypeHClass); + JSHandle typedArrFuncPrototypeValue(typedArrFuncPrototype); + + // SharedTypedArray.prototype_or_hclass + JSHandle layout = factory_->CreateSLayoutInfo(1); + PropertyAttributes attributes = PropertyAttributes::DefaultAccessor(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + attributes.SetOffset(0); + attributes.SetIsAccessor(false); + JSHandle keyString = JSHandle(factory_->NewFromUtf8("BYTES_PER_ELEMENT")); + layout->AddKey(thread_, 0, keyString.GetTaggedValue(), attributes); + + JSHandle typedArrFuncInstanceHClass = factory_->NewSEcmaHClass(JSSharedTypedArray::SIZE, 1, + JSType::JS_SHARED_TYPED_ARRAY, typedArrFuncPrototypeValue, JSHandle::Cast(layout)); + // SharedTypedArray.hclass + JSHandle typedArrFuncHClass = CreateSTypedArrayFunctionHClass(sFuncPrototype); + // SharedTypedArray = new Function() + JSHandle typedArrayFunction = + factory_->NewSFunctionByHClass(reinterpret_cast(BuiltinsSharedTypedArray::TypedArrayBaseConstructor), + typedArrFuncHClass, FunctionKind::BUILTIN_CONSTRUCTOR); + InitializeSCtor(typedArrFuncInstanceHClass, typedArrayFunction, "SharedTypedArray", FunctionLength::ZERO); + + // "constructor" property on the prototype + uint32_t fieldIndex = 0; // constructor + typedArrFuncPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, typedArrayFunction.GetTaggedValue()); + + // SharedTypedArray.prototype method + for (const base::BuiltinFunctionEntry &entry: BuiltinsSharedTypedArray::GetTypedArrayPrototypeFunctions()) { + SetSFunction(env, typedArrFuncPrototype, entry.GetName(), entry.GetEntrypoint(), fieldIndex++, + entry.GetLength(), entry.GetBuiltinStubId()); + } + // SharedTypedArray.prototype get accessor + for (const base::BuiltinFunctionEntry &entry: BuiltinsSharedTypedArray::GetTypedArrayPrototypeAccessors()) { + JSHandle getter = CreateSGetterSetter(env, entry.GetEntrypoint(), + entry.GetName(), entry.GetLength()); + SetSAccessor(typedArrFuncPrototype, fieldIndex++, getter, globalConst->GetHandledUndefined()); + } + + // %SharedTypedArray%.prototype.toString(), which is strictly equal to Array.prototype.toString + JSHandle arrFuncPrototype = env->GetSharedArrayPrototype(); + JSHandle toStringFunc = + JSObject::GetMethod(thread_, arrFuncPrototype, globalConst->GetHandledToStringString()); + RETURN_IF_ABRUPT_COMPLETION(thread_); + typedArrFuncPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, toStringFunc.GetTaggedValue()); + + // %SharedTypedArray%.prototype [ @@iterator ] ( ) + JSHandle values(factory_->NewFromASCII("values")); + JSHandle valuesFunc = + JSObject::GetMethod(thread_, JSHandle::Cast(typedArrFuncPrototype), values); + RETURN_IF_ABRUPT_COMPLETION(thread_); + typedArrFuncPrototype->SetPropertyInlinedProps(thread_, fieldIndex++, valuesFunc.GetTaggedValue()); + + // 22.2.3.31 get %SharedTypedArray%.prototype [ @@toStringTag ] + JSHandle toStringTagGetter = + CreateSGetterSetter(env, BuiltinsSharedTypedArray::ToStringTag, "[Symbol.toStringTag]", FunctionLength::ZERO); + SetSAccessor(typedArrFuncPrototype, fieldIndex++, toStringTagGetter, globalConst->GetHandledUndefined()); + + uint32_t funcFieldIndex = JSFunction::PROTOTYPE_INLINE_PROPERTY_INDEX + 1; // length, name, prototype, ... + // SharedTypedArray method + for (const base::BuiltinFunctionEntry &entry: BuiltinsSharedTypedArray::GetTypedArrayFunctions()) { + SetSFunction(env, JSHandle(typedArrayFunction), entry.GetName(), entry.GetEntrypoint(), + funcFieldIndex++, entry.GetLength(), entry.GetBuiltinStubId()); + } + + // 22.2.2.4 get %SharedTypedArray% [ @@species ] + JSHandle speciesGetter = + CreateSGetterSetter(env, BuiltinsSharedTypedArray::Species, "[Symbol.species]", FunctionLength::ZERO); + SetSAccessor(JSHandle(typedArrayFunction), funcFieldIndex++, speciesGetter, + globalConst->GetHandledUndefined()); + + env->SetSharedTypedArrayFunction(thread_, typedArrayFunction.GetTaggedValue()); + env->SetSharedTypedArrayPrototype(thread_, typedArrFuncPrototype); + + JSHandle specificTypedArrayFuncClass = CreateSSpecificTypedArrayFuncHClass(typedArrayFunction); + env->SetSharedSpecificTypedArrayFunctionClass(thread_, specificTypedArrayFuncClass); + +#define BUILTIN_SHARED_TYPED_ARRAY_CALL_INITIALIZE(Type, ctorName, TYPE, bytesPerElement) \ + InitializeS##Type(env, typedArrFuncInstanceHClass); + BUILTIN_SHARED_TYPED_ARRAY_TYPES(BUILTIN_SHARED_TYPED_ARRAY_CALL_INITIALIZE) +#undef BUILTIN_SHARED_TYPED_ARRAY_CALL_INITIALIZE +} + +JSHandle Builtins::CreateSTypedArrayPrototypeHClass(const JSHandle &sObjPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedTypedArray::GetPrototypeProperties(); + uint32_t length = properties.size(); + ASSERT(length == BuiltinsSharedTypedArray::GetNumPrototypeInlinedProperties()); + JSHandle layout = factory_->CreateSLayoutInfo(length); + JSHandle keyString; + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.iterator]") { + keyString = env->GetIteratorSymbol(); + } else if (key == "[Symbol.toStringTag]") { + keyString = env->GetToStringTagSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sTypedArrayPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedObject::SIZE, length, JSType::JS_SHARED_OBJECT, + JSHandle(sObjPrototype), + JSHandle(layout)); + return sTypedArrayPrototypeHClass; +} + +JSHandle Builtins::CreateSTypedArrayFunctionHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + auto env = vm_->GetGlobalEnv(); + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedTypedArray::GetFunctionProperties(); + uint32_t length = properties.size(); + JSHandle keyString; + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + if (key == "[Symbol.species]") { + keyString = env->GetSpeciesSymbol(); + } else { + keyString = JSHandle(factory_->NewFromUtf8(key)); + } + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} + +JSHandle Builtins::CreateSSpecificTypedArrayFuncHClass(const JSHandle &sFuncPrototype) const +{ + uint32_t index = 0; + PropertyAttributes attributes = PropertyAttributes::Default(false, false, false); + attributes.SetIsInlinedProps(true); + attributes.SetRepresentation(Representation::TAGGED); + auto properties = BuiltinsSharedTypedArray::GetSpecificFunctionProperties(); + uint32_t length = properties.size(); + JSHandle keyString; + JSHandle layout = factory_->CreateSLayoutInfo(length); + for (const auto &[key, isAccessor] : properties) { + attributes.SetOffset(index); + attributes.SetIsAccessor(isAccessor); + keyString = JSHandle(factory_->NewFromUtf8(key)); + layout->AddKey(thread_, index++, keyString.GetTaggedValue(), attributes); + } + JSHandle sobjPrototypeHClass = + factory_->NewSEcmaHClass(JSSharedFunction::SIZE, length, JSType::JS_SHARED_FUNCTION, + JSHandle(sFuncPrototype), JSHandle(layout)); + sobjPrototypeHClass->SetConstructor(true); + sobjPrototypeHClass->SetCallable(true); + return sobjPrototypeHClass; +} } // namespace panda::ecmascript diff --git a/ecmascript/checkpoint/thread_state_transition.h b/ecmascript/checkpoint/thread_state_transition.h index f6382513076dea46949c6b7f12e0f152afa19b20..1a57bcb417f9e15ed37106bf3b103532e299d734 100644 --- a/ecmascript/checkpoint/thread_state_transition.h +++ b/ecmascript/checkpoint/thread_state_transition.h @@ -29,10 +29,6 @@ public: oldState_ = self_->GetState(); if (oldState_ != newState) { self_->UpdateState(newState); - } else { - if (oldState_ == ThreadState::RUNNING) { - self_->CheckSafepointIfSuspended(); - } } } @@ -40,10 +36,6 @@ public: { if (oldState_ != self_->GetState()) { self_->UpdateState(oldState_); - } else { - if (oldState_ == ThreadState::RUNNING) { - self_->CheckSafepointIfSuspended(); - } } } @@ -97,11 +89,13 @@ public: explicit SuspendAllScope(JSThread* self) : self_(self), scope_(self, ThreadState::IS_SUSPENDED) { + TRACE_GC(GCStats::Scope::ScopeId::SuspendAll, SharedHeap::GetInstance()->GetEcmaGCStats()); ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "SuspendAll"); Runtime::GetInstance()->SuspendAll(self_); } ~SuspendAllScope() { + TRACE_GC(GCStats::Scope::ScopeId::ResumeAll, SharedHeap::GetInstance()->GetEcmaGCStats()); ECMA_BYTRACE_NAME(HITRACE_TAG_ARK, "ResumeAll"); Runtime::GetInstance()->ResumeAll(self_); } diff --git a/ecmascript/common.h b/ecmascript/common.h index e189594e80a47089d2ec0938bc1d0507ff8ca848..48bbfc6be728a496274426fe8c2dbc7a19ecb1c9 100644 --- a/ecmascript/common.h +++ b/ecmascript/common.h @@ -48,6 +48,7 @@ enum class GCReason : uint8_t { IDLE, SWITCH_BACKGROUND, EXTERNAL_TRIGGER, + WORKER_DESTRUCTION, OTHER, }; @@ -69,7 +70,9 @@ enum class RequestAotMode : uint8_t { V(Evacuate) \ V(Finish) \ V(UpdateReference) \ - V(EvacuateSpace) + V(EvacuateSpace) \ + V(SuspendAll) \ + V(ResumeAll) #define RECORD_DATA(V) \ V(START_OBJ_SIZE) \ @@ -183,8 +186,6 @@ using Address = uintptr_t; #define WIN_OR_MAC_OR_IOS_PLATFORM false #endif -#define ECMASCRIPT_ENABLE_VALUE_SERIALIZER 1 - #define STATIC_ASSERT_EQ_ARCH(expect, valueArch32, valueArch64) \ STATIC_ASSERT_EQ_ARCH32(expect, valueArch32); \ STATIC_ASSERT_EQ_ARCH64(expect, valueArch64) diff --git a/ecmascript/compiler/BUILD.gn b/ecmascript/compiler/BUILD.gn index 4f337a1dfbfb3c1fb5f403ad4157392bbbe07401..66d93a5cdbbc3d215cf6d917268603197cd55b4b 100644 --- a/ecmascript/compiler/BUILD.gn +++ b/ecmascript/compiler/BUILD.gn @@ -92,11 +92,13 @@ libark_jsoptimizer_sources = [ "builtins/builtins_array_stub_builder.cpp", "builtins/builtins_call_signature.cpp", "builtins/builtins_collection_stub_builder.cpp", + "builtins/builtins_dataview_stub_builder.cpp", "builtins/builtins_function_stub_builder.cpp", "builtins/builtins_number_stub_builder.cpp", "builtins/builtins_object_stub_builder.cpp", "builtins/builtins_string_stub_builder.cpp", "builtins/builtins_stubs.cpp", + "builtins/builtins_typedarray_stub_builder.cpp", "builtins/containers_stub_builder.cpp", "builtins/linked_hashtable_stub_builder.cpp", "builtins_lowering.cpp", @@ -125,9 +127,11 @@ libark_jsoptimizer_sources = [ "gate_accessor.cpp", "graph_editor.cpp", "graph_linearizer.cpp", + "hash_stub_builder.cpp", "hcr_circuit_builder.cpp", "hcr_gate_meta_data.cpp", "ic_stub_builder.cpp", + "induction_variable_analysis.cpp", "instruction_combine.cpp", "interpreter_stub.cpp", "ir_builder.cpp", @@ -177,14 +181,10 @@ libark_jsoptimizer_sources = [ "ts_hcr_opt_pass.cpp", "ts_inline_lowering.cpp", "type.cpp", - "type_inference/global_type_infer.cpp", - "type_inference/initialization_analysis.cpp", - "type_inference/method_type_infer.cpp", "type_inference/pgo_type_infer.cpp", "type_inference/pgo_type_infer_helper.cpp", "type_info_accessors.cpp", "type_recorder.cpp", - "typed_array_stub_builder.cpp", "typed_bytecode_lowering.cpp", "typed_hcr_lowering.cpp", "typed_native_inline_lowering.cpp", @@ -421,15 +421,20 @@ ohos_shared_library("libark_jsoptimizer") { stack_protector_ret = false deps = [ ":libark_jsoptimizer_set_with_maple", - "$ark_third_party_root/bounds_checking_function:libsec_shared", "$js_root:libark_jsruntime", "${MAPLEALL_ROOT}/maple_be:libcg", ] + external_deps = [ "bounds_checking_function:libsec_shared" ] + if (run_with_asan) { defines = [ "RUN_WITH_ASAN" ] } + if (enable_hilog) { + external_deps += [ "hilog:libhilog" ] + } + install_enable = false if (!is_mingw && !is_mac) { @@ -476,9 +481,9 @@ ohos_executable("ark_stub_compiler") { "$ark_third_party_root/icu/icu4c:static_icuuc", ] } else { - deps += [ - "$ark_third_party_root/icu/icu4c:shared_icui18n", - "$ark_third_party_root/icu/icu4c:shared_icuuc", + external_deps += [ + "icu:shared_icui18n", + "icu:shared_icuuc", ] } @@ -531,9 +536,9 @@ ohos_executable("ark_aot_compiler") { "$ark_third_party_root/icu/icu4c:static_icuuc", ] } else { - deps += [ - "$ark_third_party_root/icu/icu4c:shared_icui18n", - "$ark_third_party_root/icu/icu4c:shared_icuuc", + external_deps += [ + "icu:shared_icui18n", + "icu:shared_icuuc", ] } diff --git a/ecmascript/compiler/aot_compiler.cpp b/ecmascript/compiler/aot_compiler.cpp index c48732fd1803aa5c139570555a9d4b4ec698b056..272f562512816d06099c0050c79f62c0f18a50b7 100644 --- a/ecmascript/compiler/aot_compiler.cpp +++ b/ecmascript/compiler/aot_compiler.cpp @@ -16,8 +16,6 @@ #include #include #include -#include // NOLINTNEXTLINE(modernize-deprecated-headers) -#include #include "ecmascript/base/string_helper.h" #include "ecmascript/checkpoint/thread_state_transition.h" @@ -26,14 +24,12 @@ #include "ecmascript/compiler/pass_manager.h" #include "ecmascript/ecma_string.h" #include "ecmascript/js_runtime_options.h" -#include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/log.h" #include "ecmascript/log_wrapper.h" -#include "ecmascript/module/js_module_manager.h" #include "ecmascript/napi/include/jsnapi.h" #include "ecmascript/ohos/ohos_pkg_args.h" #include "ecmascript/platform/file.h" +#include "ecmascript/platform/os.h" namespace panda::ecmascript::kungfu { namespace { @@ -75,6 +71,13 @@ int Main(const int argc, const char **argv) return 1; } + if (runtimeOptions.WasSetDeviceState()) { + bool deviceIsScreenOff = runtimeOptions.GetDeviceState(); + if (!deviceIsScreenOff) { + BindSmallCpuCore(); + } + } + if (runtimeOptions.IsStartupTime()) { LOG_COMPILER(DEBUG) << "Startup start time: " << startTime; } @@ -117,10 +120,11 @@ int Main(const int argc, const char **argv) if (!cPreprocessor.GenerateAbcFileInfos()) { return 1; } - cPreprocessor.GenerateGlobalTypes(cOptions); cPreprocessor.GeneratePGOTypes(cOptions); cPreprocessor.SnapshotInitialize(); ret = cPreprocessor.GetCompilerResult(); + const auto &fileInfos = cPreprocessor.GetAbcFileInfo(); + cPreprocessor.GenerateMethodMap(cOptions); PassOptions::Builder optionsBuilder; PassOptions passOptions = @@ -143,6 +147,7 @@ int Main(const int argc, const char **argv) .EnableLoweringBuiltin(cOptions.isEnableLoweringBuiltin_) .EnableOptBranchProfiling(cOptions.isEnableOptBranchProfiling_) .EnableEscapeAnalysis(cOptions.isEnableEscapeAnalysis_) + .EnableInductionVariableAnalysis(cOptions.isEnableInductionVariableAnalysis_) .Build(); PassManager passManager(vm, @@ -155,11 +160,13 @@ int Main(const int argc, const char **argv) cOptions.maxMethodsInModule_, profilerDecoder, &passOptions, + cPreprocessor.GetCallMethodFlagMap(), + fileInfos, cOptions.optBCRange_); bool isEnableLiteCG = runtimeOptions.IsCompilerEnableLiteCG(); AOTFileGenerator generator(&log, &logList, vm, cOptions.triple_, isEnableLiteCG); - const auto &fileInfos = cPreprocessor.GetAbcFileInfo(); + CompileValidFiles(passManager, generator, ret, fileInfos); std::string appSignature = cPreprocessor.GetMainPkgArgsAppSignature(); generator.SaveAOTFile(cOptions.outputFileName_ + AOTFileManager::FILE_EXTENSION_AN, appSignature); diff --git a/ecmascript/compiler/aot_compiler_preprocessor.cpp b/ecmascript/compiler/aot_compiler_preprocessor.cpp index 49456b38fa9cfaab64021d66e765377e85c927e2..a29b2b8d43bb5e5bf53e26b0a6de07aa98044a0c 100644 --- a/ecmascript/compiler/aot_compiler_preprocessor.cpp +++ b/ecmascript/compiler/aot_compiler_preprocessor.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ #include "ecmascript/compiler/aot_compiler_preprocessor.h" + #include "ecmascript/compiler/pgo_type/pgo_type_parser.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/module/js_module_manager.h" @@ -37,6 +38,7 @@ CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOpti logOption_ = runtimeOptions.GetCompilerLogOption(); logMethodsList_ = runtimeOptions.GetMethodsListForLog(); compilerLogTime_ = runtimeOptions.IsEnableCompilerLogTime(); + deviceIsScreenOff_ = runtimeOptions.GetDeviceState(); maxAotMethodSize_ = runtimeOptions.GetMaxAotMethodSize(); maxMethodsInModule_ = runtimeOptions.GetCompilerModuleMethods(); hotnessThreshold_ = runtimeOptions.GetPGOHotnessThreshold(); @@ -63,6 +65,51 @@ CompilationOptions::CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOpti isEnableOptBranchProfiling_ = runtimeOptions.IsEnableBranchProfiling(); optBCRange_ = runtimeOptions.GetOptCodeRange(); isEnableEscapeAnalysis_ = runtimeOptions.IsEnableEscapeAnalysis(); + isEnableInductionVariableAnalysis_ = runtimeOptions.IsEnableInductionVariableAnalysis(); + + std::string optionSelectMethods = runtimeOptions.GetCompilerSelectMethods(); + std::string optionSkipMethods = runtimeOptions.GetCompilerSkipMethods(); + if (!optionSelectMethods.empty() && !optionSkipMethods.empty()) { + LOG_COMPILER(FATAL) << + "--compiler-select-methods and --compiler-skip-methods should not be set at the same time"; + } + if (!optionSelectMethods.empty()) { + ParseOption(optionSelectMethods, optionSelectMethods_); + } + if (!optionSkipMethods.empty()) { + ParseOption(optionSkipMethods, optionSkipMethods_); + } +} + +std::vector CompilationOptions::SplitString(const std::string &str, const char ch) const +{ + std::vector vec {}; + std::istringstream sstr(str.c_str()); + std::string split; + while (getline(sstr, split, ch)) { + vec.emplace_back(split); + } + return vec; +} + +void CompilationOptions::ParseOption(const std::string &option, + std::map> &optionMap) const +{ + const char colon = ':'; + const char comma = ','; + std::string str = option; + size_t posColon = 0; + size_t posComma = 0; + do { + posColon = str.find_last_of(colon); + std::string methodNameList = str.substr(posColon + 1, str.size()); + std::vector methodNameVec = SplitString(methodNameList, comma); + str = str.substr(0, posColon); + posComma = str.find_last_of(comma); + std::string recordName = str.substr(posComma + 1, str.size()); + str = str.substr(0, posComma); + optionMap[recordName] = methodNameVec; + } while (posComma != std::string::npos); } bool AotCompilerPreprocessor::HandleTargetCompilerMode(CompilationOptions &cOptions) @@ -117,6 +164,7 @@ void AotCompilerPreprocessor::AOTInitialize() { BytecodeStubCSigns::Initialize(); CommonStubCSigns::Initialize(); + BuiltinsStubCSigns::Initialize(); RuntimeStubCSigns::Initialize(); vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->Initialize(); } @@ -156,10 +204,8 @@ std::shared_ptr AotCompilerPreprocessor::CreateAndVerifyJSPandaFile if (runtimeOptions_.IsTargetCompilerMode()) { auto pkgArgsIter = pkgsArgs_.find(fileName); if (pkgArgsIter == pkgsArgs_.end()) { - LOG_COMPILER(ERROR) << "Can not find file in ohos pkgs args. file name: " << fileName; - return nullptr; - } - if (!(pkgArgsIter->second->GetJSPandaFile(runtimeOptions_, jsPandaFile))) { + jsPandaFile = jsPandaFileManager->OpenJSPandaFile(fileName.c_str()); + } else if (!(pkgArgsIter->second->GetJSPandaFile(runtimeOptions_, jsPandaFile))) { return nullptr; } } else { @@ -176,7 +222,7 @@ std::shared_ptr AotCompilerPreprocessor::CreateAndVerifyJSPandaFile return nullptr; } - jsPandaFileManager->AddJSPandaFileVm(vm_, jsPandaFile); + jsPandaFileManager->AddJSPandaFile(jsPandaFile); return jsPandaFile; } @@ -197,45 +243,37 @@ void AotCompilerPreprocessor::ResolveModule(const JSPandaFile *jsPandaFile, cons } } -void AotCompilerPreprocessor::GenerateGlobalTypes(const CompilationOptions &cOptions) +void AotCompilerPreprocessor::RecordArrayElement(const CompilationOptions &cOptions) { for (const AbcFileInfo &fileInfo : fileInfos_) { JSPandaFile *jsPandaFile = fileInfo.jsPandaFile_.get(); - TSManager *tsManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetTSManager(); PGOTypeManager *ptManager = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager(); + ptManager->SetCurCompilationFile(jsPandaFile); BytecodeInfoCollector collector(vm_, jsPandaFile, profilerDecoder_, cOptions.maxAotMethodSize_, cOptions.isEnableCollectLiteralInfo_); BCInfo &bytecodeInfo = collector.GetBytecodeInfo(); const PGOBCInfo *bcInfo = collector.GetPGOBCInfo(); - const auto &methodPcInfos = bytecodeInfo.GetMethodPcInfos(); auto &methodList = bytecodeInfo.GetMethodList(); for (const auto &method : methodList) { uint32_t methodOffset = method.first; - tsManager->SetCurConstantPool(jsPandaFile, methodOffset); CString recordName = MethodLiteral::GetRecordName(jsPandaFile, EntityId(methodOffset)); - auto methodLiteral = jsPandaFile->FindMethodLiteral(methodOffset); - auto &methodInfo = methodList.at(methodOffset); - auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()]; - TypeRecorder typeRecorder(jsPandaFile, methodLiteral, tsManager, recordName, &profilerDecoder_, - methodPcInfo, collector.GetByteCodes(), cOptions.isEnableOptTrackField_); - typeRecorder.BindPgoTypeToGateType(jsPandaFile, tsManager, methodLiteral); - - bcInfo->IterateInfoByType(methodOffset, PGOBCInfo::Type::ARRAY_LITERAL, - [this, tsManager, ptManager, &recordName]([[maybe_unused]] const uint32_t bcIdx, - [[maybe_unused]] const uint32_t bcOffset, const uint32_t cpIdx) { - JSHandle constpoolHandle(tsManager->GetConstantPool()); - JSThread *thread = vm_->GetJSThread(); - JSTaggedValue unsharedCp = thread->GetCurrentEcmaContext() - ->FindUnsharedConstpool(constpoolHandle.GetTaggedValue()); - ASSERT(ConstantPool::CheckUnsharedConstpool(unsharedCp)); - JSTaggedValue arr = - ConstantPool::GetLiteralFromCache( - thread, unsharedCp, cpIdx, recordName); - JSHandle arrayHandle(thread, arr); - panda_file::File::EntityId id = - ConstantPool::GetIdFromCache(constpoolHandle.GetTaggedValue(), cpIdx); - ptManager->RecordElements(id, arrayHandle->GetElements()); - }); + auto callback = [this, ptManager, methodOffset, &recordName] + (const uint32_t, const uint32_t, const uint32_t cpIdx) { + JSThread *thread = vm_->GetJSThread(); + JSTaggedValue cp = ptManager->GetConstantPoolByMethodOffset(methodOffset); + JSHandle constpoolHandle(thread, cp); + JSTaggedValue unsharedCp = thread->GetCurrentEcmaContext() + ->FindOrCreateUnsharedConstpool(constpoolHandle.GetTaggedValue()); + ASSERT(ConstantPool::CheckUnsharedConstpool(unsharedCp)); + JSTaggedValue arr = ConstantPool::GetLiteralFromCache( + thread, unsharedCp, cpIdx, recordName); + JSHandle arrayHandle(thread, arr); + panda_file::File::EntityId id = + ConstantPool::GetIdFromCache(constpoolHandle.GetTaggedValue(), cpIdx); + ptManager->RecordElements(id, arrayHandle->GetElements()); + }; + + bcInfo->IterateInfoByType(methodOffset, PGOBCInfo::Type::ARRAY_LITERAL, callback); } } } @@ -250,6 +288,7 @@ void AotCompilerPreprocessor::GeneratePGOTypes(const CompilationOptions &cOption PGOTypeParser parser(profilerDecoder_, ptManager); parser.CreatePGOType(collector); } + RecordArrayElement(cOptions); } void AotCompilerPreprocessor::SnapshotInitialize() @@ -258,6 +297,99 @@ void AotCompilerPreprocessor::SnapshotInitialize() ptManager->InitAOTSnapshot(fileInfos_.size()); } +void CallMethodFlagMap::SetIsFastCall(CString fileDesc, uint32_t methodOffset, bool isFastCall) +{ + abcIdMethodIdToIsFastCall_[std::pair(fileDesc, methodOffset)] = isFastCall; +} + +bool CallMethodFlagMap::IsFastCall(CString fileDesc, uint32_t methodOffset) const +{ + if (!abcIdMethodIdToIsFastCall_.count(std::pair(fileDesc, methodOffset))) { + return false; + } + return abcIdMethodIdToIsFastCall_.at(std::pair(fileDesc, methodOffset)); +} + +void CallMethodFlagMap::SetIsAotCompile(CString fileDesc, uint32_t methodOffset, bool isAotCompile) +{ + abcIdMethodIdToIsAotCompile_[std::pair(fileDesc, methodOffset)] = isAotCompile; +} + +bool CallMethodFlagMap::IsAotCompile(CString fileDesc, uint32_t methodOffset) const +{ + if (!abcIdMethodIdToIsAotCompile_.count(std::pair(fileDesc, methodOffset))) { + return false; + } + return abcIdMethodIdToIsAotCompile_.at(std::pair(fileDesc, methodOffset)); +} + + +bool AotCompilerPreprocessor::FilterOption(const std::map> &optionMap, + const std::string &recordName, const std::string &methodName) const +{ + if (optionMap.empty()) { + return false; + } + + auto it = optionMap.find(recordName); + if (it == optionMap.end()) { + return false; + } + + std::vector vec = it->second; + return find(vec.begin(), vec.end(), methodName) != vec.end(); +} + +bool AotCompilerPreprocessor::IsSkipMethod(const JSPandaFile *jsPandaFile, const BCInfo &bytecodeInfo, + const CString &recordName, const MethodLiteral *methodLiteral, + const MethodPcInfo &methodPCInfo, const std::string &methodName, + CompilationOptions &cOptions) const +{ + if (methodPCInfo.methodsSize > bytecodeInfo.GetMaxMethodSize() || + !profilerDecoder_.Match(jsPandaFile, recordName, methodLiteral->GetMethodId())) { + return true; + } + + if (!cOptions.optionSelectMethods_.empty()) { + return !FilterOption(cOptions.optionSelectMethods_, ConvertToStdString(recordName), methodName); + } else if (!cOptions.optionSkipMethods_.empty()) { + return FilterOption(cOptions.optionSkipMethods_, ConvertToStdString(recordName), methodName); + } + + return false; +} + +void AotCompilerPreprocessor::GenerateMethodMap(CompilationOptions &cOptions) +{ + JSPandaFileManager *jsPandaFileManager = JSPandaFileManager::GetInstance(); + jsPandaFileManager->EnumerateNonVirtualJSPandaFiles( + [this, &cOptions] (std::shared_ptr jsPandaFilePtr) { + JSPandaFile *jsPandaFile = jsPandaFilePtr.get(); + BytecodeInfoCollector collector(vm_, jsPandaFile, profilerDecoder_, cOptions.maxAotMethodSize_, + cOptions.isEnableCollectLiteralInfo_); + BCInfo &bytecodeInfo = collector.GetBytecodeInfo(); + const auto &methodPcInfos = bytecodeInfo.GetMethodPcInfos(); + auto &methodList = bytecodeInfo.GetMethodList(); + for (auto it = methodList.begin(); it != methodList.end(); it++) { + uint32_t index = it->first; + auto &methodInfo = it->second; + auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()]; + auto methodLiteral = jsPandaFile->FindMethodLiteral(index); + auto methodId = methodLiteral->GetMethodId(); + const std::string methodName(MethodLiteral::GetMethodName(jsPandaFile, methodId)); + bool isAotcompile = !IsSkipMethod(jsPandaFile, bytecodeInfo, MethodLiteral::GetRecordName( + jsPandaFile, EntityId(index)), methodLiteral, methodPcInfo, methodName, cOptions); + bool isFastCall = methodLiteral->IsFastCall(); + CString fileDesc = jsPandaFile->GetNormalizedFileDesc(); + uint32_t offset = methodId.GetOffset(); + callMethodFlagMap_.SetIsAotCompile(fileDesc, offset, isAotcompile); + callMethodFlagMap_.SetIsFastCall(fileDesc, offset, isFastCall); + LOG_COMPILER(INFO) <<"!!!"<< fileDesc <<" "<< offset << " " << isAotcompile << " " << isFastCall; + } + return true; + }); +} + std::string AotCompilerPreprocessor::GetMainPkgArgsAppSignature() const { return GetMainPkgArgs() == nullptr ? "" : GetMainPkgArgs()->GetAppSignature(); diff --git a/ecmascript/compiler/aot_compiler_preprocessor.h b/ecmascript/compiler/aot_compiler_preprocessor.h index 818bc9a00decb58e82922aaf7c48e197fb8c186f..67767475fdd0e7c881df073cde5f034e79ab6d12 100644 --- a/ecmascript/compiler/aot_compiler_preprocessor.h +++ b/ecmascript/compiler/aot_compiler_preprocessor.h @@ -15,6 +15,9 @@ #ifndef ECMASCRIPT_COMPILER_AOT_COMPILER_PREPROCESSOR_H #define ECMASCRIPT_COMPILER_AOT_COMPILER_PREPROCESSOR_H +#include "ecmascript/compiler/bytecode_info_collector.h" +#include "ecmascript/compiler/compiler_log.h" +#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h" #include "ecmascript/compiler/pass_manager.h" #include "ecmascript/ecma_vm.h" #include "macros.h" @@ -32,9 +35,22 @@ struct AbcFileInfo { std::shared_ptr jsPandaFile_; }; +class CallMethodFlagMap { +public: + CallMethodFlagMap() {} + void SetIsFastCall(CString fileDesc, uint32_t methodOffset, bool isFastCall); + bool IsFastCall(CString fileDesc, uint32_t methodOffset) const; + void SetIsAotCompile(CString fileDesc, uint32_t methodOffset, bool isAotCompile); + bool IsAotCompile(CString fileDesc, uint32_t methodOffset) const; +private: + std::map, bool> abcIdMethodIdToIsFastCall_ {}; + std::map, bool> abcIdMethodIdToIsAotCompile_ {}; +}; + struct CompilationOptions { explicit CompilationOptions(EcmaVM *vm, JSRuntimeOptions &runtimeOptions); - + void ParseOption(const std::string &option, std::map> &optionMap) const; + std::vector SplitString(const std::string &str, const char ch) const; std::string triple_; std::string outputFileName_; size_t optLevel_; @@ -42,6 +58,7 @@ struct CompilationOptions { std::string logOption_; std::string logMethodsList_; bool compilerLogTime_; + bool deviceIsScreenOff_; size_t maxAotMethodSize_; size_t maxMethodsInModule_; uint32_t hotnessThreshold_; @@ -68,6 +85,9 @@ struct CompilationOptions { bool isEnableLoweringBuiltin_; bool isEnableOptBranchProfiling_; bool isEnableEscapeAnalysis_; + bool isEnableInductionVariableAnalysis_; + std::map> optionSelectMethods_; + std::map> optionSkipMethods_; }; class AotCompilerPreprocessor { @@ -93,12 +113,40 @@ public: bool GenerateAbcFileInfos(); - void GenerateGlobalTypes(const CompilationOptions &cOptions); - void GeneratePGOTypes(const CompilationOptions &cOptions); void SnapshotInitialize(); + bool FilterOption(const std::map> &optionMap, + const std::string &recordName, const std::string &methodName) const; + + bool IsSkipMethod(const JSPandaFile *jsPandaFile, const BCInfo &bytecodeInfo, + const CString &recordName, const MethodLiteral *methodLiteral, + const MethodPcInfo &methodPCInfo, const std::string &methodName, + CompilationOptions &cOptions) const; + + void GenerateMethodMap(CompilationOptions &cOptions); + + void SetIsFastCall(CString fileDesc, uint32_t methodOffset, bool isFastCall) + { + callMethodFlagMap_.SetIsFastCall(fileDesc, methodOffset, isFastCall); + } + + bool IsFastCall(CString fileDesc, uint32_t methodOffset) + { + return callMethodFlagMap_.IsFastCall(fileDesc, methodOffset); + } + + void SetIsAotCompile(CString fileDesc, uint32_t methodOffset, bool isAotCompile) + { + callMethodFlagMap_.SetIsAotCompile(fileDesc, methodOffset, isAotCompile); + } + + bool GetIsAotCompile(CString fileDesc, uint32_t methodOffset) + { + return callMethodFlagMap_.IsAotCompile(fileDesc, methodOffset); + } + std::string GetMainPkgArgsAppSignature() const; bool GetCompilerResult() @@ -124,6 +172,10 @@ public: { return pkgsArgs_; } + const CallMethodFlagMap *GetCallMethodFlagMap() + { + return &callMethodFlagMap_; + } static std::string GetHelper() { @@ -142,6 +194,8 @@ private: void ResolveModule(const JSPandaFile *jsPandaFile, const std::string &fileName); + void RecordArrayElement(const CompilationOptions &cOptions); + EcmaVM *vm_; JSRuntimeOptions &runtimeOptions_; std::map> &pkgsArgs_; @@ -149,6 +203,7 @@ private: PGOProfilerDecoder &profilerDecoder_; arg_list_t &pandaFileNames_; CVector fileInfos_; + CallMethodFlagMap callMethodFlagMap_; friend class OhosPkgArgs; }; } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/aot_file/an_file_data_manager.cpp b/ecmascript/compiler/aot_file/an_file_data_manager.cpp index a2b4a5a606d9f667cd45c29b17bf85d84f1323d9..6110278109e92a97c2134fffd4f21abd3c104c54 100644 --- a/ecmascript/compiler/aot_file/an_file_data_manager.cpp +++ b/ecmascript/compiler/aot_file/an_file_data_manager.cpp @@ -41,6 +41,7 @@ void AnFileDataManager::SafeDestroyAllData() WriteLockHolder lock(lock_); if (loadedStub_ != nullptr) { ExecutedMemoryAllocator::DestroyBuf(loadedStub_->GetStubsMem()); + DestroyFileMapMem(loadedStub_->GetFileMapMem()); loadedStub_ = nullptr; } diff --git a/ecmascript/compiler/aot_file/aot_file_manager.cpp b/ecmascript/compiler/aot_file/aot_file_manager.cpp index 0887c68b3ac02365fa2918a742f6e5396e0bcb51..bf59b3af635ba7e3a4b4e248f94d6b87fdd8ef9f 100644 --- a/ecmascript/compiler/aot_file/aot_file_manager.cpp +++ b/ecmascript/compiler/aot_file/aot_file_manager.cpp @@ -41,6 +41,7 @@ #include "ecmascript/log_wrapper.h" #include "ecmascript/mem/region.h" #include "ecmascript/message_string.h" +#include "ecmascript/ohos/framework_helper.h" #include "ecmascript/snapshot/mem/snapshot.h" #include "ecmascript/stackmap/ark_stackmap_parser.h" #include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h" @@ -227,6 +228,12 @@ bool AOTFileManager::TryReadLock() return anFileDataManager->SafeTryReadLock(); } +bool AOTFileManager::IsEnableAOT() const +{ + AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance(); + return anFileDataManager->IsEnable(); +} + bool AOTFileManager::InsideStub(uintptr_t pc) { AnFileDataManager *anFileDataManager = AnFileDataManager::GetInstance(); @@ -410,6 +417,7 @@ void AOTFileManager::ParseDeserializedData(const CString &snapshotFileName, JSTa uint32_t anFileInfoIndex = anFileDataManager->SafeGetFileInfoIndex(baseName + FILE_EXTENSION_AN); JSThread *thread = vm_->GetJSThread(); + FrameworkHelper frameworkHelper(thread); JSHandle aiData(thread, deserializedData); uint32_t aiDataLen = aiData->GetLength(); ASSERT(aiDataLen % AOTSnapshotConstants::SNAPSHOT_DATA_ITEM_SIZE == 0); @@ -423,19 +431,23 @@ void AOTFileManager::ParseDeserializedData(const CString &snapshotFileName, JSTa fileInfo.Update(aiData->Get(i + SnapshotGlobalData::Cast(SnapshotGlobalData::CP_TOP_ITEM::PANDA_INFO_ID))); auto nameOffset = SnapshotGlobalData::Cast(SnapshotGlobalData::CP_PANDA_INFO_ITEM::NAME_ID); auto indexOffset = SnapshotGlobalData::Cast(SnapshotGlobalData::CP_PANDA_INFO_ITEM::INDEX_ID); - CString fileNameStr = EcmaStringAccessor(fileInfo->Get(nameOffset)).ToCString(); - uint32_t fileIndex = fileInfo->Get(indexOffset).GetInt(); + CString fileNameCStr = EcmaStringAccessor(fileInfo->Get(nameOffset)).ToCString(); + std::string fileNameStr = EcmaStringAccessor(fileInfo->Get(nameOffset)).ToStdString(); + uint32_t fileIndex = static_cast(fileInfo->Get(indexOffset).GetInt()); // handle constant pool cpList.Update(aiData->Get(i + SnapshotGlobalData::Cast(SnapshotGlobalData::CP_TOP_ITEM::CP_ARRAY_ID))); uint32_t cpLen = cpList->GetLength(); ASSERT(cpLen % AOTSnapshotConstants::SNAPSHOT_CP_ARRAY_ITEM_SIZE == 0); - auto &PandaCpInfoInserted = fileNameToMulCpMap.try_emplace(fileNameStr).first->second; + auto &PandaCpInfoInserted = fileNameToMulCpMap.try_emplace(fileNameCStr).first->second; PandaCpInfoInserted.fileIndex_ = fileIndex; MultiConstantPoolMap &cpMap = PandaCpInfoInserted.multiCpsMap_; for (uint32_t pos = 0; pos < cpLen; pos += AOTSnapshotConstants::SNAPSHOT_CP_ARRAY_ITEM_SIZE) { int32_t constantPoolID = cpList->Get(pos).GetInt(); JSTaggedValue cp = cpList->Get(pos + 1); cpMap.insert({constantPoolID, cp}); + if (frameworkHelper.IsFrameworkAbcFile(fileNameStr)) { + thread->GetCurrentEcmaContext()->UpdateConstpool(fileNameStr, cp, constantPoolID); + } } } } diff --git a/ecmascript/compiler/aot_file/aot_file_manager.h b/ecmascript/compiler/aot_file/aot_file_manager.h index e0f8e9428c2d327a5ef355de8327be429511b5ad..39f2fc28c9e81adc55fa335de90d35148821d4cc 100644 --- a/ecmascript/compiler/aot_file/aot_file_manager.h +++ b/ecmascript/compiler/aot_file/aot_file_manager.h @@ -197,6 +197,7 @@ public: static bool TryReadLock(); static bool InsideStub(uintptr_t pc); static bool InsideAOT(uintptr_t pc); + bool IsEnableAOT() const; void Iterate(const RootVisitor &v); const std::shared_ptr GetAnFileInfo(const JSPandaFile *jsPandaFile) const; diff --git a/ecmascript/compiler/aot_file/elf_reader.cpp b/ecmascript/compiler/aot_file/elf_reader.cpp index ed06639f6d6bf65d327075fda5203b91ee37efa2..fe839aecc2e8122ec92426d0055182b13505fde1 100644 --- a/ecmascript/compiler/aot_file/elf_reader.cpp +++ b/ecmascript/compiler/aot_file/elf_reader.cpp @@ -271,7 +271,9 @@ bool ElfReader::ParseELFSegment() ASSERT(phdr[i].p_offset % PageSize() == 0); if ((phdr[i].p_flags & llvm::ELF::PF_X) != 0) { ASSERT(reinterpret_cast(virtualAddr) % PageSize() == 0); - PageProtect(virtualAddr, phdr[i].p_memsz, PAGE_PROT_EXEC_READ); + if (!PageProtect(virtualAddr, phdr[i].p_memsz, PAGE_PROT_EXEC_READ)) { + return false; + } } } return true; diff --git a/ecmascript/compiler/aot_file/stub_file_info.cpp b/ecmascript/compiler/aot_file/stub_file_info.cpp index da036c77fe903fe5f6b06c930498a80352d646c2..00c4625197c85038ddc113be16c162566d652470 100644 --- a/ecmascript/compiler/aot_file/stub_file_info.cpp +++ b/ecmascript/compiler/aot_file/stub_file_info.cpp @@ -158,7 +158,9 @@ bool StubFileInfo::Load() } } LOG_COMPILER(INFO) << "loaded stub file successfully"; - PageProtect(stubsMem_.addr_, stubsMem_.size_, PAGE_PROT_EXEC_READ); + if (!PageProtect(stubsMem_.addr_, stubsMem_.size_, PAGE_PROT_EXEC_READ)) { + return false; + } return true; } diff --git a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp index 2a7ef8d6cc8b5ab91a032689e764f3854b9cc6ce..b4d873fdd6c6e6f14b6d864fbbb08b37ef9e323a 100644 --- a/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp +++ b/ecmascript/compiler/aot_snapshot/snapshot_constantpool_data.cpp @@ -255,7 +255,7 @@ JSHandle BaseSnapshotInfo::GetUnsharedConstpool(const ItemData &da { EcmaContext *context = thread_->GetCurrentEcmaContext(); JSTaggedValue shareCp = context->FindConstpool(jsPandaFile_, data.constantPoolId_); - JSHandle cp(thread_, context->FindUnsharedConstpool(shareCp)); + JSHandle cp(thread_, context->FindOrCreateUnsharedConstpool(shareCp)); return cp; } diff --git a/ecmascript/compiler/array_bounds_check_elimination.cpp b/ecmascript/compiler/array_bounds_check_elimination.cpp index dbfb0345bd059f98810343c3f82880ce0f647a1c..53fd49e956132cd8a26d1c69d48ef510dd9a932f 100644 --- a/ecmascript/compiler/array_bounds_check_elimination.cpp +++ b/ecmascript/compiler/array_bounds_check_elimination.cpp @@ -640,9 +640,7 @@ GateRef ArrayBoundsCheckElimination::PredicateCmpWithConst(GateRef left, TypedBi GateRef ArrayBoundsCheckElimination::PredicateAdd(GateRef left, int32_t leftConst, TypedBinOp cond, GateRef right) { GateRef constGate = builder_.Int32(leftConst); - GateRef binaryOpGate = builder_.InsertTypedBinaryop(left, constGate, GateType::NumberType(), - GateType::NumberType(), GateType::AnyType(), - PGOTypeRef::NoneType(), TypedBinOp::TYPED_ADD); + GateRef binaryOpGate = builder_.InsertTypedBinaryop(left, constGate, TypedBinOp::TYPED_ADD); return Predicate(binaryOpGate, cond, right); } @@ -774,10 +772,10 @@ void ArrayBoundsCheckElimination::ProcessIf(IntegerStack &pushed, GateRegion *pa case TypedBinOp::TYPED_EQ: case TypedBinOp::TYPED_NOTEQ: { if (cond == OpCode::IF_TRUE) { - op = TypedBinaryMetaData::GetRevCompareOp(op); + op = acc_.GetRevCompareOpForTypedBinOp(op); } AddIfCondition(pushed, x, y, op); - AddIfCondition(pushed, y, x, TypedBinaryMetaData::GetSwapCompareOp(op)); + AddIfCondition(pushed, y, x, acc_.GetSwapCompareOpForTypedBinOp(op)); break; } default: @@ -884,16 +882,10 @@ void ArrayBoundsCheckElimination::InBlockMotion(GateLists &indexChecked, GateLis GateRef lowerCompare = index; if (info->min_ > 0) { GateRef minGate = builder_.Int32(info->min_); - lowerCompare = builder_.InsertTypedBinaryop(lowerCompare, minGate, - GateType::NumberType(), GateType::NumberType(), - GateType::AnyType(), PGOTypeRef::NoneType(), - TypedBinOp::TYPED_ADD); + lowerCompare = builder_.InsertTypedBinaryop(lowerCompare, minGate, TypedBinOp::TYPED_ADD); } else if (info->min_ < 0) { GateRef minGate = builder_.Int32(-info->min_); - lowerCompare = builder_.InsertTypedBinaryop(lowerCompare, minGate, - GateType::NumberType(), GateType::NumberType(), - GateType::AnyType(), PGOTypeRef::NoneType(), - TypedBinOp::TYPED_SUB); + lowerCompare = builder_.InsertTypedBinaryop(lowerCompare, minGate, TypedBinOp::TYPED_SUB); } PredicateCmpWithConst(lowerCompare, TypedBinOp::TYPED_GREATEREQ, 0); @@ -903,16 +895,10 @@ void ArrayBoundsCheckElimination::InBlockMotion(GateLists &indexChecked, GateLis if (info->max_ != 0) { if (info->max_ > 0) { GateRef maxGate = builder_.Int32(info->max_); - upperCompare = builder_.InsertTypedBinaryop(upperCompare, maxGate, - GateType::NumberType(), GateType::NumberType(), - GateType::AnyType(), PGOTypeRef::NoneType(), - TypedBinOp::TYPED_ADD); + upperCompare = builder_.InsertTypedBinaryop(upperCompare, maxGate, TypedBinOp::TYPED_ADD); } else if (info->max_ < 0) { GateRef maxGate = builder_.Int32(-info->max_); - upperCompare = builder_.InsertTypedBinaryop(upperCompare, maxGate, - GateType::NumberType(), GateType::NumberType(), - GateType::AnyType(), PGOTypeRef::NoneType(), - TypedBinOp::TYPED_SUB); + upperCompare = builder_.InsertTypedBinaryop(upperCompare, maxGate, TypedBinOp::TYPED_SUB); } } diff --git a/ecmascript/compiler/async_function_lowering.cpp b/ecmascript/compiler/async_function_lowering.cpp index af186fe424114225ac7dacda9581a3f66ee2fb8d..a1b779e396c54caf385948cbcd65c5ad39defa8e 100644 --- a/ecmascript/compiler/async_function_lowering.cpp +++ b/ecmascript/compiler/async_function_lowering.cpp @@ -15,6 +15,8 @@ #include "ecmascript/compiler/async_function_lowering.h" +#include "ecmascript/js_generator_object.h" + namespace panda::ecmascript::kungfu { void AsyncFunctionLowering::ProcessAll() { diff --git a/ecmascript/compiler/async_function_lowering.h b/ecmascript/compiler/async_function_lowering.h index adca55226c7621a35c709e74656297123d0ef8a2..fb05bfaf5496de0c649f04430bc09aae6521802f 100644 --- a/ecmascript/compiler/async_function_lowering.h +++ b/ecmascript/compiler/async_function_lowering.h @@ -18,9 +18,7 @@ #include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/circuit.h" -#include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/circuit_builder.h" -#include "ecmascript/mem/chunk_containers.h" namespace panda::ecmascript::kungfu { class AsyncFunctionLowering { diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp index 16ab38682917916b4fb002355d2ef54931ecf0e4..3fbcce43c0cd2b91e28f6eb31bbea365b415945a 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.cpp @@ -26,6 +26,391 @@ #include "ecmascript/base/array_helper.h" namespace panda::ecmascript::kungfu { +void BuiltinsArrayStubBuilder::With(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + DEFVARIABLE(relativeIndex, VariableType::INT64(), Int64(0)); + DEFVARIABLE(actualIndex, VariableType::INT64(), Int64(0)); + Label isHeapObject(env); + Label isJsArray(env); + Label isStableArray(env); + Label defaultConstr(env); + Label notCOWArray(env); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + BRANCH(IsStableJSArray(glue, thisValue), &isStableArray, slowPath); + Bind(&isStableArray); + BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); + Bind(¬COWArray); + + GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + GateRef index = GetCallArg0(numArgs); + Label taggedIsInt(env); + BRANCH(TaggedIsInt(index), &taggedIsInt, slowPath); + Bind(&taggedIsInt); + { + relativeIndex = GetInt64OfTInt(index); + DEFVARIABLE(value, VariableType::JS_ANY(), Hole()); + Label twoArg(env); + Label ifOneArg(env); + Label getIndex(env); + // 2 : means there are two args + BRANCH(Int64Equal(numArgs, IntPtr(2)), &twoArg, &ifOneArg); + Bind(&twoArg); + { + value = GetCallArg1(numArgs); + Jump(&getIndex); + } + Bind(&ifOneArg); + { + // 1 : means there are only one arg + BRANCH(Int64Equal(numArgs, IntPtr(1)), &getIndex, slowPath); + } + Bind(&getIndex); + { + Label indexGreaterOrEqualZero(env); + Label indexLessZero(env); + Label next(env); + Label notOutOfRange(env); + BRANCH(Int64GreaterThanOrEqual(*relativeIndex, Int64(0)), &indexGreaterOrEqualZero, &indexLessZero); + Bind(&indexGreaterOrEqualZero); + { + actualIndex = *relativeIndex; + Jump(&next); + } + Bind(&indexLessZero); + { + actualIndex = Int64Add(thisLen, *relativeIndex); + Jump(&next); + } + Bind(&next); + { + BRANCH(BoolOr(Int64GreaterThanOrEqual(*actualIndex, thisLen), Int64LessThan(*actualIndex, Int64(0))), + slowPath, ¬OutOfRange); + Bind(¬OutOfRange); + { + GateRef newArray = NewArray(glue, Int32(0)); + GrowElementsCapacity(glue, newArray, TruncInt64ToInt32(thisLen)); + DEFVARIABLE(k, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label loopExit(env); + Label loopNext(env); + Label replaceIndex(env); + Label notReplaceIndex(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + BRANCH(Int64LessThan(*k, thisLen), &loopNext, &loopExit); + Bind(&loopNext); + BRANCH(Int64Equal(*k, *actualIndex), &replaceIndex, ¬ReplaceIndex); + Bind(&replaceIndex); + { + SetValueWithElementsKind(glue, newArray, *value, *k, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + Bind(¬ReplaceIndex); + { + GateRef ele = GetTaggedValueWithElementsKind(thisValue, *k); + Label eleIsHole(env); + Label eleNotHole(env); + BRANCH(TaggedIsHole(ele), &eleIsHole, &eleNotHole); + Bind(&eleIsHole); + { + SetValueWithElementsKind(glue, newArray, Undefined(), *k, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + Bind(&eleNotHole); + { + SetValueWithElementsKind(glue, newArray, ele, *k, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + } + Bind(&loopEnd); + k = Int64Add(*k, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + SetArrayLength(glue, newArray, thisLen); + result->WriteVariable(newArray); + Jump(exit); + } + } + } + } +} + +void BuiltinsArrayStubBuilder::Unshift(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label isHeapObject(env); + Label isJsArray(env); + Label isStableJsArray(env); + Label notOverRange(env); + Label numNotEqualZero(env); + Label numLessThanOrEqualThree(env); + Label loopHead(env); + Label next(env); + Label loopEnd(env); + Label loopExit(env); + Label grow(env); + Label setValue(env); + Label numEqual2(env); + Label numEqual3(env); + Label threeArgs(env); + Label final(env); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(IsStableJSArray(glue, thisValue), &isStableJsArray, slowPath); + Bind(&isStableJsArray); + + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + Label equalCls(env); + GateRef arrayCls = LoadHClass(thisValue); + BRANCH(Equal(intialHClass, arrayCls), &equalCls, slowPath); + Bind(&equalCls); + + BRANCH(Int64GreaterThan(numArgs, IntPtr(0)), &numNotEqualZero, slowPath); + Bind(&numNotEqualZero); + GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + GateRef argLen = ZExtInt32ToInt64(ChangeIntPtrToInt32(numArgs)); + GateRef newLen = Int64Add(thisLen, argLen); + BRANCH(Int64GreaterThan(newLen, Int64(base::MAX_SAFE_INTEGER)), slowPath, ¬OverRange); + Bind(¬OverRange); + // 3 : max param num + BRANCH(Int64LessThanOrEqual(numArgs, IntPtr(3)), &numLessThanOrEqualThree, slowPath); + Bind(&numLessThanOrEqualThree); + { + DEFVARIABLE(elements, VariableType::JS_ANY(), GetElementsArray(thisValue)); + GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(*elements)); + BRANCH(Int64GreaterThan(newLen, capacity), &grow, &setValue); + Bind(&grow); + { + elements = CallRuntime(glue, RTSTUB_ID(JSObjectGrowElementsCapacity), {thisValue, IntToTaggedInt(newLen)}); + Jump(&setValue); + } + Bind(&setValue); + { + DEFVARIABLE(fromKey, VariableType::INT64(), Int64Sub(thisLen, Int64(1))); + DEFVARIABLE(toKey, VariableType::INT64(), Int64Sub(newLen, Int64(1))); + DEFVARIABLE(ele, VariableType::JS_ANY(), Hole()); + Label eleIsHole(env); + Label hasProperty(env); + Label notHasProperty(env); + Label hasException0(env); + Label notHasException0(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + BRANCH(Int64GreaterThanOrEqual(*fromKey, Int64(0)), &next, &loopExit); + Bind(&next); + { + ele = GetTaggedValueWithElementsKind(thisValue, *fromKey); + BRANCH(TaggedIsHole(*ele), &eleIsHole, ¬HasException0); + Bind(&eleIsHole); + { + GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), + { thisValue, IntToTaggedInt(*fromKey) }); + BRANCH(TaggedIsTrue(hasProp), &hasProperty, ¬HasProperty); + Bind(&hasProperty); + { + ele = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*fromKey), + ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + } + Bind(¬HasProperty); + { + SetValueWithElementsKind(glue, thisValue, Hole(), *toKey, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + Bind(¬HasException0); + { + SetValueWithElementsKind(glue, thisValue, *ele, *toKey, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + } + Bind(&loopEnd); + fromKey = Int64Sub(*fromKey, Int64(1)); + toKey = Int64Sub(*toKey, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + { + GateRef value0 = GetCallArg0(numArgs); + // 0 : the first Element position + SetValueWithElementsKind(glue, thisValue, value0, Int64(0), Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + // 2 : the second param + BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(2)), &numEqual2, &numEqual3); + Bind(&numEqual2); + { + GateRef value1 = GetCallArg1(numArgs); + // 1 : the second Element position + SetValueWithElementsKind(glue, thisValue, value1, Int64(1), Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&numEqual3); + } + Bind(&numEqual3); + { + // 3 : the third param + BRANCH(Int64Equal(numArgs, IntPtr(3)), &threeArgs, &final); + Bind(&threeArgs); + GateRef value2 = GetCallArg2(numArgs); + // 2 : the third Element position + SetValueWithElementsKind(glue, thisValue, value2, Int64(2), Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&final); + } + Bind(&final); + { + SetArrayLength(glue, thisValue, newLen); + result->WriteVariable(IntToTaggedPtr(newLen)); + Jump(exit); + } + } + } + } +} + +void BuiltinsArrayStubBuilder::Shift(GateRef glue, GateRef thisValue, + [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label isHeapObject(env); + Label stableJSArray(env); + Label isDefaultConstructor(env); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(HasConstructor(thisValue), slowPath, &isDefaultConstructor); + Bind(&isDefaultConstructor); + GateRef isThisEcmaObject = IsEcmaObject(thisValue); + GateRef isThisStableJSArray = IsStableJSArray(glue, thisValue); + BRANCH(BoolAnd(isThisEcmaObject, isThisStableJSArray), &stableJSArray, slowPath); + Bind(&stableJSArray); + { + Label isLengthWritable(env); + BRANCH(IsArrayLengthWritable(glue, thisValue), &isLengthWritable, slowPath); + Bind(&isLengthWritable); + { + GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + Label lengthNotZero(env); + BRANCH(Int64Equal(thisLen, Int64(0)), exit, &lengthNotZero); + Bind(&lengthNotZero); + { + Label isJsCOWArray(env); + Label getElements(env); + BRANCH(IsJsCOWArray(thisValue), &isJsCOWArray, &getElements); + Bind(&isJsCOWArray); + { + CallRuntime(glue, RTSTUB_ID(CheckAndCopyArray), { thisValue }); + Jump(&getElements); + } + Bind(&getElements); + { + GateRef elements = GetElementsArray(thisValue); + GateRef capacity = ZExtInt32ToInt64(GetLengthOfTaggedArray(elements)); + GateRef index = Int64Sub(thisLen, Int64(1)); + DEFVARIABLE(element, VariableType::JS_ANY(), Hole()); + element = GetTaggedValueWithElementsKind(thisValue, Int64(0)); + Label hasException0(env); + Label taggedHole(env); + Label copyArray(env); + BRANCH(TaggedIsHole(*element), &taggedHole, ©Array); + Bind(&taggedHole); + { + element = FastGetPropertyByIndex(glue, thisValue, Int32(0), ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ©Array); + Bind(&hasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + } + Bind(©Array); + { + DEFVARIABLE(fromKey, VariableType::INT64(), Int64(1)); + DEFVARIABLE(toKey, VariableType::INT64(), Int64Sub(*fromKey, Int64(1))); + Label loopHead(env); + Label loopNext(env); + Label loopEnd(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + BRANCH(Int64LessThan(*fromKey, thisLen), &loopNext, &loopExit); + Bind(&loopNext); + { + GateRef ele = GetTaggedValueWithElementsKind(thisValue, *fromKey); + SetValueWithElementsKind(glue, thisValue, ele, *toKey, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + Bind(&loopEnd); + fromKey = Int64Add(*fromKey, Int64(1)); + toKey = Int64Add(*toKey, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + { + Label noTrim(env); + Label needTrim(env); + Label setNewLen(env); + GateRef unused = Int64Sub(capacity, index); + BRANCH(Int64GreaterThan(unused, Int64(TaggedArray::MAX_END_UNUSED)), &needTrim, &noTrim); + Bind(&needTrim); + { + CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), {glue, elements, index}); + Jump(&setNewLen); + } + Bind(&noTrim); + { + SetValueWithElementsKind(glue, thisValue, Hole(), index, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&setNewLen); + } + Bind(&setNewLen); + { + GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); + Store(VariableType::INT32(), glue, thisValue, lengthOffset, index); + + Label isNotHole(env); + BRANCH(TaggedIsHole(*element), exit, &isNotHole); + Bind(&isNotHole); + { + result->WriteVariable(*element); + Jump(exit); + } + } + } + } + } + } + } + } +} + void BuiltinsArrayStubBuilder::Concat(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { @@ -867,9 +1252,10 @@ void BuiltinsArrayStubBuilder::Sort(GateRef glue, GateRef thisValue, auto env = GetEnvironment(); Label isHeapObject(env); Label isJsArray(env); - Label isStability(env); Label defaultConstr(env); + Label isStability(env); Label notCOWArray(env); + Label argUndefined(env); BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); Bind(&isHeapObject); BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); @@ -881,134 +1267,280 @@ void BuiltinsArrayStubBuilder::Sort(GateRef glue, GateRef thisValue, BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); Bind(¬COWArray); - Label argUndefined(env); GateRef callbackFnHandle = GetCallArg0(numArgs); - GateRef isUndefined = TaggedIsUndefined(callbackFnHandle); - BRANCH(isUndefined, &argUndefined, slowPath); + Branch(TaggedIsUndefined(callbackFnHandle), &argUndefined, slowPath); Bind(&argUndefined); - { - Label isStableJSArray(env); - GateRef stableArray = IsStableJSArray(glue, thisValue); - BRANCH(BoolAnd(stableArray, isUndefined), &isStableJSArray, slowPath); - Bind(&isStableJSArray); - { - GateRef len = ZExtInt32ToInt64(GetArrayLength(thisValue)); - DEFVARIABLE(i, VariableType::INT64(), Int64(1)); - DEFVARIABLE(presentValue, VariableType::JS_ANY(), Undefined()); - DEFVARIABLE(middleValue, VariableType::JS_ANY(), Undefined()); - DEFVARIABLE(previousValue, VariableType::JS_ANY(), Undefined()); - Label loopHead(env); - Label loopEnd(env); - Label next(env); - Label loopExit(env); - Jump(&loopHead); - LoopBegin(&loopHead); - { - BRANCH(Int64LessThan(*i, len), &next, &loopExit); - Bind(&next); - DEFVARIABLE(beginIndex, VariableType::INT64(), Int64(0)); - DEFVARIABLE(endIndex, VariableType::INT64(), *i); - presentValue = GetTaggedValueWithElementsKind(thisValue, *i); - Label loopHead1(env); - Label loopEnd1(env); - Label next1(env); - Label loopExit1(env); - Jump(&loopHead1); - LoopBegin(&loopHead1); - { - BRANCH(Int64LessThan(*beginIndex, *endIndex), &next1, &loopExit1); - Bind(&next1); - GateRef sum = Int64Add(*beginIndex, *endIndex); - GateRef middleIndex = Int64Div(sum, Int64(2)); // 2 : half - middleValue = GetTaggedValueWithElementsKind(thisValue, middleIndex); - Label isInt(env); - BRANCH(BoolAnd(TaggedIsInt(*middleValue), TaggedIsInt(*presentValue)), &isInt, slowPath); - Bind(&isInt); - { - GateRef compareResult = - CallNGCRuntime(glue, RTSTUB_ID(FastArraySort), {*middleValue, *presentValue}); - Label less0(env); - Label greater0(env); - BRANCH(Int32LessThanOrEqual(compareResult, Int32(0)), &less0, &greater0); - Bind(&greater0); - { - endIndex = middleIndex; - Jump(&loopEnd1); - } - Bind(&less0); - { - beginIndex = middleIndex; - beginIndex = Int64Add(*beginIndex, Int64(1)); - Jump(&loopEnd1); - } - } - } - Bind(&loopEnd1); - LoopEnd(&loopHead1); - Bind(&loopExit1); - - Label shouldCopy(env); - GateRef isGreater0 = Int64GreaterThanOrEqual(*endIndex, Int64(0)); - GateRef lessI = Int64LessThan(*endIndex, *i); - BRANCH(BoolAnd(isGreater0, lessI), &shouldCopy, &loopEnd); - Bind(&shouldCopy);{ - DEFVARIABLE(j, VariableType::INT64(), *i); - Label loopHead2(env); - Label loopEnd2(env); - Label next2(env); - Label loopExit2(env); - Jump(&loopHead2); - LoopBegin(&loopHead2); - { - BRANCH(Int64GreaterThan(*j, *endIndex), &next2, &loopExit2); - Bind(&next2); - previousValue = GetTaggedValueWithElementsKind(thisValue, Int64Sub(*j, Int64(1))); - SetValueWithElementsKind(glue, thisValue, *previousValue, *j, Boolean(false), - Int32(static_cast(ElementsKind::NONE))); - Jump(&loopEnd2); - } - Bind(&loopEnd2); - j = Int64Sub(*j, Int64(1)); - LoopEnd(&loopHead2); - Bind(&loopExit2); - SetValueWithElementsKind(glue, thisValue, *presentValue, *endIndex, Boolean(false), - Int32(static_cast(ElementsKind::NONE))); - Jump(&loopEnd); - } - } - Bind(&loopEnd); - i = Int64Add(*i, Int64(1)); - LoopEnd(&loopHead, env, glue); - Bind(&loopExit); - result->WriteVariable(thisValue); - Jump(exit); - } - } + result->WriteVariable(DoSort(glue, thisValue, Boolean(false), result, exit, slowPath)); + Jump(exit); } -void BuiltinsArrayStubBuilder::Reduce(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath) +void BuiltinsArrayStubBuilder::ToSorted(GateRef glue, GateRef thisValue, + GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); - DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0)); Label isHeapObject(env); Label isJsArray(env); Label defaultConstr(env); - Label atLeastOneArg(env); - Label callbackFnHandleHeapObject(env); - Label callbackFnHandleCallable(env); - Label noTypeError(env); - + Label isStability(env); + Label notCOWArray(env); + Label argUndefined(env); BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); Bind(&isHeapObject); BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); Bind(&isJsArray); BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); Bind(&defaultConstr); - thisLen = GetArrayLength(thisValue); - BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath); - Bind(&atLeastOneArg); - GateRef callbackFnHandle = GetCallArg0(numArgs); + BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath); + Bind(&isStability); + BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); + Bind(¬COWArray); + GateRef callbackFnHandle = GetCallArg0(numArgs); + BRANCH(TaggedIsUndefined(callbackFnHandle), &argUndefined, slowPath); + Bind(&argUndefined); + + GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + GateRef receiver = NewArray(glue, thisArrLen); + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + BRANCH(Int64LessThan(*i, thisArrLen), &next, &loopExit); + Bind(&next); + { + GateRef ele = GetTaggedValueWithElementsKind(thisValue, *i); + SetValueWithElementsKind(glue, receiver, ele, *i, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + result->WriteVariable(DoSort(glue, receiver, Boolean(true), result, exit, slowPath)); + Jump(exit); +} + +GateRef BuiltinsArrayStubBuilder::DoSort(GateRef glue, GateRef receiver, GateRef receiverState, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + GateRef len = ZExtInt32ToInt64(GetArrayLength(receiver)); + DEFVARIABLE(i, VariableType::INT64(), Int64(1)); + DEFVARIABLE(presentValue, VariableType::JS_ANY(), Undefined()); + DEFVARIABLE(middleValue, VariableType::JS_ANY(), Undefined()); + DEFVARIABLE(previousValue, VariableType::JS_ANY(), Undefined()); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + BRANCH(Int64LessThan(*i, len), &next, &loopExit); + Bind(&next); + DEFVARIABLE(beginIndex, VariableType::INT64(), Int64(0)); + DEFVARIABLE(endIndex, VariableType::INT64(), *i); + Label presentValueIsHole(env); + Label afterGettingpresentValue(env); + Label presentValueHasProperty(env); + Label presentValueHasException0(env); + presentValue = GetTaggedValueWithElementsKind(receiver, *i); + BRANCH(TaggedIsHole(*presentValue), &presentValueIsHole, &afterGettingpresentValue); + Bind(&presentValueIsHole); + { + GateRef presentValueHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { receiver, IntToTaggedInt(*i) }); + BRANCH(TaggedIsTrue(presentValueHasProp), &presentValueHasProperty, &afterGettingpresentValue); + Bind(&presentValueHasProperty); + { + presentValue = FastGetPropertyByIndex(glue, receiver, TruncInt64ToInt32(*i), ProfileOperation()); + BRANCH(HasPendingException(glue), &presentValueHasException0, &afterGettingpresentValue); + Bind(&presentValueHasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + } + } + Bind(&afterGettingpresentValue); + { + Label loopHead1(env); + Label loopEnd1(env); + Label next1(env); + Label loopExit1(env); + Jump(&loopHead1); + LoopBegin(&loopHead1); + { + Label middleValueIsHole(env); + Label afterGettingmiddleValue(env); + Label middleValueHasProperty(env); + Label middleValueHasException0(env); + BRANCH(Int64LessThan(*beginIndex, *endIndex), &next1, &loopExit1); + Bind(&next1); + GateRef sum = Int64Add(*beginIndex, *endIndex); + GateRef middleIndex = Int64Div(sum, Int64(2)); // 2 : half + middleValue = GetTaggedValueWithElementsKind(receiver, middleIndex); + BRANCH(TaggedIsHole(*middleValue), &middleValueIsHole, &afterGettingmiddleValue); + Bind(&middleValueIsHole); + { + GateRef middleValueHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), + { receiver, IntToTaggedInt(middleIndex) }); + BRANCH(TaggedIsTrue(middleValueHasProp), &middleValueHasProperty, &afterGettingmiddleValue); + Bind(&middleValueHasProperty); + { + middleValue = FastGetPropertyByIndex(glue, receiver, + TruncInt64ToInt32(middleIndex), ProfileOperation()); + BRANCH(HasPendingException(glue), &middleValueHasException0, &afterGettingmiddleValue); + Bind(&middleValueHasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + } + } + Bind(&afterGettingmiddleValue); + { + Label isInt(env); + BRANCH(BoolAnd(TaggedIsInt(*middleValue), TaggedIsInt(*presentValue)), &isInt, slowPath); + Bind(&isInt); + { + GateRef compareResult = + CallNGCRuntime(glue, RTSTUB_ID(FastArraySort), {*middleValue, *presentValue}); + Label less0(env); + Label greater0(env); + BRANCH(Int32LessThanOrEqual(compareResult, Int32(0)), &less0, &greater0); + Bind(&greater0); + { + endIndex = middleIndex; + Jump(&loopEnd1); + } + Bind(&less0); + { + beginIndex = middleIndex; + beginIndex = Int64Add(*beginIndex, Int64(1)); + Jump(&loopEnd1); + } + } + } + } + Bind(&loopEnd1); + LoopEnd(&loopHead1); + Bind(&loopExit1); + + Label shouldCopy(env); + GateRef isGreater0 = Int64GreaterThanOrEqual(*endIndex, Int64(0)); + GateRef lessI = Int64LessThan(*endIndex, *i); + BRANCH(BoolAnd(isGreater0, lessI), &shouldCopy, &loopEnd); + Bind(&shouldCopy); + { + DEFVARIABLE(j, VariableType::INT64(), *i); + Label loopHead2(env); + Label loopEnd2(env); + Label next2(env); + Label loopExit2(env); + Label receiverIsNew(env); + Label receiverIsOrigin(env); + Label receiverIsNew2(env); + Label receiverIsOrigin2(env); + Jump(&loopHead2); + LoopBegin(&loopHead2); + { + Label previousValueIsHole(env); + Label afterGettingpreviousValue(env); + Label previousValueHasProperty(env); + Label previousValueHasException0(env); + BRANCH(Int64GreaterThan(*j, *endIndex), &next2, &loopExit2); + Bind(&next2); + previousValue = GetTaggedValueWithElementsKind(receiver, Int64Sub(*j, Int64(1))); + BRANCH(TaggedIsHole(*previousValue), &previousValueIsHole, &afterGettingpreviousValue); + Bind(&previousValueIsHole); + { + GateRef previousValueHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), + { receiver, IntToTaggedInt(Int64Sub(*j, Int64(1))) }); + BRANCH(TaggedIsTrue(previousValueHasProp), + &previousValueHasProperty, &afterGettingpreviousValue); + Bind(&previousValueHasProperty); + { + previousValue = FastGetPropertyByIndex(glue, receiver, + TruncInt64ToInt32(Int64Sub(*j, Int64(1))), ProfileOperation()); + BRANCH(HasPendingException(glue), &previousValueHasException0, &afterGettingpreviousValue); + Bind(&previousValueHasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + } + } + Bind(&afterGettingpreviousValue); + { + BRANCH(receiverState, &receiverIsNew, &receiverIsOrigin); + Bind(&receiverIsNew); + SetValueWithElementsKind(glue, receiver, *previousValue, *j, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd2); + Bind(&receiverIsOrigin); + SetValueWithElementsKind(glue, receiver, *previousValue, *j, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd2); + } + } + Bind(&loopEnd2); + j = Int64Sub(*j, Int64(1)); + LoopEnd(&loopHead2); + Bind(&loopExit2); + BRANCH(receiverState, &receiverIsNew2, &receiverIsOrigin2); + Bind(&receiverIsNew2); + { + SetValueWithElementsKind(glue, receiver, *presentValue, *endIndex, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + Bind(&receiverIsOrigin2); + { + SetValueWithElementsKind(glue, receiver, *presentValue, *endIndex, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + env->SubCfgExit(); + return receiver; +} + +void BuiltinsArrayStubBuilder::Reduce(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0)); + Label isHeapObject(env); + Label isJsArray(env); + Label defaultConstr(env); + Label atLeastOneArg(env); + Label callbackFnHandleHeapObject(env); + Label callbackFnHandleCallable(env); + Label noTypeError(env); + + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + thisLen = GetArrayLength(thisValue); + BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath); + Bind(&atLeastOneArg); + GateRef callbackFnHandle = GetCallArg0(numArgs); BRANCH(TaggedIsHeapObject(callbackFnHandle), &callbackFnHandleHeapObject, slowPath); Bind(&callbackFnHandleHeapObject); BRANCH(IsCallable(callbackFnHandle), &callbackFnHandleCallable, slowPath); @@ -1152,38 +1684,165 @@ void BuiltinsArrayStubBuilder::Reverse(GateRef glue, GateRef thisValue, [[maybe_ BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); Bind(¬COWArray); - GateRef thisArrLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); - DEFVARIABLE(i, VariableType::INT64(), Int64(0)); - DEFVARIABLE(j, VariableType::INT64(), Int64Sub(thisArrLen, Int64(1))); + result->WriteVariable(DoReverse(glue, thisValue, thisValue, Boolean(false), result, exit)); + Jump(exit); +} + +// Note: unused arguments are reserved for further development +void BuiltinsArrayStubBuilder::ToReversed(GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label isHeapObject(env); + Label isJsArray(env); + Label defaultConstr(env); + Label isStability(env); + Label notCOWArray(env); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath); + Bind(&isStability); + BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); + Bind(¬COWArray); + + GateRef thisArrLen = GetArrayLength(thisValue); + GateRef receiver = NewArray(glue, Int32(0)); + GrowElementsCapacity(glue, receiver, thisArrLen); + SetArrayLength(glue, receiver, thisArrLen); + result->WriteVariable(DoReverse(glue, thisValue, receiver, Boolean(true), result, exit)); + Jump(exit); +} +GateRef BuiltinsArrayStubBuilder::DoReverse(GateRef glue, GateRef thisValue, GateRef receiver, + GateRef receiverState, Variable *result, Label *exit) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + DEFVARIABLE(j, VariableType::INT64(), Int64Sub(ZExtInt32ToInt64(GetArrayLength(thisValue)), Int64(1))); Label loopHead(env); Label loopEnd(env); Label next(env); Label loopExit(env); + Jump(&loopHead); LoopBegin(&loopHead); { - Label arrayValue(env); - Label valueEqual(env); - BRANCH(Int64LessThan(*i, *j), &next, &loopExit); + DEFVARIABLE(lower, VariableType::JS_ANY(), Hole()); + DEFVARIABLE(upper, VariableType::JS_ANY(), Hole()); + Label lowerValueIsHole(env); + Label afterGettingLower(env); + Label lowerHasProperty(env); + Label lowerHasException0(env); + Label upperValueIsHole(env); + Label afterGettingUpper(env); + Label upperHasProperty(env); + Label upperHasException0(env); + Label receiverIsNew(env); + Label receiverIsOrigin(env); + Label lowerIsHole(env); + Label lowerIsNotHole(env); + Label dealWithUpper(env); + Label upperIsHole(env); + Label upperIsNotHole(env); + BRANCH(Int64LessThanOrEqual(*i, *j), &next, &loopExit); Bind(&next); { - GateRef lower = GetTaggedValueWithElementsKind(thisValue, *i); - GateRef upper = GetTaggedValueWithElementsKind(thisValue, *j); - SetValueWithElementsKind(glue, thisValue, upper, *i, Boolean(false), - Int32(static_cast(ElementsKind::NONE))); - SetValueWithElementsKind(glue, thisValue, lower, *j, Boolean(false), - Int32(static_cast(ElementsKind::NONE))); - Jump(&loopEnd); + lower = GetTaggedValueWithElementsKind(thisValue, *i); + BRANCH(TaggedIsHole(*lower), &lowerValueIsHole, &afterGettingLower); + Bind(&lowerValueIsHole); + { + GateRef lowerHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) }); + BRANCH(TaggedIsTrue(lowerHasProp), &lowerHasProperty, &afterGettingLower); + Bind(&lowerHasProperty); + { + lower = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation()); + BRANCH(HasPendingException(glue), &lowerHasException0, &afterGettingLower); + Bind(&lowerHasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + } + } + Bind(&afterGettingLower); + { + upper = GetTaggedValueWithElementsKind(thisValue, *j); + BRANCH(TaggedIsHole(*upper), &upperValueIsHole, &afterGettingUpper); + Bind(&upperValueIsHole); + { + GateRef upperHasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*j) }); + BRANCH(TaggedIsTrue(upperHasProp), &upperHasProperty, &afterGettingUpper); + Bind(&upperHasProperty); + { + upper = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*j), ProfileOperation()); + BRANCH(HasPendingException(glue), &upperHasException0, &afterGettingUpper); + } + Bind(&upperHasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + } + Bind(&afterGettingUpper); + { + BRANCH(receiverState, &receiverIsNew, &receiverIsOrigin); + Bind(&receiverIsNew); + { + BRANCH(TaggedIsHole(*lower), &lowerIsHole, &lowerIsNotHole); + Bind(&lowerIsHole); + { + SetValueWithElementsKind(glue, receiver, Undefined(), *j, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&dealWithUpper); + } + Bind(&lowerIsNotHole); + { + SetValueWithElementsKind(glue, receiver, *lower, *j, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&dealWithUpper); + } + Bind(&dealWithUpper); + { + BRANCH(TaggedIsHole(*upper), &upperIsHole, &upperIsNotHole); + Bind(&upperIsHole); + { + SetValueWithElementsKind(glue, receiver, Undefined(), *i, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + Bind(&upperIsNotHole); + { + SetValueWithElementsKind(glue, receiver, *upper, *i, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + } + Bind(&receiverIsOrigin); + { + SetValueWithElementsKind(glue, receiver, *upper, *i, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + SetValueWithElementsKind(glue, receiver, *lower, *j, Boolean(false), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + } } } Bind(&loopEnd); i = Int64Add(*i, Int64(1)); j = Int64Sub(*j, Int64(1)); - LoopEnd(&loopHead, env, glue); + LoopEnd(&loopHead); Bind(&loopExit); - result->WriteVariable(thisValue); - Jump(exit); + env->SubCfgExit(); + return receiver; } GateRef BuiltinsArrayStubBuilder::IsJsArrayWithLengthLimit(GateRef glue, GateRef object, @@ -2129,19 +2788,14 @@ void BuiltinsArrayStubBuilder::Splice(GateRef glue, GateRef thisValue, GateRef n } } -void BuiltinsArrayStubBuilder::CopyWithin(GateRef glue, GateRef thisValue, GateRef numArgs, +void BuiltinsArrayStubBuilder::ToSpliced(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); - Label thisExists(env); Label isHeapObject(env); Label isJsArray(env); - Label defaultConstr(env); Label isStability(env); - Label notCOWArray(env); - Label equalCls(env); - BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists); - Bind(&thisExists); + Label defaultConstr(env); BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); Bind(&isHeapObject); BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); @@ -2150,6 +2804,7 @@ void BuiltinsArrayStubBuilder::CopyWithin(GateRef glue, GateRef thisValue, GateR Bind(&defaultConstr); BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath); Bind(&isStability); + Label notCOWArray(env); BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); Bind(¬COWArray); @@ -2157,40 +2812,267 @@ void BuiltinsArrayStubBuilder::CopyWithin(GateRef glue, GateRef thisValue, GateR GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + Label equalCls(env); GateRef arrayCls = LoadHClass(thisValue); BRANCH(Equal(intialHClass, arrayCls), &equalCls, slowPath); Bind(&equalCls); - DEFVARIABLE(startPos, VariableType::INT64(), Int64(0)); - DEFVARIABLE(endPos, VariableType::INT64(), Int64(0)); - Label targetTagExists(env); - Label targetTagIsInt(env); - Label startTagExists(env); - Label startTagIsInt(env); - Label afterCallArg1(env); - Label endTagExists(env); - Label endTagIsInt(env); - Label afterCallArg2(env); - GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); - BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &targetTagExists); - Bind(&targetTagExists); - GateRef targetTag = GetCallArg0(numArgs); - BRANCH(TaggedIsInt(targetTag), &targetTagIsInt, slowPath); - Bind(&targetTagIsInt); - GateRef argTarget = SExtInt32ToInt64(TaggedGetInt(targetTag)); - BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &afterCallArg1, &startTagExists); - Bind(&startTagExists); - { - GateRef startTag = GetCallArg1(numArgs); - BRANCH(TaggedIsInt(startTag), &startTagIsInt, slowPath); - Bind(&startTagIsInt); - startPos = SExtInt32ToInt64(TaggedGetInt(startTag)); - Jump(&afterCallArg1); - } - Bind(&afterCallArg1); + GateRef thisLen = GetArrayLength(thisValue); + Label lessThreeArg(env); + DEFVARIABLE(actualStart, VariableType::INT32(), Int32(0)); + DEFVARIABLE(actualDeleteCount, VariableType::INT32(), Int32(0)); + DEFVARIABLE(newLen, VariableType::INT32(), Int32(0)); + DEFVARIABLE(insertCount, VariableType::INT32(), Int32(0)); + GateRef argc = ChangeIntPtrToInt32(numArgs); + // 3: max arg count + BRANCH(Int32LessThanOrEqual(argc, Int32(3)), &lessThreeArg, slowPath); + Bind(&lessThreeArg); { - endPos = thisLen; - BRANCH(Int64GreaterThanOrEqual(IntPtr(2), numArgs), &afterCallArg2, &endTagExists); + Label checkOverFlow(env); + Label greaterZero(env); + Label greaterOne(env); + Label checkGreaterOne(env); + Label notOverFlow(env); + Label copyAfter(env); + // 0: judge the first arg exists + BRANCH(Int32GreaterThan(argc, Int32(0)), &greaterZero, &checkGreaterOne); + Bind(&greaterZero); + { + GateRef taggedStart = GetCallArg0(numArgs); + Label taggedStartInt(env); + BRANCH(TaggedIsInt(taggedStart), &taggedStartInt, slowPath); + Bind(&taggedStartInt); + { + GateRef intStart = GetInt32OfTInt(taggedStart); + actualStart = CalArrayRelativePos(intStart, thisLen); + actualDeleteCount = Int32Sub(thisLen, *actualStart); + Jump(&checkGreaterOne); + } + } + Bind(&checkGreaterOne); + { + // 1: judge the second arg exists + BRANCH(Int32GreaterThan(argc, Int32(1)), &greaterOne, &checkOverFlow); + Bind(&greaterOne); + { + // 2: arg count which is not an item + insertCount = Int32Sub(argc, Int32(2)); + GateRef argDeleteCount = GetCallArg1(numArgs); + Label argDeleteCountInt(env); + BRANCH(TaggedIsInt(argDeleteCount), &argDeleteCountInt, slowPath); + Bind(&argDeleteCountInt); + { + DEFVARIABLE(deleteCount, VariableType::INT32(), TaggedGetInt(argDeleteCount)); + Label deleteCountLessZero(env); + Label calActualDeleteCount(env); + BRANCH(Int32LessThan(*deleteCount, Int32(0)), &deleteCountLessZero, &calActualDeleteCount); + Bind(&deleteCountLessZero); + { + deleteCount = Int32(0); + Jump(&calActualDeleteCount); + } + Bind(&calActualDeleteCount); + { + actualDeleteCount = *deleteCount; + Label lessArrayLen(env); + BRANCH(Int32LessThan(Int32Sub(thisLen, *actualStart), *deleteCount), + &lessArrayLen, &checkOverFlow); + Bind(&lessArrayLen); + { + actualDeleteCount = Int32Sub(thisLen, *actualStart); + Jump(&checkOverFlow); + } + } + } + } + Bind(&checkOverFlow); + { + newLen = Int32Add(Int32Sub(thisLen, *actualDeleteCount), *insertCount); + BRANCH(Int64GreaterThan(ZExtInt32ToInt64(*newLen), Int64(base::MAX_SAFE_INTEGER)), + slowPath, ¬OverFlow); + Bind(¬OverFlow); + Label newLenEmpty(env); + Label newLenNotEmpty(env); + BRANCH(Int32Equal(*newLen, Int32(0)), &newLenEmpty, &newLenNotEmpty); + Bind(&newLenEmpty); + { + NewObjectStubBuilder newBuilder(this); + result->WriteVariable(newBuilder.CreateEmptyArray(glue)); + Jump(exit); + } + Bind(&newLenNotEmpty); + { + Label copyBefore(env); + Label insertArg(env); + GateRef newArray = NewArray(glue, Int32(0)); + GrowElementsCapacity(glue, newArray, *newLen); + DEFVARIABLE(oldIndex, VariableType::INT32(), Int32(0)); + DEFVARIABLE(newIndex, VariableType::INT32(), Int32(0)); + BRANCH(Int32GreaterThan(*actualStart, Int32(0)), ©Before, &insertArg); + Bind(©Before); + { + Label loopHead(env); + Label loopEnd(env); + Label loopNext(env); + Label loopExit(env); + Label eleIsHole(env); + Label eleNotHole(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + BRANCH(Int32LessThan(*oldIndex, *actualStart), &loopNext, &loopExit); + Bind(&loopNext); + GateRef ele = GetTaggedValueWithElementsKind(thisValue, *oldIndex); + BRANCH(TaggedIsHole(ele), &eleIsHole, &eleNotHole); + Bind(&eleIsHole); + { + SetValueWithElementsKind(glue, newArray, Undefined(), *newIndex, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + Bind(&eleNotHole); + { + SetValueWithElementsKind(glue, newArray, ele, *newIndex, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd); + } + } + Bind(&loopEnd); + oldIndex = Int32Add(*oldIndex, Int32(1)); + newIndex = Int32Add(*newIndex, Int32(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(&insertArg); + } + Bind(&insertArg); + { + Label insert(env); + BRANCH(Int32GreaterThan(*insertCount, Int32(0)), &insert, ©After); + Bind(&insert); + { + GateRef insertNum = GetCallArg2(numArgs); + SetValueWithElementsKind(glue, newArray, insertNum, *newIndex, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + newIndex = Int32Add(*newIndex, Int32(1)); + Jump(©After); + } + } + Bind(©After); + { + Label canCopyAfter(env); + Label setLength(env); + oldIndex = Int32Add(*actualStart, *actualDeleteCount); + BRANCH(Int32LessThan(*oldIndex, thisLen), &canCopyAfter, &setLength); + Bind(&canCopyAfter); + { + Label loopHead1(env); + Label loopNext1(env); + Label loopEnd1(env); + Label loopExit1(env); + Label ele1IsHole(env); + Label ele1NotHole(env); + Jump(&loopHead1); + LoopBegin(&loopHead1); + { + BRANCH(Int32LessThan(*oldIndex, thisLen), &loopNext1, &loopExit1); + Bind(&loopNext1); + GateRef ele1 = GetTaggedValueWithElementsKind(thisValue, *oldIndex); + BRANCH(TaggedIsHole(ele1), &ele1IsHole, &ele1NotHole); + Bind(&ele1IsHole); + { + SetValueWithElementsKind(glue, newArray, Undefined(), *newIndex, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd1); + } + Bind(&ele1NotHole); + { + SetValueWithElementsKind(glue, newArray, ele1, *newIndex, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + Jump(&loopEnd1); + } + } + Bind(&loopEnd1); + oldIndex = Int32Add(*oldIndex, Int32(1)); + newIndex = Int32Add(*newIndex, Int32(1)); + LoopEnd(&loopHead1); + Bind(&loopExit1); + Jump(&setLength); + } + Bind(&setLength); + { + SetArrayLength(glue, newArray, *newLen); + result->WriteVariable(newArray); + Jump(exit); + } + } + } + } + } + } +} + +void BuiltinsArrayStubBuilder::CopyWithin(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisExists(env); + Label isHeapObject(env); + Label isJsArray(env); + Label defaultConstr(env); + Label isStability(env); + Label notCOWArray(env); + Label equalCls(env); + BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists); + Bind(&thisExists); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath); + Bind(&isStability); + BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); + Bind(¬COWArray); + + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + GateRef arrayCls = LoadHClass(thisValue); + BRANCH(Equal(intialHClass, arrayCls), &equalCls, slowPath); + Bind(&equalCls); + + DEFVARIABLE(startPos, VariableType::INT64(), Int64(0)); + DEFVARIABLE(endPos, VariableType::INT64(), Int64(0)); + Label targetTagExists(env); + Label targetTagIsInt(env); + Label startTagExists(env); + Label startTagIsInt(env); + Label afterCallArg1(env); + Label endTagExists(env); + Label endTagIsInt(env); + Label afterCallArg2(env); + GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &targetTagExists); + Bind(&targetTagExists); + GateRef targetTag = GetCallArg0(numArgs); + BRANCH(TaggedIsInt(targetTag), &targetTagIsInt, slowPath); + Bind(&targetTagIsInt); + GateRef argTarget = SExtInt32ToInt64(TaggedGetInt(targetTag)); + BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &afterCallArg1, &startTagExists); + Bind(&startTagExists); + { + GateRef startTag = GetCallArg1(numArgs); + BRANCH(TaggedIsInt(startTag), &startTagIsInt, slowPath); + Bind(&startTagIsInt); + startPos = SExtInt32ToInt64(TaggedGetInt(startTag)); + Jump(&afterCallArg1); + } + Bind(&afterCallArg1); + { + endPos = thisLen; + BRANCH(Int64GreaterThanOrEqual(IntPtr(2), numArgs), &afterCallArg2, &endTagExists); Bind(&endTagExists); { GateRef endTag = GetCallArg2(numArgs); @@ -2346,6 +3228,206 @@ GateRef BuiltinsArrayStubBuilder::CalculatePositionWithLength(GateRef position, return ret; } +void BuiltinsArrayStubBuilder::Some(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisExists(env); + Label isHeapObject(env); + Label isJsArray(env); + Label defaultConstr(env); + Label isStability(env); + Label notCOWArray(env); + Label equalCls(env); + BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists); + Bind(&thisExists); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath); + Bind(&isStability); + BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); + Bind(¬COWArray); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + GateRef arrayCls = LoadHClass(thisValue); + BRANCH(Equal(intialHClass, arrayCls), &equalCls, slowPath); + Bind(&equalCls); + + Label arg0HeapObject(env); + Label callable(env); + Label thisIsStable(env); + Label thisNotStable(env); + GateRef callbackFnHandle = GetCallArg0(numArgs); + BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath); + Bind(&arg0HeapObject); + BRANCH(IsCallable(callbackFnHandle), &callable, slowPath); + Bind(&callable); + GateRef argHandle = GetCallArg1(numArgs); + + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue))); + Jump(&thisIsStable); + + Bind(&thisIsStable); + { + DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole()); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label nextStep(env); + Label kValueIsHole(env); + Label callDispatch(env); + Label hasProperty(env); + Label hasException0(env); + Label notHasException0(env); + Label hasException1(env); + Label notHasException1(env); + BRANCH(IsStableJSArray(glue, thisValue), &nextStep, &thisNotStable); + Bind(&nextStep); + BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit); + Bind(&next); + kValue = GetTaggedValueWithElementsKind(thisValue, *i); + BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch); + Bind(&kValueIsHole); + { + GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) }); + BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd); + Bind(&hasProperty); + { + kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException0); + { + BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch); + } + } + } + Bind(&callDispatch); + { + GateRef key = Int64ToTaggedInt(*i); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, + Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, + { argHandle, *kValue, key, thisValue }); + BRANCH(HasPendingException(glue), &hasException1, ¬HasException1); + Bind(&hasException1); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException1); + { + DEFVARIABLE(newLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue))); + Label changeThisLen(env); + Label afterChangeLen(env); + Label retValueIsTrue(env); + BRANCH(Int64LessThan(*newLen, *thisArrLen), &changeThisLen, &afterChangeLen); + Bind(&changeThisLen); + { + thisArrLen = *newLen; + Jump(&afterChangeLen); + } + Bind(&afterChangeLen); + { + BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &retValueIsTrue, &loopEnd); + Bind(&retValueIsTrue); + { + result->WriteVariable(TaggedTrue()); + Jump(exit); + } + } + } + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + result->WriteVariable(TaggedFalse()); + Jump(exit); + } + + Bind(&thisNotStable); + { + DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole()); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label hasProperty(env); + Label hasException0(env); + Label notHasException0(env); + Label callDispatch(env); + Label hasException1(env); + Label notHasException1(env); + BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit); + Bind(&next); + GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) }); + BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd); + Bind(&hasProperty); + { + kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException0); + { + BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch); + Bind(&callDispatch); + { + GateRef key = Int64ToTaggedInt(*i); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, + Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, + { argHandle, *kValue, key, thisValue }); + BRANCH(HasPendingException(glue), &hasException1, ¬HasException1); + Bind(&hasException1); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException1); + { + Label retValueIsTrue(env); + BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &retValueIsTrue, &loopEnd); + Bind(&retValueIsTrue); + { + result->WriteVariable(TaggedTrue()); + Jump(exit); + } + } + } + } + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + result->WriteVariable(TaggedFalse()); + Jump(exit); + } +} + void BuiltinsArrayStubBuilder::Every(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { @@ -2527,10 +3609,215 @@ void BuiltinsArrayStubBuilder::Every(GateRef glue, GateRef thisValue, GateRef nu } } Bind(&loopEnd); - i = Int64Add(*i, Int64(1)); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + result->WriteVariable(TaggedTrue()); + Jump(exit); + } +} + +void BuiltinsArrayStubBuilder::ReduceRight(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisExists(env); + Label isHeapObject(env); + Label isJsArray(env); + Label defaultConstr(env); + Label isStability(env); + Label notCOWArray(env); + Label equalCls(env); + BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists); + Bind(&thisExists); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath); + Bind(&isStability); + BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); + Bind(¬COWArray); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + GateRef arrayCls = LoadHClass(thisValue); + BRANCH(Equal(intialHClass, arrayCls), &equalCls, slowPath); + Bind(&equalCls); + + DEFVARIABLE(thisLen, VariableType::INT32(), Int32(0)); + DEFVARIABLE(accumulator, VariableType::JS_ANY(), Undefined()); + DEFVARIABLE(k, VariableType::INT32(), Int32(0)); + Label atLeastOneArg(env); + Label callbackFnHandleHeapObject(env); + Label callbackFnHandleCallable(env); + Label noTypeError(env); + Label updateAccumulator(env); + Label thisIsStable(env); + Label thisNotStable(env); + thisLen = GetArrayLength(thisValue); + BRANCH(Int64GreaterThanOrEqual(numArgs, IntPtr(1)), &atLeastOneArg, slowPath); + Bind(&atLeastOneArg); + GateRef callbackFnHandle = GetCallArg0(numArgs); + BRANCH(TaggedIsHeapObject(callbackFnHandle), &callbackFnHandleHeapObject, slowPath); + Bind(&callbackFnHandleHeapObject); + BRANCH(IsCallable(callbackFnHandle), &callbackFnHandleCallable, slowPath); + Bind(&callbackFnHandleCallable); + GateRef thisLenIsZero = Int32Equal(*thisLen, Int32(0)); + GateRef numArgsLessThanTwo = Int64LessThan(numArgs, IntPtr(2)); // 2: callbackFn initialValue + BRANCH(BoolAnd(thisLenIsZero, numArgsLessThanTwo), slowPath, &noTypeError); + Bind(&noTypeError); + k = Int32Sub(*thisLen, Int32(1)); + BRANCH(Int64Equal(numArgs, IntPtr(2)), &updateAccumulator, slowPath); // 2: callbackFn initialValue + Bind(&updateAccumulator); + accumulator = GetCallArg1(numArgs); + Jump(&thisIsStable); + + Bind(&thisIsStable); + { + DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole()); + GateRef argsLength = Int32(4); + NewObjectStubBuilder newBuilder(this); + GateRef argList = newBuilder.NewTaggedArray(glue, argsLength); + Label loopHead(env); + Label next(env); + Label loopEnd(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label nextStep(env); + Label kValueIsHole(env); + Label callDispatch(env); + Label hasProperty(env); + Label hasException0(env); + Label notHasException0(env); + Label hasException1(env); + Label notHasException1(env); + GateRef newLen = GetArrayLength(thisValue); + BRANCH(BoolAnd(IsStableJSArray(glue, thisValue), Int32Equal(*thisLen, newLen)), + &nextStep, &thisNotStable); + Bind(&nextStep); + BRANCH(Int32GreaterThanOrEqual(*k, Int32(0)), &next, &loopExit); + Bind(&next); + kValue = GetTaggedValueWithElementsKind(thisValue, *k); + BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch); + Bind(&kValueIsHole); + { + GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*k) }); + BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd); + Bind(&hasProperty); + kValue = FastGetPropertyByIndex(glue, thisValue, *k, ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + result->WriteVariable(Exception()); + Jump(exit); + Bind(¬HasException0); + BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch); + } + Bind(&callDispatch); + { + // callback param 0: accumulator + SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator); + // callback param 1: currentValue + SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), *kValue); + // callback param 2: index + SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k)); + // callback param 3: array + SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue); + GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET)); + GateRef callResult = JSCallDispatch(glue, callbackFnHandle, argsLength, 0, + Circuit::NullGate(), JSCallMode::CALL_THIS_ARGV_WITH_RETURN, + {argsLength, argv, Undefined()}); + BRANCH(HasPendingException(glue), &hasException1, ¬HasException1); + Bind(&hasException1); + { + result->WriteVariable(Exception()); + Jump(exit); + } + + Bind(¬HasException1); + { + accumulator = callResult; + Jump(&loopEnd); + } + } + } + Bind(&loopEnd); + k = Int32Sub(*k, Int32(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + result->WriteVariable(*accumulator); + Jump(exit); + } + + Bind(&thisNotStable); + { + DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole()); + GateRef argsLength = Int32(4); + NewObjectStubBuilder newBuilder(this); + GateRef argList = newBuilder.NewTaggedArray(glue, argsLength); + Label loopHead(env); + Label next(env); + Label loopEnd(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label hasProperty(env); + Label hasException0(env); + Label notHasException0(env); + Label callDispatch(env); + Label hasException1(env); + Label notHasException1(env); + BRANCH(Int32GreaterThanOrEqual(*k, Int32(0)), &next, &loopExit); + Bind(&next); + GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*k) }); + BRANCH(TaggedIsTrue(hasProp), &hasProperty, &loopEnd); + Bind(&hasProperty); + kValue = FastGetPropertyByIndex(glue, thisValue, *k, ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + result->WriteVariable(Exception()); + Jump(exit); + Bind(¬HasException0); + BRANCH(TaggedIsHole(*kValue), &loopEnd, &callDispatch); + Bind(&callDispatch); + { + // callback param 0: accumulator + SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(0), *accumulator); + // callback param 1: currentValue + SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(1), *kValue); + // callback param 2: index + SetValueToTaggedArray(VariableType::INT32(), glue, argList, Int32(2), IntToTaggedInt(*k)); + // callback param 3: array + SetValueToTaggedArray(VariableType::JS_ANY(), glue, argList, Int32(3), thisValue); + GateRef argv = PtrAdd(argList, IntPtr(TaggedArray::DATA_OFFSET)); + GateRef callResult = JSCallDispatch(glue, callbackFnHandle, argsLength, 0, + Circuit::NullGate(), JSCallMode::CALL_THIS_ARGV_WITH_RETURN, + {argsLength, argv, Undefined()}); + BRANCH(HasPendingException(glue), &hasException1, ¬HasException1); + Bind(&hasException1); + { + result->WriteVariable(Exception()); + Jump(exit); + } + + Bind(¬HasException1); + { + accumulator = callResult; + Jump(&loopEnd); + } + } + } + Bind(&loopEnd); + k = Int32Sub(*k, Int32(1)); LoopEnd(&loopHead); Bind(&loopExit); - result->WriteVariable(TaggedTrue()); + result->WriteVariable(*accumulator); Jump(exit); } } @@ -2918,4 +4205,431 @@ void BuiltinsArrayStubBuilder::FindLast(GateRef glue, GateRef thisValue, GateRef Jump(exit); } } + +void BuiltinsArrayStubBuilder::GenArrayConstructor(GateRef glue, GateRef nativeCode, + GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs) +{ + auto env = GetEnvironment(); + DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); + + Label newTargetIsHeapObject(env); + Label newTargetIsJSFunction(env); + Label slowPath(env); + Label slowPath1(env); + Label slowPath2(env); + Label exit(env); + + BRANCH(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); + Bind(&newTargetIsHeapObject); + BRANCH(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); + Bind(&newTargetIsJSFunction); + { + Label fastGetHclass(env); + Label intialHClassIsHClass(env); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + BRANCH(Equal(arrayFunc, newTarget), &fastGetHclass, &slowPath2); + Bind(&fastGetHclass); + GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + DEFVARIABLE(arrayLength, VariableType::INT64(), Int64(0)); + BRANCH(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); + Bind(&intialHClassIsHClass); + { + Label noArg(env); + Label hasArg(env); + Label arrayCreate(env); + BRANCH(Int64Equal(numArgs, IntPtr(0)), &noArg, &hasArg); + Bind(&noArg); + { + Jump(&arrayCreate); + } + Bind(&hasArg); + { + Label hasOneArg(env); + BRANCH(Int64Equal(numArgs, IntPtr(1)), &hasOneArg, &slowPath); + Bind(&hasOneArg); + { + Label argIsNumber(env); + GateRef arg0 = GetArg(numArgs, IntPtr(0)); + BRANCH(TaggedIsNumber(arg0), &argIsNumber, &slowPath); + Bind(&argIsNumber); + { + Label argIsInt(env); + Label argIsDouble(env); + BRANCH(TaggedIsInt(arg0), &argIsInt, &argIsDouble); + Bind(&argIsInt); + { + Label validIntLength(env); + GateRef intLen = GetInt64OfTInt(arg0); + GateRef isGEZero = Int64GreaterThanOrEqual(intLen, Int64(0)); + GateRef isLEMaxLen = Int64LessThanOrEqual(intLen, Int64(JSArray::MAX_ARRAY_INDEX)); + BRANCH(BoolAnd(isGEZero, isLEMaxLen), &validIntLength, &slowPath); + Bind(&validIntLength); + { + arrayLength = intLen; + Jump(&arrayCreate); + } + } + Bind(&argIsDouble); + { + Label validDoubleLength(env); + GateRef doubleLength = GetDoubleOfTDouble(arg0); + GateRef doubleToInt = DoubleToInt(glue, doubleLength); + GateRef intToDouble = CastInt64ToFloat64(SExtInt32ToInt64(doubleToInt)); + GateRef doubleEqual = DoubleEqual(doubleLength, intToDouble); + GateRef doubleLEMaxLen = + DoubleLessThanOrEqual(doubleLength, Double(JSArray::MAX_ARRAY_INDEX)); + BRANCH(BoolAnd(doubleEqual, doubleLEMaxLen), &validDoubleLength, &slowPath); + Bind(&validDoubleLength); + { + arrayLength = SExtInt32ToInt64(doubleToInt); + Jump(&arrayCreate); + } + } + } + } + } + Bind(&arrayCreate); + { + Label lengthValid(env); + BRANCH(Int64GreaterThan(*arrayLength, Int64(JSObject::MAX_GAP)), &slowPath, &lengthValid); + Bind(&lengthValid); + { + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + res = newBuilder.NewJSArrayWithSize(intialHClass, *arrayLength); + GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); + Store(VariableType::INT32(), glue, *res, lengthOffset, TruncInt64ToInt32(*arrayLength)); + GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, + ConstantIndex::ARRAY_LENGTH_ACCESSOR); + SetPropertyInlinedProps(glue, *res, intialHClass, accessor, + Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); + SetExtensibleToBitfield(glue, *res, true); + Jump(&exit); + } + } + } + Bind(&slowPath2); + { + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); + GateRef argv = GetArgv(); + res = CallBuiltinRuntimeWithNewTarget(glue, { glue, nativeCode, func, thisValue, numArgs, argv, newTarget }, + name.c_str()); + Jump(&exit); + } + } + Bind(&slowPath); + { + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); + GateRef argv = GetArgv(); + res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true, name.c_str()); + Jump(&exit); + } + Bind(&slowPath1); + { + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); + res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); + Jump(&exit); + } + + Bind(&exit); + Return(*res); +} + +void BuiltinsArrayStubBuilder::FlatMap(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisExists(env); + Label isHeapObject(env); + Label isJsArray(env); + Label defaultConstr(env); + Label isStability(env); + Label notCOWArray(env); + Label equalCls(env); + BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists); + Bind(&thisExists); + BRANCH(TaggedIsHeapObject(thisValue), &isHeapObject, slowPath); + Bind(&isHeapObject); + BRANCH(IsJsArray(thisValue), &isJsArray, slowPath); + Bind(&isJsArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + BRANCH(IsStableJSArray(glue, thisValue), &isStability, slowPath); + Bind(&isStability); + BRANCH(IsJsCOWArray(thisValue), slowPath, ¬COWArray); + Bind(¬COWArray); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); + GateRef intialHClass = Load(VariableType::JS_ANY(), arrayFunc, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + GateRef arrayCls = LoadHClass(thisValue); + BRANCH(Equal(intialHClass, arrayCls), &equalCls, slowPath); + Bind(&equalCls); + + Label arg0HeapObject(env); + Label callable(env); + Label thisIsStable(env); + Label thisNotStable(env); + Label doFlat(env); + GateRef callbackFnHandle = GetCallArg0(numArgs); + BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath); + Bind(&arg0HeapObject); + BRANCH(IsCallable(callbackFnHandle), &callable, slowPath); + Bind(&callable); + GateRef argHandle = GetCallArg1(numArgs); + + DEFVARIABLE(i, VariableType::INT64(), Int64(0)); + DEFVARIABLE(thisArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue))); + DEFVARIABLE(newArrLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue))); + GateRef mappedArray = NewArray(glue, *thisArrLen); + BRANCH(IsStableJSArray(glue, thisValue), &thisIsStable, &thisNotStable); + + Bind(&thisIsStable); + { + DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole()); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label nextStep(env); + Label kValueIsHole(env); + Label callDispatch(env); + Label hasProperty(env); + Label changeNewArrLen(env); + Label hasException0(env); + Label notHasException0(env); + Label hasException1(env); + Label notHasException1(env); + BRANCH(IsStableJSArray(glue, thisValue), &nextStep, &thisNotStable); + Bind(&nextStep); + BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit); + Bind(&next); + kValue = GetTaggedValueWithElementsKind(thisValue, *i); + BRANCH(TaggedIsHole(*kValue), &kValueIsHole, &callDispatch); + Bind(&kValueIsHole); + { + GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) }); + BRANCH(TaggedIsTrue(hasProp), &hasProperty, &changeNewArrLen); + Bind(&hasProperty); + { + kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException0); + { + BRANCH(TaggedIsHole(*kValue), &changeNewArrLen, &callDispatch); + } + } + Bind(&changeNewArrLen); + { + newArrLen = Int64Sub(*newArrLen, Int64(1)); + Jump(&loopEnd); + } + } + Bind(&callDispatch); + { + GateRef key = Int64ToTaggedInt(*i); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), + 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, + { argHandle, *kValue, key, thisValue }); + BRANCH(HasPendingException(glue), &hasException1, ¬HasException1); + Bind(&hasException1); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException1); + { + DEFVARIABLE(newLen, VariableType::INT64(), ZExtInt32ToInt64(GetArrayLength(thisValue))); + Label changeThisLen(env); + Label afterChangeLen(env); + Label retValueIsHeapObject(env); + Label retValueIsJsArray(env); + BRANCH(Int64LessThan(*newLen, *thisArrLen), &changeThisLen, &afterChangeLen); + Bind(&changeThisLen); + { + newArrLen = Int64Sub(*newArrLen, Int64Sub(*thisArrLen, *newLen)); + thisArrLen = *newLen; + Jump(&afterChangeLen); + } + Bind(&afterChangeLen); + { + SetValueWithElementsKind(glue, mappedArray, retValue, *i, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + BRANCH(TaggedIsHeapObject(retValue), &retValueIsHeapObject, &loopEnd); + Bind(&retValueIsHeapObject); + { + BRANCH(IsJsArray(retValue), &retValueIsJsArray, &loopEnd); + } + Bind(&retValueIsJsArray); + { + GateRef arrLen = ZExtInt32ToInt64(GetArrayLength(retValue)); + newArrLen = Int64Sub(Int64Add(*newArrLen, arrLen), Int64(1)); + Jump(&loopEnd); + } + } + } + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(&doFlat); + } + + Bind(&thisNotStable); + { + DEFVARIABLE(kValue, VariableType::JS_ANY(), Hole()); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label hasProperty(env); + Label changeNewArrLen(env); + Label hasException0(env); + Label notHasException0(env); + Label callDispatch(env); + Label hasException1(env); + Label notHasException1(env); + BRANCH(Int64LessThan(*i, *thisArrLen), &next, &loopExit); + Bind(&next); + GateRef hasProp = CallRuntime(glue, RTSTUB_ID(HasProperty), { thisValue, IntToTaggedInt(*i) }); + BRANCH(TaggedIsTrue(hasProp), &hasProperty, &changeNewArrLen); + Bind(&hasProperty); + { + kValue = FastGetPropertyByIndex(glue, thisValue, TruncInt64ToInt32(*i), ProfileOperation()); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException0); + { + BRANCH(TaggedIsHole(*kValue), &changeNewArrLen, &callDispatch); + } + } + Bind(&changeNewArrLen); + { + newArrLen = Int64Sub(*newArrLen, Int64(1)); + Jump(&loopEnd); + } + Bind(&callDispatch); + { + GateRef key = Int64ToTaggedInt(*i); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), + 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, + { argHandle, *kValue, key, thisValue }); + BRANCH(HasPendingException(glue), &hasException1, ¬HasException1); + Bind(&hasException1); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException1); + { + Label retValueIsHeapObject(env); + Label retValueIsJsArray(env); + SetValueWithElementsKind(glue, mappedArray, retValue, *i, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + BRANCH(TaggedIsHeapObject(retValue), &retValueIsHeapObject, &loopEnd); + Bind(&retValueIsHeapObject); + { + BRANCH(IsJsArray(retValue), &retValueIsJsArray, &loopEnd); + } + Bind(&retValueIsJsArray); + { + GateRef arrLen = ZExtInt32ToInt64(GetArrayLength(retValue)); + newArrLen = Int64Sub(Int64Add(*newArrLen, arrLen), Int64(1)); + Jump(&loopEnd); + } + } + } + } + Bind(&loopEnd); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + Jump(&doFlat); + } + + Bind(&doFlat); + { + i = Int64(0); + DEFVARIABLE(j, VariableType::INT64(), Int64(0)); + GateRef newArray = NewArray(glue, *newArrLen); + Label loopHead2(env); + Label loopEnd2(env); + Label next2(env); + Label loopExit2(env); + Jump(&loopHead2); + LoopBegin(&loopHead2); + { + Label nextStep(env); + Label retValueIsHeapObject(env); + Label retValueIsJsArray(env); + Label retValueIsNotJsArray(env); + BRANCH(Int64LessThan(*i, *thisArrLen), &next2, &loopExit2); + Bind(&next2); + GateRef retValue = GetTaggedValueWithElementsKind(mappedArray, *i); + BRANCH(TaggedIsHole(retValue), &loopEnd2, &nextStep); + Bind(&nextStep); + BRANCH(TaggedIsHeapObject(retValue), &retValueIsHeapObject, &retValueIsNotJsArray); + Bind(&retValueIsHeapObject); + { + BRANCH(IsJsArray(retValue), &retValueIsJsArray, &retValueIsNotJsArray); + Bind(&retValueIsJsArray); + { + GateRef arrLen = ZExtInt32ToInt64(GetArrayLength(retValue)); + DEFVARIABLE(k, VariableType::INT64(), Int64(0)); + Label loopHead3(env); + Label loopEnd3(env); + Label next3(env); + Label loopExit3(env); + Jump(&loopHead3); + LoopBegin(&loopHead3); + { + BRANCH(Int64LessThan(*k, arrLen), &next3, &loopExit3); + Bind(&next3); + SetValueWithElementsKind(glue, newArray, GetTaggedValueWithElementsKind(retValue, *k), *j, + Boolean(true), Int32(static_cast(ElementsKind::NONE))); + j = Int64Add(*j, Int64(1)); + Jump(&loopEnd3); + } + Bind(&loopEnd3); + k = Int64Add(*k, Int64(1)); + LoopEnd(&loopHead3); + Bind(&loopExit3); + Jump(&loopEnd2); + } + } + Bind(&retValueIsNotJsArray); + { + SetValueWithElementsKind(glue, newArray, retValue, *j, Boolean(true), + Int32(static_cast(ElementsKind::NONE))); + j = Int64Add(*j, Int64(1)); + Jump(&loopEnd2); + } + } + Bind(&loopEnd2); + i = Int64Add(*i, Int64(1)); + LoopEnd(&loopHead2); + Bind(&loopExit2); + result->WriteVariable(newArray); + Jump(exit); + } +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_array_stub_builder.h b/ecmascript/compiler/builtins/builtins_array_stub_builder.h index 66e16bc00d846daf046fcd7cf970dcab5d0a79bf..4a4e1f0faf236411e45fcd0337b21033445e6f8f 100644 --- a/ecmascript/compiler/builtins/builtins_array_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_array_stub_builder.h @@ -30,72 +30,27 @@ public: NO_COPY_SEMANTIC(BuiltinsArrayStubBuilder); void GenerateCircuit() override {} - void Concat(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Filter(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Find(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); +#define DECLARE_BUILTINS_ARRAY_STUB_BUILDER(method, ...) \ + void method(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); +BUILTINS_WITH_ARRAY_STUB_BUILDER(DECLARE_BUILTINS_ARRAY_STUB_BUILDER) +#undef DECLARE_BUILTINS_ARRAY_STUB_BUILDER - void FindIndex(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void ForEach(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void IndexOf(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); + void Sort(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); - void LastIndexOf(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Pop(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Slice(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Sort(GateRef glue, GateRef thisValue, - GateRef numArgs, Variable *result, Label *exit, Label *slowPath); - - void Values(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Reduce(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Reverse(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void From(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); - void Splice(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); - - void Push(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Includes(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); - - void CopyWithin(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Every(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void Map(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath); - - void FindLastIndex(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); - - void FindLast(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *result, Label *exit, Label *slowPath); + void GenArrayConstructor(GateRef glue, GateRef nativeCode, GateRef func, + GateRef newTarget, GateRef thisValue, GateRef numArgs); GateRef IsConcatSpreadable(GateRef glue, GateRef obj); GateRef NewArray(GateRef glue, GateRef count); GateRef CalculatePositionWithLength(GateRef position, GateRef length); + + GateRef DoReverse(GateRef glue, GateRef thisValue, GateRef receiver, GateRef receiverState, + Variable *result, Label *exit); + + GateRef DoSort(GateRef glue, GateRef receiver, GateRef receiverState, + Variable *result, Label *exit, Label *slowPath); private: static constexpr uint32_t MAX_LENGTH_ZERO = 0; static constexpr uint32_t MAX_LENGTH_ONE = 1; diff --git a/ecmascript/compiler/builtins/builtins_call_signature.cpp b/ecmascript/compiler/builtins/builtins_call_signature.cpp index 91b4a28a5cc0bc85739f692bec19ca379c6a3364..f61ba6788959a03ec0588092b86c0a3c642dde70 100644 --- a/ecmascript/compiler/builtins/builtins_call_signature.cpp +++ b/ecmascript/compiler/builtins/builtins_call_signature.cpp @@ -39,7 +39,12 @@ void BuiltinsStubCSigns::Initialize() BuiltinsCallSignature::Initialize(&callSigns_[name]); \ COMMON_INIT(name) - BUILTINS_STUB_LIST(INIT_BUILTINS_METHOD) +#define INIT_BUILTINS_METHOD_DYN(name, type, ...) \ + BuiltinsCallSignature::Initialize(&callSigns_[type##name]); \ + COMMON_INIT(type##name) + + BUILTINS_STUB_LIST(INIT_BUILTINS_METHOD, INIT_BUILTINS_METHOD_DYN) +#undef INIT_BUILTINS_METHOD_DYN #undef INIT_BUILTINS_METHOD #undef COMMON_INIT diff --git a/ecmascript/compiler/builtins/builtins_call_signature.h b/ecmascript/compiler/builtins/builtins_call_signature.h index 46ae034eb07af56ce0f44b276eb3ccc8a09d5b93..3a6241a579075d490759b4936e703d3907351fbd 100644 --- a/ecmascript/compiler/builtins/builtins_call_signature.h +++ b/ecmascript/compiler/builtins/builtins_call_signature.h @@ -27,87 +27,135 @@ namespace panda::ecmascript::kungfu { // BUILTINS_STUB_LIST is shared both ASM Interpreter and AOT. // AOT_BUILTINS_STUB_LIST is used in AOT only. -#define BUILTINS_STUB_LIST(V) \ - BUILTINS_METHOD_STUB_LIST(V) \ +#define BUILTINS_STUB_LIST(V, D) \ + BUILTINS_METHOD_STUB_LIST(D, D, D, D) \ + BUILTINS_WITH_CONTAINERS_STUB_BUILDER(D) \ BUILTINS_CONSTRUCTOR_STUB_LIST(V) \ - AOT_AND_BUILTINS_STUB_LIST(V) - -#define BUILTINS_METHOD_STUB_LIST(V) \ - V(StringCharCodeAt) \ - V(StringCodePointAt) \ - V(StringIndexOf) \ - V(StringSubstring) \ - V(StringReplace) \ - V(StringCharAt) \ - V(StringFromCharCode) \ - V(StringTrim) \ - V(StringSlice) \ - V(StringConcat) \ - V(StringStartsWith) \ - V(StringToLowerCase) \ - V(StringEndsWith) \ - V(GetStringIterator) \ - V(ObjectToString) \ - V(ObjectCreate) \ - V(ObjectAssign) \ - V(ObjectHasOwnProperty) \ - V(ObjectKeys) \ - V(VectorForEach) \ - V(VectorReplaceAllElements) \ - V(StackForEach) \ - V(PlainArrayForEach) \ - V(QueueForEach) \ - V(DequeForEach) \ - V(LightWeightMapForEach) \ - V(LightWeightSetForEach) \ - V(HashMapForEach) \ - V(HashSetForEach) \ - V(LinkedListForEach) \ - V(ListForEach) \ - V(ArrayListForEach) \ - V(ArrayListReplaceAllElements) \ - V(FunctionPrototypeApply) \ - V(ArrayConcat) \ - V(ArrayFilter) \ - V(ArrayFind) \ - V(ArrayFindIndex) \ - V(ArrayForEach) \ - V(ArrayIndexOf) \ - V(ArrayMap) \ - V(ArrayLastIndexOf) \ - V(ArrayPop) \ - V(ArraySlice) \ - V(ArrayValues) \ - V(ArrayReduce) \ - V(ArrayReverse) \ - V(ArrayPush) \ - V(ArrayIncludes) \ - V(ArrayFrom) \ - V(ArraySplice) \ - V(ArrayCopyWithin) \ - V(ArrayEvery) \ - V(ArrayFindLastIndex) \ - V(ArrayFindLast) \ - V(SetClear) \ - V(SetValues) \ - V(SetEntries) \ - V(SetForEach) \ - V(SetAdd) \ - V(SetDelete) \ - V(SetHas) \ - V(MapClear) \ - V(MapValues) \ - V(MapEntries) \ - V(MapKeys) \ - V(MapForEach) \ - V(MapSet) \ - V(MapDelete) \ - V(MapHas) \ - V(MapGet) \ - V(NumberParseFloat) \ - V(TypedArraySubArray) \ - V(TypedArrayGetByteLength) \ - V(TypedArrayGetByteOffset) + AOT_AND_BUILTINS_STUB_LIST(V) \ + BUILTINS_ARKTOOLS_STUB_BUILDER(D) + +#define BUILTINS_METHOD_STUB_LIST(V, T, D, K) \ + BUILTINS_WITH_STRING_STUB_BUILDER(V) \ + BUILTINS_WITH_OBJECT_STUB_BUILDER(T) \ + BUILTINS_WITH_ARRAY_STUB_BUILDER(V) \ + BUILTINS_WITH_SET_STUB_BUILDER(D) \ + BUILTINS_WITH_MAP_STUB_BUILDER(D) \ + BUILTINS_WITH_FUNCTION_STUB_BUILDER(V) \ + BUILTINS_WITH_NUMBER_STUB_BUILDER(T) \ + BUILTINS_WITH_TYPEDARRAY_STUB_BUILDER(V) \ + BUILTINS_WITH_DATAVIEW_STUB_BUILDER(K) + +#define BUILTINS_WITH_STRING_STUB_BUILDER(V) \ + V(CharAt, String, Hole()) \ + V(FromCharCode, String, Hole()) \ + V(CharCodeAt, String, DoubleToTaggedDoublePtr(Double(base::NAN_VALUE))) \ + V(CodePointAt, String, Undefined()) \ + V(IndexOf, String, IntToTaggedPtr(Int32(-1))) \ + V(Substring, String, IntToTaggedPtr(Int32(-1))) \ + V(Replace, String, Undefined()) \ + V(Trim, String, Undefined()) \ + V(Concat, String, Undefined()) \ + V(Slice, String, Undefined()) \ + V(ToLowerCase, String, Undefined()) \ + V(StartsWith, String, TaggedFalse()) \ + V(EndsWith, String, TaggedFalse()) \ + V(GetStringIterator, String, Undefined()) + +#define BUILTINS_WITH_OBJECT_STUB_BUILDER(V) \ + V(ToString, Object, Undefined()) \ + V(Create, Object, Undefined()) \ + V(Assign, Object, Undefined()) \ + V(HasOwnProperty, Object, TaggedFalse()) \ + V(Keys, Object, Undefined()) + +#define BUILTINS_WITH_ARRAY_STUB_BUILDER(V) \ + V(With, Array, Undefined()) \ + V(Unshift, Array, Undefined()) \ + V(Shift, Array, Undefined()) \ + V(Concat, Array, Undefined()) \ + V(Filter, Array, Undefined()) \ + V(Find, Array, Undefined()) \ + V(FindIndex, Array, Undefined()) \ + V(From, Array, Undefined()) \ + V(Splice, Array, Undefined()) \ + V(ToSpliced, Array, Undefined()) \ + V(ForEach, Array, Undefined()) \ + V(IndexOf, Array, Undefined()) \ + V(LastIndexOf, Array, Undefined()) \ + V(Pop, Array, Undefined()) \ + V(Slice, Array, Undefined()) \ + V(Reduce, Array, Undefined()) \ + V(Reverse, Array, Undefined()) \ + V(ToReversed, Array, Undefined()) \ + V(Push, Array, Undefined()) \ + V(Values, Array, Undefined()) \ + V(Includes, Array, Undefined()) \ + V(CopyWithin, Array, Undefined()) \ + V(Some, Array, Undefined()) \ + V(Every, Array, Undefined()) \ + V(FindLastIndex, Array, Undefined()) \ + V(FindLast, Array, Undefined()) \ + V(ReduceRight, Array, Undefined()) \ + V(Map, Array, Undefined()) \ + V(FlatMap, Array, Undefined()) \ + V(ToSorted, Array, Undefined()) + +#define BUILTINS_WITH_SET_STUB_BUILDER(V) \ + V(Clear, Set, Undefined()) \ + V(Values, Set, Undefined()) \ + V(Entries, Set, Undefined()) \ + V(ForEach, Set, Undefined()) \ + V(Add, Set, Undefined()) \ + V(Delete, Set, Undefined()) \ + V(Has, Set, Undefined()) + +#define BUILTINS_WITH_MAP_STUB_BUILDER(V) \ + V(Clear, Map, Undefined()) \ + V(Values, Map, Undefined()) \ + V(Entries, Map, Undefined()) \ + V(Keys, Map, Undefined()) \ + V(ForEach, Map, Undefined()) \ + V(Set, Map, Undefined()) \ + V(Delete, Map, Undefined()) \ + V(Has, Map, Undefined()) \ + V(Get, Map, Undefined()) + +#define BUILTINS_WITH_FUNCTION_STUB_BUILDER(V) \ + V(PrototypeApply, Function, Undefined()) + +#define BUILTINS_WITH_NUMBER_STUB_BUILDER(V) \ + V(ParseFloat, Number, Undefined()) + +#define BUILTINS_WITH_TYPEDARRAY_STUB_BUILDER(V) \ + V(Filter, TypedArray, Undefined()) \ + V(Slice, TypedArray, Undefined()) \ + V(SubArray, TypedArray, Undefined()) \ + V(GetByteLength, TypedArray, Undefined()) \ + V(GetByteOffset, TypedArray, Undefined()) + +#define BUILTINS_WITH_DATAVIEW_STUB_BUILDER(V) \ + V(SetInt32, DataView, INT32, SetTypedValue, Undefined()) \ + V(SetFloat32, DataView, FLOAT32, SetTypedValue, Undefined()) \ + V(SetFloat64, DataView, FLOAT64, SetTypedValue, Undefined()) + +#define BUILTINS_WITH_CONTAINERS_STUB_BUILDER(V) \ + V(ForEach, ArrayList, ContainersCommonFuncCall, ARRAYLIST_FOREACH, JS_POINTER) \ + V(ForEach, Deque, DequeCommonFuncCall, DEQUE_FOREACH, JS_POINTER) \ + V(ForEach, HashMap, ContainersHashCall, HASHMAP_FOREACH, JS_POINTER) \ + V(ForEach, HashSet, ContainersHashCall, HASHSET_FOREACH, JS_POINTER) \ + V(ForEach, LightWeightMap, ContainersLightWeightCall, LIGHTWEIGHTMAP_FOREACH, JS_POINTER) \ + V(ForEach, LightWeightSet, ContainersLightWeightCall, LIGHTWEIGHTSET_FOREACH, JS_POINTER) \ + V(ForEach, LinkedList, ContainersLinkedListCall, LINKEDLIST_FOREACH, JS_POINTER) \ + V(ForEach, List, ContainersLinkedListCall, LIST_FOREACH, JS_POINTER) \ + V(ForEach, PlainArray, ContainersCommonFuncCall, PLAINARRAY_FOREACH, JS_POINTER) \ + V(ForEach, Queue, QueueCommonFuncCall, QUEUE_FOREACH, JS_POINTER) \ + V(ForEach, Stack, ContainersCommonFuncCall, STACK_FOREACH, JS_POINTER) \ + V(ForEach, Vector, ContainersCommonFuncCall, VECTOR_FOREACH, JS_POINTER) \ + V(ReplaceAllElements, ArrayList, ContainersCommonFuncCall, ARRAYLIST_REPLACEALLELEMENTS, JS_POINTER) \ + V(ReplaceAllElements, Vector, ContainersCommonFuncCall, VECTOR_REPLACEALLELEMENTS, JS_POINTER) + +#define BUILTINS_ARKTOOLS_STUB_BUILDER(V) \ + V(HashCode, ArkTools, Undefined()) #define BUILTINS_CONSTRUCTOR_STUB_LIST(V) \ V(BooleanConstructor) \ @@ -118,23 +166,21 @@ namespace panda::ecmascript::kungfu { V(MapConstructor) #define AOT_AND_BUILTINS_STUB_LIST(V) \ - V(LocaleCompare) \ - V(STRING_ITERATOR_PROTO_NEXT) \ - V(SORT) + V(StringLocaleCompare) \ + V(StringIteratorProtoNext) \ + V(ArraySort) #define AOT_BUILTINS_STUB_LIST(V) \ - V(SQRT) /* list start and math list start */ \ - V(FLOOR) /* math list end */ \ - V(STRINGIFY) \ - V(MAP_PROTO_ITERATOR) \ - V(SET_PROTO_ITERATOR) \ - V(STRING_PROTO_ITERATOR) \ - V(ARRAY_PROTO_ITERATOR) \ - V(TYPED_ARRAY_PROTO_ITERATOR) \ - V(MAP_ITERATOR_PROTO_NEXT) \ - V(SET_ITERATOR_PROTO_NEXT) \ - V(ARRAY_ITERATOR_PROTO_NEXT) \ - V(ITERATOR_PROTO_RETURN) + V(JsonStringify) \ + V(MapProtoIterator) \ + V(MapIteratorProtoNext) \ + V(SetProtoIterator) \ + V(SetIteratorProtoNext) \ + V(StringProtoIterator) \ + V(ArrayProtoIterator) \ + V(ArrayIteratorProtoNext) \ + V(TypeArrayProtoIterator) \ + V(IteratorProtoReturn) // List of builtins which will try to be inlined in TypedNativeInlineLoweringPass #define AOT_BUILTINS_INLINE_LIST(V) \ @@ -147,34 +193,68 @@ namespace panda::ecmascript::kungfu { V(MathAtanh) \ V(MathCos) \ V(MathCosh) \ + V(MathSign) \ V(MathSin) \ V(MathSinh) \ + V(MathSqrt) \ V(MathTan) \ + V(MathCbrt) \ V(MathTanh) \ V(MathLog) \ V(MathLog2) \ V(MathLog10) \ V(MathLog1p) \ + V(MathExp) \ + V(MathExpm1) \ + V(MathClz32) \ V(MathPow) \ + V(MathTrunc) \ + V(MathCeil) \ + V(MathFloor) \ V(MathAbs) \ + V(MathRound) \ + V(MathFRound) \ + V(MathMin) \ + V(MathMax) \ + V(MathImul) \ + V(GlobalIsFinite) \ + V(GlobalIsNan) \ + V(ArrayBufferIsView) \ + V(DataViewGetFloat32) \ + V(DataViewGetFloat64) \ + V(DataViewGetInt8) \ + V(DataViewGetInt16) \ + V(DataViewGetInt32) \ + V(DataViewGetUint16) \ + V(DataViewGetUint32) \ + V(DataViewGetUint8) \ + V(DataViewSetInt8) \ + V(DataViewSetInt16) \ + V(DataViewSetUint8) \ + V(DataViewSetUint16) \ + V(DataViewSetUint32) \ + V(NumberIsFinite) \ + V(NumberIsInteger) \ + V(NumberIsNaN) \ + V(NumberIsSafeInteger) \ V(TYPED_BUILTINS_INLINE_FIRST = MathAcos) \ - V(TYPED_BUILTINS_INLINE_LAST = MathAbs) + V(TYPED_BUILTINS_INLINE_LAST = NumberIsSafeInteger) class BuiltinsStubCSigns { public: enum ID { #define DEF_STUB_ID(name) name, +#define DEF_STUB_ID_DYN(name, type, ...) type##name, PADDING_BUILTINS_STUB_LIST(DEF_STUB_ID) - BUILTINS_STUB_LIST(DEF_STUB_ID) + BUILTINS_STUB_LIST(DEF_STUB_ID, DEF_STUB_ID_DYN) NUM_OF_BUILTINS_STUBS, AOT_BUILTINS_STUB_LIST(DEF_STUB_ID) AOT_BUILTINS_INLINE_LIST(DEF_STUB_ID) +#undef DEF_STUB_ID_DYN #undef DEF_STUB_ID BUILTINS_CONSTRUCTOR_STUB_FIRST = BooleanConstructor, - TYPED_BUILTINS_FIRST = SQRT, - TYPED_BUILTINS_LAST = ITERATOR_PROTO_RETURN, - TYPED_BUILTINS_MATH_FIRST = SQRT, - TYPED_BUILTINS_MATH_LAST = FLOOR, + TYPED_BUILTINS_FIRST = JsonStringify, + TYPED_BUILTINS_LAST = IteratorProtoReturn, INVALID = 0xFF, }; static_assert(ID::NONE == 0); @@ -212,9 +292,9 @@ public: static bool IsTypedBuiltin(ID builtinId) { - return (BuiltinsStubCSigns::ID::LocaleCompare == builtinId) || - (BuiltinsStubCSigns::ID::STRING_ITERATOR_PROTO_NEXT == builtinId) || - (BuiltinsStubCSigns::ID::SORT == builtinId) || + return (BuiltinsStubCSigns::ID::StringLocaleCompare == builtinId) || + (BuiltinsStubCSigns::ID::StringIteratorProtoNext == builtinId) || + (BuiltinsStubCSigns::ID::ArraySort == builtinId) || ((BuiltinsStubCSigns::ID::TYPED_BUILTINS_FIRST <= builtinId) && (builtinId <= BuiltinsStubCSigns::ID::TYPED_BUILTINS_LAST)); } @@ -224,9 +304,14 @@ public: if (TYPED_BUILTINS_INLINE_FIRST <= builtinId && builtinId <= TYPED_BUILTINS_INLINE_LAST) { return true; } + if (BuiltinsStubCSigns::ID::DataViewSetInt32 <= builtinId && + builtinId <= BuiltinsStubCSigns::ID::DataViewSetFloat64) { + return true; + } // NOTE(schernykh): try to remove this switch and move StringFromCharCode to TYPED_BUILTINS_INLINE list switch (builtinId) { case BuiltinsStubCSigns::ID::StringFromCharCode: + case BuiltinsStubCSigns::ID::MapGet: return true; default: return false; @@ -234,12 +319,6 @@ public: return false; } - static bool IsTypedBuiltinMath(ID builtinId) - { - return (BuiltinsStubCSigns::ID::TYPED_BUILTINS_MATH_FIRST <= builtinId) && - (builtinId <= BuiltinsStubCSigns::ID::TYPED_BUILTINS_MATH_LAST); - } - static bool IsTypedBuiltinNumber(ID builtinId) { return BuiltinsStubCSigns::ID::NumberConstructor == builtinId; @@ -248,11 +327,22 @@ public: static bool IsTypedBuiltinCallThis0(ID builtinId) { switch (builtinId) { - case BuiltinsStubCSigns::ID::MAP_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::SET_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::STRING_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::ARRAY_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::ITERATOR_PROTO_RETURN: + case BuiltinsStubCSigns::ID::MapIteratorProtoNext: + case BuiltinsStubCSigns::ID::SetIteratorProtoNext: + case BuiltinsStubCSigns::ID::StringIteratorProtoNext: + case BuiltinsStubCSigns::ID::ArrayIteratorProtoNext: + case BuiltinsStubCSigns::ID::IteratorProtoReturn: + case BuiltinsStubCSigns::ID::ArraySort: + return true; + default: + return false; + } + } + + static bool IsTypedBuiltinCallThis1(ID builtinId) + { + switch (builtinId) { + case BuiltinsStubCSigns::ID::JsonStringify: return true; default: return false; @@ -262,7 +352,7 @@ public: static bool IsTypedBuiltinCallThis3(ID builtinId) { switch (builtinId) { - case BuiltinsStubCSigns::ID::LocaleCompare: + case BuiltinsStubCSigns::ID::StringLocaleCompare: return true; default: return false; @@ -290,6 +380,8 @@ public: return ConstantIndex::MATH_COS_INDEX; case BuiltinsStubCSigns::ID::MathCosh: return ConstantIndex::MATH_COSH_INDEX; + case BuiltinsStubCSigns::ID::MathSign: + return ConstantIndex::MATH_SIGN_INDEX; case BuiltinsStubCSigns::ID::MathSin: return ConstantIndex::MATH_SIN_INDEX; case BuiltinsStubCSigns::ID::MathSinh: @@ -308,30 +400,100 @@ public: return ConstantIndex::MATH_LOG10_INDEX; case BuiltinsStubCSigns::ID::MathLog1p: return ConstantIndex::MATH_LOG1P_INDEX; + case BuiltinsStubCSigns::ID::MathExp: + return ConstantIndex::MATH_EXP_INDEX; + case BuiltinsStubCSigns::ID::MathExpm1: + return ConstantIndex::MATH_EXPM1_INDEX; + case BuiltinsStubCSigns::ID::MathClz32: + return ConstantIndex::MATH_CLZ32_INDEX; case BuiltinsStubCSigns::ID::MathPow: return ConstantIndex::MATH_POW_INDEX; - case BuiltinsStubCSigns::ID::FLOOR: - return ConstantIndex::MATH_FLOOR_FUNCTION_INDEX; - case BuiltinsStubCSigns::ID::SQRT: - return ConstantIndex::MATH_SQRT_FUNCTION_INDEX; - case BuiltinsStubCSigns::ID::LocaleCompare: + case BuiltinsStubCSigns::ID::MathCbrt: + return ConstantIndex::MATH_CBRT_INDEX; + case BuiltinsStubCSigns::ID::MathTrunc: + return ConstantIndex::MATH_TRUNC_INDEX; + case BuiltinsStubCSigns::ID::MathCeil: + return ConstantIndex::MATH_CEIL_INDEX; + case BuiltinsStubCSigns::ID::MathFloor: + return ConstantIndex::MATH_FLOOR_INDEX; + case BuiltinsStubCSigns::ID::MathMin: + return ConstantIndex::MATH_MIN_INDEX; + case BuiltinsStubCSigns::ID::MathMax: + return ConstantIndex::MATH_MAX_INDEX; + case BuiltinsStubCSigns::ID::MathSqrt: + return ConstantIndex::MATH_SQRT_INDEX; + case BuiltinsStubCSigns::ID::MathRound: + return ConstantIndex::MATH_ROUND_INDEX; + case BuiltinsStubCSigns::ID::MathFRound: + return ConstantIndex::MATH_FROUND_INDEX; + case BuiltinsStubCSigns::ID::MathImul: + return ConstantIndex::MATH_IMUL_INDEX; + case BuiltinsStubCSigns::ID::MapGet: + return ConstantIndex::MAP_GET_INDEX; + case BuiltinsStubCSigns::ID::StringLocaleCompare: return ConstantIndex::LOCALE_COMPARE_FUNCTION_INDEX; - case BuiltinsStubCSigns::ID::SORT: + case BuiltinsStubCSigns::ID::ArraySort: return ConstantIndex::ARRAY_SORT_FUNCTION_INDEX; - case BuiltinsStubCSigns::ID::STRINGIFY: + case BuiltinsStubCSigns::ID::JsonStringify: return ConstantIndex::JSON_STRINGIFY_FUNCTION_INDEX; - case BuiltinsStubCSigns::ID::MAP_ITERATOR_PROTO_NEXT: + case BuiltinsStubCSigns::ID::MapIteratorProtoNext: return ConstantIndex::MAP_ITERATOR_PROTO_NEXT_INDEX; - case BuiltinsStubCSigns::ID::SET_ITERATOR_PROTO_NEXT: + case BuiltinsStubCSigns::ID::SetIteratorProtoNext: return ConstantIndex::SET_ITERATOR_PROTO_NEXT_INDEX; - case BuiltinsStubCSigns::ID::STRING_ITERATOR_PROTO_NEXT: + case BuiltinsStubCSigns::ID::StringIteratorProtoNext: return ConstantIndex::STRING_ITERATOR_PROTO_NEXT_INDEX; - case BuiltinsStubCSigns::ID::ARRAY_ITERATOR_PROTO_NEXT: + case BuiltinsStubCSigns::ID::ArrayIteratorProtoNext: return ConstantIndex::ARRAY_ITERATOR_PROTO_NEXT_INDEX; - case BuiltinsStubCSigns::ID::ITERATOR_PROTO_RETURN: + case BuiltinsStubCSigns::ID::IteratorProtoReturn: return ConstantIndex::ITERATOR_PROTO_RETURN_INDEX; case BuiltinsStubCSigns::ID::StringFromCharCode: return ConstantIndex::STRING_FROM_CHAR_CODE_INDEX; + case BuiltinsStubCSigns::ID::GlobalIsFinite: + return ConstantIndex::GLOBAL_IS_FINITE_INDEX; + case BuiltinsStubCSigns::ID::GlobalIsNan: + return ConstantIndex::GLOBAL_IS_NAN_INDEX; + case BuiltinsStubCSigns::ID::ArrayBufferIsView: + return ConstantIndex::ARRAY_BUFFER_IS_VIEW_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetFloat32: + return ConstantIndex::DATA_VIEW_GET_FLOAT32_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetFloat64: + return ConstantIndex::DATA_VIEW_GET_FLOAT64_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetInt8: + return ConstantIndex::DATA_VIEW_GET_INT8_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetInt16: + return ConstantIndex::DATA_VIEW_GET_INT16_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetInt32: + return ConstantIndex::DATA_VIEW_GET_INT32_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetUint16: + return ConstantIndex::DATA_VIEW_GET_UINT16_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetUint32: + return ConstantIndex::DATA_VIEW_GET_UINT32_INDEX; + case BuiltinsStubCSigns::ID::DataViewGetUint8: + return ConstantIndex::DATA_VIEW_GET_UINT8_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetFloat32: + return ConstantIndex::DATA_VIEW_SET_FLOAT32_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetFloat64: + return ConstantIndex::DATA_VIEW_SET_FLOAT64_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetInt8: + return ConstantIndex::DATA_VIEW_SET_INT8_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetInt16: + return ConstantIndex::DATA_VIEW_SET_INT16_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetInt32: + return ConstantIndex::DATA_VIEW_SET_INT32_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetUint8: + return ConstantIndex::DATA_VIEW_SET_UINT8_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetUint16: + return ConstantIndex::DATA_VIEW_SET_UINT16_INDEX; + case BuiltinsStubCSigns::ID::DataViewSetUint32: + return ConstantIndex::DATA_VIEW_SET_UINT32_INDEX; + case BuiltinsStubCSigns::ID::NumberIsFinite: + return ConstantIndex::NUMBER_IS_FINITE_INDEX; + case BuiltinsStubCSigns::ID::NumberIsInteger: + return ConstantIndex::NUMBER_IS_INTEGER_INDEX; + case BuiltinsStubCSigns::ID::NumberIsNaN: + return ConstantIndex::NUMBER_IS_NAN_INDEX; + case BuiltinsStubCSigns::ID::NumberIsSafeInteger: + return ConstantIndex::NUMBER_IS_SAFEINTEGER_INDEX; default: LOG_COMPILER(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -340,34 +502,94 @@ public: static size_t GetGlobalEnvIndex(ID builtinId); + static std::string GetBuiltinName(ID id) + { + static const std::map builtinId2Str = { + {MathAcos, "Math.acos"}, + {MathAcosh, "Math.acosh"}, + {MathAsin, "Math.asin"}, + {MathAsinh, "Math.asinh"}, + {MathAtan, "Math.atan"}, + {MathAtan2, "Math.atan2"}, + {MathAtanh, "Math.atanh"}, + {MathCos, "Math.cos"}, + {MathCosh, "Math.cosh"}, + {MathSign, "Math.sign"}, + {MathSin, "Math.sin"}, + {MathSinh, "Math.sinh"}, + {MathTan, "Math.tan"}, + {MathTanh, "Math.tanh"}, + {MathLog, "Math.log"}, + {MathLog2, "Math.log2"}, + {MathLog10, "Math.log10"}, + {MathLog1p, "Math.log1p"}, + {MathExp, "Math.exp"}, + {MathExpm1, "Math.expm1"}, + {MathClz32, "Math.clz32"}, + {MathSqrt, "Math.sqrt"}, + {MathCbrt, "Math.cbrt"}, + {MathAbs, "Math.abs"}, + {MathPow, "Math.pow"}, + {MathTrunc, "Math.trunc"}, + {MathRound, "Math.round"}, + {MathFRound, "Math.fround"}, + {MathCeil, "Math.ceil"}, + {MathFloor, "Math.floor"}, + {MathImul, "Math.imul"}, + {MathMax, "Math.max"}, + {MathMin, "Math.min"}, + {GlobalIsFinite, "isFinite"}, + {GlobalIsNan, "isNan"}, + {MapGet, "Map.get"}, + }; + if (builtinId2Str.count(id) > 0) { + return builtinId2Str.at(id); + } + return ""; + } + static ID GetBuiltinId(std::string idStr) { - const std::map str2BuiltinId = { - {"Acos", MathAcos}, - {"Acosh", MathAcosh}, - {"Asin", MathAsin}, - {"Asinh", MathAsinh}, - {"Atan", MathAtan}, - {"Atan2", MathAtan2}, - {"Atanh", MathAtanh}, - {"Cos", MathCos}, - {"Cosh", MathCosh}, - {"Sin", MathSin}, - {"Sinh", MathSinh}, - {"Tan", MathTan}, - {"Tanh", MathTanh}, - {"Log", MathLog}, - {"Log2", MathLog2}, - {"Log10", MathLog10}, - {"Log1p", MathLog1p}, - {"sqrt", SQRT}, + static const std::map str2BuiltinId = { + {"acos", MathAcos}, + {"acosh", MathAcosh}, + {"asin", MathAsin}, + {"asinh", MathAsinh}, + {"atan", MathAtan}, + {"atan2", MathAtan2}, + {"atanh", MathAtanh}, + {"cos", MathCos}, + {"cosh", MathCosh}, + {"sign", MathSign}, + {"sin", MathSin}, + {"sinh", MathSinh}, + {"tan", MathTan}, + {"tanh", MathTanh}, + {"log", MathLog}, + {"log2", MathLog2}, + {"log10", MathLog10}, + {"log1p", MathLog1p}, + {"exp", MathExp}, + {"expm1", MathExpm1}, + {"clz32", MathClz32}, + {"sqrt", MathSqrt}, + {"cbrt", MathCbrt}, {"abs", MathAbs}, {"pow", MathPow}, - {"floor", FLOOR}, - {"localeCompare", LocaleCompare}, - {"next", STRING_ITERATOR_PROTO_NEXT}, - {"sort", SORT}, - {"stringify", STRINGIFY}, + {"trunc", MathTrunc}, + {"round", MathRound}, + {"fround", MathFRound}, + {"ceil", MathCeil}, + {"floor", MathFloor}, + {"imul", MathImul}, + {"max", MathMax}, + {"min", MathMin}, + {"localeCompare", StringLocaleCompare}, + {"next", StringIteratorProtoNext}, + {"sort", ArraySort}, + {"stringify", JsonStringify}, + {"isFinite", GlobalIsFinite}, + {"isNan", GlobalIsNan}, }; if (str2BuiltinId.count(idStr) > 0) { return str2BuiltinId.at(idStr); @@ -399,9 +621,9 @@ enum class BuiltinsArgs : size_t { #define PGO_BUILTINS_STUB_ID(name) ((-1) * kungfu::BuiltinsStubCSigns::name) #define IS_TYPED_BUILTINS_ID(id) kungfu::BuiltinsStubCSigns::IsTypedBuiltin(id) #define IS_TYPED_INLINE_BUILTINS_ID(id) kungfu::BuiltinsStubCSigns::IsTypedInlineBuiltin(id) -#define IS_TYPED_BUILTINS_MATH_ID(id) kungfu::BuiltinsStubCSigns::IsTypedBuiltinMath(id) #define IS_TYPED_BUILTINS_NUMBER_ID(id) kungfu::BuiltinsStubCSigns::IsTypedBuiltinNumber(id) #define IS_TYPED_BUILTINS_ID_CALL_THIS0(id) kungfu::BuiltinsStubCSigns::IsTypedBuiltinCallThis0(id) +#define IS_TYPED_BUILTINS_ID_CALL_THIS1(id) kungfu::BuiltinsStubCSigns::IsTypedBuiltinCallThis1(id) #define IS_TYPED_BUILTINS_ID_CALL_THIS3(id) kungfu::BuiltinsStubCSigns::IsTypedBuiltinCallThis3(id) #define GET_TYPED_CONSTANT_INDEX(id) kungfu::BuiltinsStubCSigns::GetConstantIndex(id) #define GET_TYPED_GLOBAL_ENV_INDEX(id) kungfu::BuiltinsStubCSigns::GetGlobalEnvIndex(id) diff --git a/ecmascript/compiler/builtins/builtins_collection_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_collection_stub_builder.cpp index 451df9e85d50ce610870113bc2c514ef465e7757..e60f4eaf278145bbe3055b1530113952ad909bb8 100644 --- a/ecmascript/compiler/builtins/builtins_collection_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_collection_stub_builder.cpp @@ -135,12 +135,13 @@ void BuiltinsCollectionStubBuilder::ForEach(Variable *result, La GateRef linkedTable = GetLinked(); GateRef res = Circuit::NullGate(); + GateRef thisArg = GetCallArg1(numArgs_); if constexpr (std::is_same_v) { LinkedHashTableStubBuilder linkedHashTableStubBuilder(this, glue_); - res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, numArgs_); + res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, callbackFnHandle, thisArg); } else { LinkedHashTableStubBuilder linkedHashTableStubBuilder(this, glue_); - res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, numArgs_); + res = linkedHashTableStubBuilder.ForEach(thisValue_, linkedTable, callbackFnHandle, thisArg); } Label exception(env); diff --git a/ecmascript/compiler/builtins/builtins_dataview_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_dataview_stub_builder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..397e2e7371a2bb2e0bb4924f0c6e689f05e4c291 --- /dev/null +++ b/ecmascript/compiler/builtins/builtins_dataview_stub_builder.cpp @@ -0,0 +1,225 @@ +/* + * 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. + */ + +#include "ecmascript/compiler/builtins/builtins_dataview_stub_builder.h" + +#include "ecmascript/builtins/builtins_arraybuffer.h" +#include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h" +#include "ecmascript/compiler/new_object_stub_builder.h" +#include "ecmascript/compiler/stub_builder-inl.h" + +namespace panda::ecmascript::kungfu { +template +void BuiltinsDataViewStubBuilder::SetTypedValue(GateRef glue, GateRef thisValue, + GateRef numArgs, [[maybe_unused]] Variable* res, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisIsHeapObject(env); + Label thisIsDataView(env); + Label indexIsInt(env); + BRANCH(TaggedIsHeapObject(thisValue), &thisIsHeapObject, slowPath); + Bind(&thisIsHeapObject); + BRANCH(IsDataView(thisValue), &thisIsDataView, slowPath); + Bind(&thisIsDataView); + GateRef indexTagged = GetCallArg0(numArgs); + GateRef value = GetCallArg1(numArgs); + BRANCH(TaggedIsInt(indexTagged), &indexIsInt, slowPath); + Bind(&indexIsInt); + { + DEFVARIABLE(isLittleEndian, VariableType::JS_ANY(), TaggedFalse()); + Label indexIsValid(env); + Label valueIsValid(env); + Label checkOffset(env); + Label getArrayBuffer(env); + Label setValue(env); + Label toBool(env); + GateRef index = GetInt32OfTInt(indexTagged); + BRANCH(Int32LessThan(index, Int32(0)), slowPath, &indexIsValid); + Bind(&indexIsValid); + { + BRANCH(TaggedIsNumber(value), &valueIsValid, slowPath); + Bind(&valueIsValid); + GateRef littleEndianHandle; // need to init + if (type == DataViewType::UINT8 || type == DataViewType::INT8) { + littleEndianHandle = TaggedTrue(); + } else { + littleEndianHandle = GetCallArg2(numArgs); + } + BRANCH(TaggedIsUndefined(littleEndianHandle), &getArrayBuffer, &toBool); + Bind(&toBool); + { + isLittleEndian = FastToBoolean(littleEndianHandle, 1); + Jump(&getArrayBuffer); + } + Bind(&getArrayBuffer); + { + GateRef buffer = GetViewedArrayBuffer(thisValue); + BRANCH(IsDetachedBuffer(buffer), slowPath, &checkOffset); + Bind(&checkOffset); + { + GateRef offset = GetByteOffset(thisValue); + GateRef size = GetByteLength(thisValue); + GateRef elementSize = GetElementSize(type); + BRANCH(Int32GreaterThan(Int32Add(index, elementSize), size), slowPath, &setValue); + Bind(&setValue); + { + GateRef bufferIndex = Int32Add(index, offset); + BuiltinsTypedArrayStubBuilder builder(this); + GateRef pointer = builder.GetDataPointFromBuffer(buffer); + GateRef doubleValue = TaggedGetNumber(value); + if (type == DataViewType::INT32 || type == DataViewType::UINT32) { + SetValueInBufferForInt32(glue, pointer, bufferIndex, + DoubleToInt(glue, doubleValue), *isLittleEndian); + } else if (type == DataViewType::FLOAT32) { + GateRef flaotValue = TruncDoubleToFloat32(doubleValue); + SetValueInBufferForInt32(glue, pointer, bufferIndex, + CastFloat32ToInt32(flaotValue), *isLittleEndian); + } else if (type == DataViewType::FLOAT64) { + GateRef int64Value = CastDoubleToInt64(doubleValue); + SetValueInBufferForInt64(glue, pointer, bufferIndex, + int64Value, *isLittleEndian); + } + Jump(exit); + } + } + } + } + } +} + +template void BuiltinsDataViewStubBuilder::SetTypedValue(GateRef glue, GateRef thisValue, + GateRef numArgs, Variable* res, Label *exit, Label *slowPath); +template void BuiltinsDataViewStubBuilder::SetTypedValue(GateRef glue, GateRef thisValue, + GateRef numArgs, Variable* res, Label *exit, Label *slowPath); +template void BuiltinsDataViewStubBuilder::SetTypedValue(GateRef glue, GateRef thisValue, + GateRef numArgs, Variable* res, Label *exit, Label *slowPath); + +void BuiltinsDataViewStubBuilder::SetValueInBufferForInt32(GateRef glue, GateRef pointer, GateRef offset, + GateRef value, GateRef littleEndianHandle) +{ + auto env = GetEnvironment(); + Label subentry(env); + env->SubCfgEntry(&subentry); + Label exit(env); + Label littleEnd(env); + Label notLittleEnd(env); + GateRef b0 = Int32And(value, Int32(0xFF)); + GateRef b1 = Int32And(Int32LSR(value, Int32(builtins::BITS_EIGHT)), Int32(0xFF)); + GateRef b2 = Int32And(Int32LSR(value, Int32(2 * builtins::BITS_EIGHT)), Int32(0xFF)); + GateRef b3 = Int32LSR(value, Int32(builtins::BITS_TWENTY_FOUR)); + + BRANCH(TaggedIsTrue(littleEndianHandle), &littleEnd, ¬LittleEnd); + Bind(&littleEnd); + { + Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b0)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b1)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b2)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b3)); + Jump(&exit); + } + Bind(¬LittleEnd); + { + Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b3)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b2)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b1)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b0)); + Jump(&exit); + } + Bind(&exit); + env->SubCfgExit(); +} + +void BuiltinsDataViewStubBuilder::SetValueInBufferForInt64(GateRef glue, GateRef pointer, GateRef offset, + GateRef value, GateRef littleEndianHandle) +{ + auto env = GetEnvironment(); + Label subentry(env); + env->SubCfgEntry(&subentry); + Label exit(env); + Label littleEnd(env); + Label notLittleEnd(env); + GateRef lowerInt32 = TruncInt64ToInt32(Int64And(value, Int64(0xFFFFFFFF))); // NOLINT + GateRef highInt32 = TruncInt64ToInt32(Int64LSR(Int64And(value, Int64(0xFFFFFFFF00000000)), Int64(32))); // NOLINT + + GateRef b0 = Int32And(lowerInt32, Int32(builtins::BITS_MASK_FF)); + GateRef b1 = Int32And(Int32LSR(lowerInt32, Int32(builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF)); + // 2: 2 * 8 bits + GateRef b2 = Int32And(Int32LSR(lowerInt32, Int32(2 * builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF)); + GateRef b3 = Int32LSR(lowerInt32, Int32(builtins::BITS_TWENTY_FOUR)); + GateRef b4 = Int32And(highInt32, Int32(builtins::BITS_MASK_FF)); + GateRef b5 = Int32And(Int32LSR(highInt32, Int32(builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF)); + // 2: 2 * 8 bits + GateRef b6 = Int32And(Int32LSR(highInt32, Int32(2 * builtins::BITS_EIGHT)), Int32(builtins::BITS_MASK_FF)); + GateRef b7 = Int32LSR(highInt32, Int32(builtins::BITS_TWENTY_FOUR)); + + BRANCH(TaggedIsTrue(littleEndianHandle), &littleEnd, ¬LittleEnd); + Bind(&littleEnd); + { + Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b0)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b1)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b2)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b3)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FOUR)), TruncInt32ToInt8(b4)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FIVE)), TruncInt32ToInt8(b5)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SIX)), TruncInt32ToInt8(b6)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SEVEN)), TruncInt32ToInt8(b7)); + Jump(&exit); + } + Bind(¬LittleEnd); + { + Store(VariableType::INT8(), glue, pointer, offset, TruncInt32ToInt8(b7)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(1)), TruncInt32ToInt8(b6)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::TWO)), TruncInt32ToInt8(b5)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::THREE)), TruncInt32ToInt8(b4)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FOUR)), TruncInt32ToInt8(b3)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::FIVE)), TruncInt32ToInt8(b2)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SIX)), TruncInt32ToInt8(b1)); + Store(VariableType::INT8(), glue, pointer, Int32Add(offset, Int32(OffsetIndex::SEVEN)), TruncInt32ToInt8(b0)); + Jump(&exit); + } + Bind(&exit); + env->SubCfgExit(); +} + +GateRef BuiltinsDataViewStubBuilder::GetElementSize(DataViewType type) +{ + GateRef size; + switch (type) { + case DataViewType::INT8: + case DataViewType::UINT8: + case DataViewType::UINT8_CLAMPED: + size = Int32(1); + break; + case DataViewType::INT16: + case DataViewType::UINT16: + size = Int32(2); // 2 means the length + break; + case DataViewType::INT32: + case DataViewType::UINT32: + case DataViewType::FLOAT32: + size = Int32(4); // 4 means the length + break; + case DataViewType::FLOAT64: + case DataViewType::BIGINT64: + case DataViewType::BIGUINT64: + size = Int32(8); // 8 means the length + break; + default: + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + } + return size; +} +} // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_dataview_stub_builder.h b/ecmascript/compiler/builtins/builtins_dataview_stub_builder.h new file mode 100644 index 0000000000000000000000000000000000000000..091aaaececfd0a740591b0a6666937b6cc5aa1a1 --- /dev/null +++ b/ecmascript/compiler/builtins/builtins_dataview_stub_builder.h @@ -0,0 +1,40 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_COMPILER_BUILTINS_DATAVIEW_STUB_BUILDER_H +#define ECMASCRIPT_COMPILER_BUILTINS_DATAVIEW_STUB_BUILDER_H +#include "ecmascript/compiler/builtins/builtins_stubs.h" +#include "ecmascript/js_dataview.h" +namespace panda::ecmascript::kungfu { +class BuiltinsDataViewStubBuilder : public BuiltinsStubBuilder { +public: + enum OffsetIndex : uint8_t { ZERO = 0, ONE, TWO, THREE, FOUR, FIVE, SIX, SEVEN}; + explicit BuiltinsDataViewStubBuilder(StubBuilder *parent) + : BuiltinsStubBuilder(parent) {} + ~BuiltinsDataViewStubBuilder() override = default; + NO_MOVE_SEMANTIC(BuiltinsDataViewStubBuilder); + NO_COPY_SEMANTIC(BuiltinsDataViewStubBuilder); + void GenerateCircuit() override {} + template + void SetTypedValue(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable* res, Label *exit, Label *slowPath); + void SetValueInBufferForInt32(GateRef glue, GateRef pointer, GateRef offset, + GateRef value, GateRef littleEndianHandle); + void SetValueInBufferForInt64(GateRef glue, GateRef pointer, GateRef offset, + GateRef value, GateRef littleEndianHandle); + GateRef GetElementSize(DataViewType type); +}; +} // namespace panda::ecmascript::kungfu +#endif // ECMASCRIPT_COMPILER_BUILTINS_DATAVIEW_STUB_BUILDER_H \ No newline at end of file diff --git a/ecmascript/compiler/builtins/builtins_function_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_function_stub_builder.cpp index bc33c773f6d71937ef16e1791bb004d10136b12e..62a59c773f84d2c986283924425ec4e5c8dffdf1 100644 --- a/ecmascript/compiler/builtins/builtins_function_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_function_stub_builder.cpp @@ -22,7 +22,7 @@ namespace panda::ecmascript::kungfu { -void BuiltinsFunctionStubBuilder::Apply(GateRef glue, GateRef thisValue, +void BuiltinsFunctionStubBuilder::PrototypeApply(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath) { auto env = GetEnvironment(); diff --git a/ecmascript/compiler/builtins/builtins_function_stub_builder.h b/ecmascript/compiler/builtins/builtins_function_stub_builder.h index babea4fce2d3eb34dcf7356f5abc220a76717c9c..41fa8701ac6dbbc74b662a0b4b76b60795db51fc 100644 --- a/ecmascript/compiler/builtins/builtins_function_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_function_stub_builder.h @@ -26,7 +26,11 @@ public: NO_MOVE_SEMANTIC(BuiltinsFunctionStubBuilder); NO_COPY_SEMANTIC(BuiltinsFunctionStubBuilder); void GenerateCircuit() override {} - void Apply(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); +#define DECLARE_BUILTINS_FUNCTION_STUB_BUILDER(method, ...) \ + void method(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); +BUILTINS_WITH_FUNCTION_STUB_BUILDER(DECLARE_BUILTINS_FUNCTION_STUB_BUILDER) +#undef DECLARE_BUILTINS_FUNCTION_STUB_BUILDER + GateRef BuildArgumentsListFastElements(GateRef glue, GateRef arrayObj); private: GateRef MakeArgListWithHole(GateRef glue, GateRef argv, GateRef length); diff --git a/ecmascript/compiler/builtins/builtins_number_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_number_stub_builder.cpp index c60bea0085875720a301bd614bc41fe0f87ea6a3..d876bd18e2329ec3e1b634fb85295704c74d6648 100644 --- a/ecmascript/compiler/builtins/builtins_number_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_number_stub_builder.cpp @@ -15,8 +15,10 @@ #include "ecmascript/compiler/builtins/builtins_number_stub_builder.h" +#include "ecmascript/compiler/new_object_stub_builder.h" #include "ecmascript/compiler/stub_builder-inl.h" #include "ecmascript/js_arguments.h" +#include "ecmascript/js_primitive_ref.h" #include "ecmascript/tagged_dictionary.h" namespace panda::ecmascript::kungfu { @@ -46,4 +48,88 @@ void BuiltinsNumberStubBuilder::ParseFloat(Variable *result, Label *exit, Label } } } + +void BuiltinsNumberStubBuilder::GenNumberConstructor(GateRef nativeCode, GateRef func, GateRef newTarget) +{ + auto env = GetEnvironment(); + DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); + DEFVARIABLE(numberValue, VariableType::JS_ANY(), IntToTaggedPtr(IntPtr(0))); + Label thisCollectionObj(env); + Label slowPath(env); + Label slowPath1(env); + Label slowPath2(env); + Label exit(env); + + Label hasArg(env); + Label numberCreate(env); + Label newTargetIsHeapObject(env); + BRANCH(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); + Bind(&newTargetIsHeapObject); + BRANCH(Int64GreaterThan(numArgs_, IntPtr(0)), &hasArg, &numberCreate); + Bind(&hasArg); + { + GateRef value = GetArgNCheck(Int32(0)); + Label number(env); + BRANCH(TaggedIsNumber(value), &number, &slowPath); + Bind(&number); + { + numberValue = value; + res = value; + Jump(&numberCreate); + } + } + + Bind(&numberCreate); + Label newObj(env); + Label newTargetIsJSFunction(env); + BRANCH(TaggedIsUndefined(newTarget), &exit, &newObj); + Bind(&newObj); + { + BRANCH(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); + Bind(&newTargetIsJSFunction); + { + Label intialHClassIsHClass(env); + GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, + IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); + BRANCH(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); + Bind(&intialHClassIsHClass); + { + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue_, 0); + Label afterNew(env); + newBuilder.NewJSObject(&res, &afterNew, intialHClass); + Bind(&afterNew); + { + GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET); + Store(VariableType::INT64(), glue_, *res, valueOffset, *numberValue); + Jump(&exit); + } + } + Bind(&slowPath2); + { + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); + GateRef argv = GetArgv(); + res = CallBuiltinRuntimeWithNewTarget(glue_, + { glue_, nativeCode, func, thisValue_, numArgs_, argv, newTarget }, name.c_str()); + Jump(&exit); + } + } + } + + Bind(&slowPath); + { + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); + GateRef argv = GetArgv(); + res = CallBuiltinRuntime(glue_, { glue_, nativeCode, func, thisValue_, numArgs_, argv }, true, name.c_str()); + Jump(&exit); + } + Bind(&slowPath1); + { + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); + res = CallSlowPath(nativeCode, glue_, thisValue_, numArgs_, func, newTarget, name.c_str()); + Jump(&exit); + } + Bind(&exit); + Return(*res); +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_number_stub_builder.h b/ecmascript/compiler/builtins/builtins_number_stub_builder.h index 564fc2ffda95de81998ccc7bbd8451796cdd7f50..511819557810a1ce6b00457c316a8ff2ed0bcc41 100644 --- a/ecmascript/compiler/builtins/builtins_number_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_number_stub_builder.h @@ -28,7 +28,12 @@ public: NO_MOVE_SEMANTIC(BuiltinsNumberStubBuilder); NO_COPY_SEMANTIC(BuiltinsNumberStubBuilder); void GenerateCircuit() override {} - void ParseFloat(Variable *result, Label *exit, Label *slowPath); +#define DECLARE_BUILTINS_NUMBER_STUB_BUILDER(method, ...) \ + void method(Variable *result, Label *exit, Label *slowPath); +BUILTINS_WITH_NUMBER_STUB_BUILDER(DECLARE_BUILTINS_NUMBER_STUB_BUILDER) +#undef DECLARE_BUILTINS_NUMBER_STUB_BUILDER + + void GenNumberConstructor(GateRef nativeCode, GateRef func, GateRef newTarget); private: GateRef glue_ { Circuit::NullGate() }; diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp index 5a382826100e67f7e40942dca6ee7b4e81e46447..2a5326b867b255d2ba89a75c72f819cc3ed54050 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.cpp @@ -15,10 +15,10 @@ #include "ecmascript/compiler/builtins/builtins_object_stub_builder.h" +#include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h" #include "ecmascript/compiler/circuit_builder_helper.h" #include "ecmascript/compiler/new_object_stub_builder.h" #include "ecmascript/compiler/stub_builder-inl.h" -#include "ecmascript/compiler/typed_array_stub_builder.h" #include "ecmascript/js_arguments.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/message_string.h" @@ -57,7 +57,7 @@ GateRef BuiltinsObjectStubBuilder::CreateListFromArrayLike(GateRef glue, GateRef GateRef int32Len = GetLengthOfJSTypedArray(arrayObj); NewObjectStubBuilder newBuilder(this); GateRef array = newBuilder.NewTaggedArray(glue, int32Len); - TypedArrayStubBuilder arrayStubBuilder(this); + BuiltinsTypedArrayStubBuilder arrayStubBuilder(this); arrayStubBuilder.FastCopyElementToArray(glue, arrayObj, array); // c. ReturnIfAbrupt(next). Label isPendingException2(env); @@ -299,7 +299,7 @@ void BuiltinsObjectStubBuilder::Create(Variable *result, Label *exit, Label *slo GateRef proto = GetCallArg0(numArgs_); GateRef protoIsNull = TaggedIsNull(proto); GateRef protoIsEcmaObj = IsEcmaObject(proto); - GateRef protoIsJSShared = TaggedIsShared(proto); + GateRef protoIsJSShared = TaggedIsSharedObj(proto); BRANCH(BoolOr(BoolAnd(BoolNot(protoIsEcmaObj), BoolNot(protoIsNull)), protoIsJSShared), slowPath, &newObject); Bind(&newObject); { @@ -1214,10 +1214,15 @@ GateRef BuiltinsObjectStubBuilder::GetEnumElementKeys(GateRef glue, GateRef obj) LoopEnd(&loopHead, env, glue); Bind(&afterLoop); { - Store(VariableType::INT32(), glue_, - elementArray, IntPtr(TaggedArray::LENGTH_OFFSET), *elementIndex); result = elementArray; - Jump(&exit); + Label needTrim(env); + BRANCH(Int32LessThan(*elementIndex, numOfElements), &needTrim, &exit); + Bind(&needTrim); + { + CallNGCRuntime(glue, RTSTUB_ID(ArrayTrim), + {glue, elementArray, ZExtInt32ToInt64(*elementIndex)}); + Jump(&exit); + } } } } diff --git a/ecmascript/compiler/builtins/builtins_object_stub_builder.h b/ecmascript/compiler/builtins/builtins_object_stub_builder.h index a5c79f34e3bb8621b5a2aef7eaeea792254ce6e2..ccc1fd0eb4ce89054328bbb5fd73d50235c40ed2 100644 --- a/ecmascript/compiler/builtins/builtins_object_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_object_stub_builder.h @@ -28,13 +28,14 @@ public: NO_MOVE_SEMANTIC(BuiltinsObjectStubBuilder); NO_COPY_SEMANTIC(BuiltinsObjectStubBuilder); void GenerateCircuit() override {} + +#define DECLARE_BUILTINS_OBJECT_STUB_BUILDER(method, ...) \ + void method(Variable *result, Label *exit, Label *slowPath); +BUILTINS_WITH_OBJECT_STUB_BUILDER(DECLARE_BUILTINS_OBJECT_STUB_BUILDER) +#undef DECLARE_BUILTINS_OBJECT_STUB_BUILDER + GateRef CreateListFromArrayLike(GateRef glue, GateRef arrayObj); GateRef CreateArrayFromList(GateRef glue, GateRef elements); - void ToString(Variable *result, Label *exit, Label *slowPath); - void Create(Variable *result, Label *exit, Label *slowPath); - void Assign(Variable *result, Label *exit, Label *slowPath); - void HasOwnProperty(Variable *result, Label *exit, Label *slowPath); - void Keys(Variable *result, Label *exit, Label *slowPath); private: GateRef OrdinaryNewJSObjectCreate(GateRef proto); diff --git a/ecmascript/compiler/builtins/builtins_string_stub_builder.h b/ecmascript/compiler/builtins/builtins_string_stub_builder.h index f3b5656f1f37fd74056a94cecea14b26e0099bc3..d39b14e19eb76abc435eda139dcfcbb502e3a130 100644 --- a/ecmascript/compiler/builtins/builtins_string_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_string_stub_builder.h @@ -32,22 +32,12 @@ public: NO_COPY_SEMANTIC(BuiltinsStringStubBuilder); void GenerateCircuit() override {} - void FromCharCode(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); - void CharAt(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); - void CharCodeAt(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); - void CodePointAt(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); - void IndexOf(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); - void Substring(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); - void Replace(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); - void Trim(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); - void Slice(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); +#define DECLARE_BUILTINS_SRRING_STUB_BUILDER(method, ...) \ + void method(GateRef glue, GateRef thisValue, GateRef numArgs, Variable* res, Label *exit, Label *slowPath); +BUILTINS_WITH_STRING_STUB_BUILDER(DECLARE_BUILTINS_SRRING_STUB_BUILDER) +#undef DECLARE_BUILTINS_SRRING_STUB_BUILDER + void LocaleCompare(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); - void Concat(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); - void StartsWith(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); - void ToLowerCase(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); - void EndsWith(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); - void GetStringIterator(GateRef glue, GateRef thisValue, GateRef numArgs, - Variable *res, Label *exit, Label *slowPath); void StringIteratorNext(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *res, Label *exit, Label *slowPath); diff --git a/ecmascript/compiler/builtins/builtins_stubs.cpp b/ecmascript/compiler/builtins/builtins_stubs.cpp index 7796862bfeb9be1a8be54d765a30f5ffbfd0e0d5..12e77bb5679be9aa0daf1cac0576824b26163e69 100644 --- a/ecmascript/compiler/builtins/builtins_stubs.cpp +++ b/ecmascript/compiler/builtins/builtins_stubs.cpp @@ -18,20 +18,23 @@ #include "ecmascript/base/number_helper.h" #include "ecmascript/compiler/builtins/builtins_array_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_call_signature.h" +#include "ecmascript/compiler/builtins/builtins_dataview_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_function_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_string_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_number_stub_builder.h" +#include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h" #include "ecmascript/compiler/builtins/containers_vector_stub_builder.h" #include "ecmascript/compiler/builtins/containers_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_collection_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_object_stub_builder.h" #include "ecmascript/compiler/codegen/llvm/llvm_ir_builder.h" -#include "ecmascript/compiler/typed_array_stub_builder.h" #include "ecmascript/compiler/interpreter_stub-inl.h" #include "ecmascript/compiler/new_object_stub_builder.h" #include "ecmascript/compiler/stub_builder-inl.h" #include "ecmascript/compiler/stub_builder.h" +#include "ecmascript/compiler/hash_stub_builder.h" #include "ecmascript/compiler/variable_type.h" +#include "ecmascript/js_dataview.h" #include "ecmascript/js_date.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/linked_hash_table.h" @@ -152,18 +155,18 @@ GateRef BuiltinsStubBuilder::CallSlowPath(GateRef nativeCode, GateRef glue, Gate return ret; } -#define DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER(method, resultVariableType, initValue) \ -DECLARE_BUILTINS(String##method) \ +#define DECLARE_BUILTINS_STUB_BUILDER(method, type, initValue) \ +DECLARE_BUILTINS(type##method) \ { \ auto env = GetEnvironment(); \ - DEFVARIABLE(res, VariableType::resultVariableType(), initValue); \ + DEFVARIABLE(res, VariableType::JS_ANY(), initValue); \ Label exit(env); \ Label slowPath(env); \ - BuiltinsStringStubBuilder stringStubBuilder(this); \ - stringStubBuilder.method(glue, thisValue, numArgs, &res, &exit, &slowPath); \ + Builtins##type##StubBuilder builder(this); \ + builder.method(glue, thisValue, numArgs, &res, &exit, &slowPath); \ Bind(&slowPath); \ { \ - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(String##method)); \ + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ @@ -171,150 +174,108 @@ DECLARE_BUILTINS(String##method) Return(*res); \ } -#define BUILTINS_WITH_STRING_STUB_BUILDER(V) \ - V(CharAt, JS_POINTER, Hole()) \ - V(FromCharCode, JS_ANY, Hole()) \ - V(CharCodeAt, JS_ANY, DoubleToTaggedDoublePtr(Double(base::NAN_VALUE))) \ - V(CodePointAt, JS_ANY, Undefined()) \ - V(IndexOf, JS_ANY, IntToTaggedPtr(Int32(-1))) \ - V(Substring, JS_ANY, IntToTaggedPtr(Int32(-1))) \ - V(Replace, JS_ANY, Undefined()) \ - V(Trim, JS_ANY, Undefined()) \ - V(Concat, JS_ANY, Undefined()) \ - V(Slice, JS_ANY, Undefined()) \ - V(ToLowerCase, JS_ANY, Undefined()) \ - V(StartsWith, JS_ANY, TaggedFalse()) \ - V(EndsWith, JS_ANY, TaggedFalse()) - -DECLARE_BUILTINS(LocaleCompare) -{ - auto env = GetEnvironment(); - DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - Label exit(env); - Label slowPath(env); - BuiltinsStringStubBuilder stringStubBuilder(this); - stringStubBuilder.LocaleCompare(glue, thisValue, numArgs, &res, &exit, &slowPath); - Bind(&slowPath); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(LocaleCompare)); - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); - Jump(&exit); - } - Bind(&exit); - Return(*res); +#define DECLARE_BUILTINS_STUB_BUILDER1(method, type, initValue) \ +DECLARE_BUILTINS(type##method) \ +{ \ + auto env = GetEnvironment(); \ + DEFVARIABLE(res, VariableType::JS_ANY(), initValue); \ + Label thisCollectionObj(env); \ + Label slowPath(env); \ + Label exit(env); \ + Builtins##type##StubBuilder builder(this, glue, thisValue, numArgs); \ + builder.method(&res, &exit, &slowPath); \ + Bind(&slowPath); \ + { \ + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ + res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ + Jump(&exit); \ + } \ + Bind(&exit); \ + Return(*res); \ } -DECLARE_BUILTINS(GetStringIterator) -{ - auto env = GetEnvironment(); - DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - Label exit(env); - Label slowPath(env); - BuiltinsStringStubBuilder stringStubBuilder(this); - stringStubBuilder.GetStringIterator(glue, thisValue, numArgs, &res, &exit, &slowPath); - Bind(&slowPath); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(GetStringIterator)); - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); - Jump(&exit); - } - Bind(&exit); - Return(*res); +// map and set stub function +#define DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(method, type, retDefaultValue) \ +DECLARE_BUILTINS(type##method) \ +{ \ + auto env = GetEnvironment(); \ + DEFVARIABLE(res, VariableType::JS_ANY(), retDefaultValue); \ + Label slowPath(env); \ + Label exit(env); \ + BuiltinsCollectionStubBuilder builder(this, glue, thisValue, numArgs); \ + builder.method(&res, &exit, &slowPath); \ + Bind(&slowPath); \ + { \ + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ + res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ + Jump(&exit); \ + } \ + Bind(&exit); \ + Return(*res); \ } -DECLARE_BUILTINS(STRING_ITERATOR_PROTO_NEXT) -{ - auto env = GetEnvironment(); - DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - Label exit(env); - Label slowPath(env); - BuiltinsStringStubBuilder stringStubBuilder(this); - stringStubBuilder.StringIteratorNext(glue, thisValue, numArgs, &res, &exit, &slowPath); - Bind(&slowPath); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(STRING_ITERATOR_PROTO_NEXT)); - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); - Jump(&exit); - } - Bind(&exit); - Return(*res); +// map and set stub function +#define DECLARE_BUILTINS_DATAVIEW_STUB_BUILDER(method, type, numType, function, retDefaultValue) \ +DECLARE_BUILTINS(type##method) \ +{ \ + auto env = GetEnvironment(); \ + DEFVARIABLE(res, VariableType::JS_ANY(), retDefaultValue); \ + Label slowPath(env); \ + Label exit(env); \ + BuiltinsDataViewStubBuilder builder(this); \ + builder.function(glue, thisValue, numArgs, &res, &exit, &slowPath); \ + Bind(&slowPath); \ + { \ + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ + res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ + Jump(&exit); \ + } \ + Bind(&exit); \ + Return(*res); \ } -BUILTINS_WITH_STRING_STUB_BUILDER(DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER) - -#undef DECLARE_BUILTINS_WITH_STRING_STUB_BUILDER -#undef BUILTINS_WITH_STRING_STUB_BUILDER +BUILTINS_METHOD_STUB_LIST(DECLARE_BUILTINS_STUB_BUILDER, DECLARE_BUILTINS_STUB_BUILDER1, + DECLARE_BUILTINS_COLLECTION_STUB_BUILDER, DECLARE_BUILTINS_DATAVIEW_STUB_BUILDER) +#undef DECLARE_BUILTINS_STUB_BUILDER +#undef DECLARE_BUILTINS_STUB_BUILDER1 +#undef DECLARE_BUILTINS_COLLECTION_STUB_BUILDER +#undef DECLARE_BUILTINS_DATAVIEW_STUB_BUILDER -DECLARE_BUILTINS(FunctionPrototypeApply) +DECLARE_BUILTINS(ArkToolsHashCode) { + (void) nativeCode; + (void) func; + (void) newTarget; + (void) thisValue; auto env = GetEnvironment(); - DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - Label exit(env); - Label slowPath(env); - BuiltinsFunctionStubBuilder functionStubBuilder(this); - functionStubBuilder.Apply(glue, thisValue, numArgs, &res, &exit, &slowPath); - Bind(&slowPath); + GateRef key = GetCallArg0(numArgs); + + Label irHash(env); + Label rtHash(env); + BRANCH(IntPtrEqual(numArgs, IntPtr(1)), &irHash, &rtHash); + Bind(&irHash); { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(FunctionPrototypeApply)); - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); - Jump(&exit); + HashStubBuilder hashBuilder(this, glue); + GateRef hash = hashBuilder.GetHash(key); + Return(env->GetBuilder()->Int32ToTaggedPtr(hash)); } - Bind(&exit); - Return(*res); + Bind(&rtHash); + Return(CallRuntime(glue, RTSTUB_ID(GetLinkedHash), { key })); } -#define DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER(StubName, Method, methodType, resultVariableType) \ -DECLARE_BUILTINS(StubName) \ -{ \ - auto env = GetEnvironment(); \ - DEFVARIABLE(res, VariableType::resultVariableType(), Undefined()); \ - Label exit(env); \ - Label slowPath(env); \ - ContainersStubBuilder containersBuilder(this); \ - containersBuilder.Method(glue, thisValue, numArgs, &res, &exit, &slowPath, ContainersType::methodType); \ - Bind(&slowPath); \ - { \ - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(StubName)); \ - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ - Jump(&exit); \ - } \ - Bind(&exit); \ - Return(*res); \ -} - -#define BUILTINS_WITH_CONTAINERS_STUB_BUILDER(V) \ - V(ArrayListForEach, ContainersCommonFuncCall, ARRAYLIST_FOREACH, JS_POINTER) \ - V(DequeForEach, DequeCommonFuncCall, DEQUE_FOREACH, JS_POINTER) \ - V(HashMapForEach, ContainersHashCall, HASHMAP_FOREACH, JS_POINTER) \ - V(HashSetForEach, ContainersHashCall, HASHSET_FOREACH, JS_POINTER) \ - V(LightWeightMapForEach, ContainersLightWeightCall, LIGHTWEIGHTMAP_FOREACH, JS_POINTER) \ - V(LightWeightSetForEach, ContainersLightWeightCall, LIGHTWEIGHTSET_FOREACH, JS_POINTER) \ - V(LinkedListForEach, ContainersLinkedListCall, LINKEDLIST_FOREACH, JS_POINTER) \ - V(ListForEach, ContainersLinkedListCall, LIST_FOREACH, JS_POINTER) \ - V(PlainArrayForEach, ContainersCommonFuncCall, PLAINARRAY_FOREACH, JS_POINTER) \ - V(QueueForEach, QueueCommonFuncCall, QUEUE_FOREACH, JS_POINTER) \ - V(StackForEach, ContainersCommonFuncCall, STACK_FOREACH, JS_POINTER) \ - V(VectorForEach, ContainersCommonFuncCall, VECTOR_FOREACH, JS_POINTER) \ - V(ArrayListReplaceAllElements, ContainersCommonFuncCall, ARRAYLIST_REPLACEALLELEMENTS, JS_POINTER) \ - V(VectorReplaceAllElements, ContainersCommonFuncCall, VECTOR_REPLACEALLELEMENTS, JS_POINTER) - -BUILTINS_WITH_CONTAINERS_STUB_BUILDER(DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER) - -#undef DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER -#undef BUILTINS_WITH_CONTAINERS_STUB_BUILDER - -#define DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER(Method, resultVariableType) \ -DECLARE_BUILTINS(Array##Method) \ +// aot and builtins public stub function +#define DECLARE_AOT_AND_BUILTINS_STUB_BUILDER(stubName, method, type, initValue) \ +DECLARE_BUILTINS(stubName) \ { \ auto env = GetEnvironment(); \ - DEFVARIABLE(res, VariableType::resultVariableType(), Undefined()); \ + DEFVARIABLE(res, VariableType::JS_ANY(), initValue); \ Label exit(env); \ Label slowPath(env); \ - BuiltinsArrayStubBuilder arrayStubBuilder(this); \ - arrayStubBuilder.Method(glue, thisValue, numArgs, &res, &exit, &slowPath); \ + Builtins##type##StubBuilder builder(this); \ + builder.method(glue, thisValue, numArgs, &res, &exit, &slowPath); \ Bind(&slowPath); \ { \ - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(Array##Method)); \ + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(stubName)); \ res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ Jump(&exit); \ } \ @@ -322,51 +283,37 @@ DECLARE_BUILTINS(Array##Method) Return(*res); \ } -#define BUILTINS_WITH_ARRAY_STUB_BUILDER(V) \ - V(Concat, JS_ANY) \ - V(Filter, JS_POINTER) \ - V(Find, JS_ANY) \ - V(FindIndex, JS_ANY) \ - V(From, JS_ANY) \ - V(Splice, JS_ANY) \ - V(ForEach, JS_ANY) \ - V(IndexOf, JS_ANY) \ - V(LastIndexOf, JS_ANY) \ - V(Pop, JS_ANY) \ - V(Slice, JS_POINTER) \ - V(Reduce, JS_ANY) \ - V(Reverse, JS_POINTER) \ - V(Push, JS_ANY) \ - V(Values, JS_POINTER) \ - V(Includes, JS_ANY) \ - V(CopyWithin, JS_ANY) \ - V(Every, JS_ANY) \ - V(FindLastIndex, JS_ANY) \ - V(FindLast, JS_ANY) \ - V(Map, JS_ANY) - -DECLARE_BUILTINS(SORT) -{ - auto env = GetEnvironment(); - DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - Label exit(env); - Label slowPath(env); - BuiltinsArrayStubBuilder arrayStubBuilder(this); - arrayStubBuilder.Sort(glue, thisValue, numArgs, &res, &exit, &slowPath); - Bind(&slowPath); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(SORT)); - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); - Jump(&exit); - } - Bind(&exit); - Return(*res); +#define AOT_AND_BUILTINS_STUB_LIST_WITH_METHOD(V) \ + V(StringLocaleCompare, LocaleCompare, String, Undefined()) \ + V(StringIteratorProtoNext, StringIteratorNext, String, Undefined()) \ + V(ArraySort, Sort, Array, Undefined()) + +AOT_AND_BUILTINS_STUB_LIST_WITH_METHOD(DECLARE_AOT_AND_BUILTINS_STUB_BUILDER) +#undef AOT_AND_BUILTINS_STUB_LIST +#undef DECLARE_AOT_AND_BUILTINS_STUB_BUILDER + +// containers stub function +#define DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER(funcName, type, method, methodType, resultVariableType) \ +DECLARE_BUILTINS(type##funcName) \ +{ \ + auto env = GetEnvironment(); \ + DEFVARIABLE(res, VariableType::resultVariableType(), Undefined()); \ + Label exit(env); \ + Label slowPath(env); \ + ContainersStubBuilder containersBuilder(this); \ + containersBuilder.method(glue, thisValue, numArgs, &res, &exit, &slowPath, ContainersType::methodType); \ + Bind(&slowPath); \ + { \ + auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##funcName)); \ + res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ + Jump(&exit); \ + } \ + Bind(&exit); \ + Return(*res); \ } -BUILTINS_WITH_ARRAY_STUB_BUILDER(DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER) - -#undef DECLARE_BUILTINS_WITH_ARRAY_STUB_BUILDER -#undef BUILTINS_WITH_ARRAY_STUB_BUILDER +BUILTINS_WITH_CONTAINERS_STUB_BUILDER(DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER) +#undef DECLARE_BUILTINS_WITH_CONTAINERS_STUB_BUILDER DECLARE_BUILTINS(BooleanConstructor) { @@ -430,90 +377,6 @@ DECLARE_BUILTINS(BooleanConstructor) Return(*res); } -DECLARE_BUILTINS(NumberConstructor) -{ - auto env = GetEnvironment(); - DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - DEFVARIABLE(numberValue, VariableType::JS_ANY(), IntToTaggedPtr(IntPtr(0))); - Label thisCollectionObj(env); - Label slowPath(env); - Label slowPath1(env); - Label slowPath2(env); - Label exit(env); - - Label hasArg(env); - Label numberCreate(env); - Label newTargetIsHeapObject(env); - BRANCH(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); - Bind(&newTargetIsHeapObject); - BRANCH(Int64GreaterThan(numArgs, IntPtr(0)), &hasArg, &numberCreate); - Bind(&hasArg); - { - GateRef value = GetArgNCheck(Int32(0)); - Label number(env); - BRANCH(TaggedIsNumber(value), &number, &slowPath); - Bind(&number); - { - numberValue = value; - res = value; - Jump(&numberCreate); - } - } - - Bind(&numberCreate); - Label newObj(env); - Label newTargetIsJSFunction(env); - BRANCH(TaggedIsUndefined(newTarget), &exit, &newObj); - Bind(&newObj); - { - BRANCH(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); - Bind(&newTargetIsJSFunction); - { - Label intialHClassIsHClass(env); - GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, - IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); - BRANCH(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); - Bind(&intialHClassIsHClass); - { - NewObjectStubBuilder newBuilder(this); - newBuilder.SetParameters(glue, 0); - Label afterNew(env); - newBuilder.NewJSObject(&res, &afterNew, intialHClass); - Bind(&afterNew); - { - GateRef valueOffset = IntPtr(JSPrimitiveRef::VALUE_OFFSET); - Store(VariableType::INT64(), glue, *res, valueOffset, *numberValue); - Jump(&exit); - } - } - Bind(&slowPath2); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); - GateRef argv = GetArgv(); - res = CallBuiltinRuntimeWithNewTarget(glue, - { glue, nativeCode, func, thisValue, numArgs, argv, newTarget }, name.c_str()); - Jump(&exit); - } - } - } - - Bind(&slowPath); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); - GateRef argv = GetArgv(); - res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true, name.c_str()); - Jump(&exit); - } - Bind(&slowPath1); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(NumberConstructor)); - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); - Jump(&exit); - } - Bind(&exit); - Return(*res); -} - DECLARE_BUILTINS(DateConstructor) { auto env = GetEnvironment(); @@ -615,278 +478,29 @@ DECLARE_BUILTINS(DateConstructor) Return(*res); } -DECLARE_BUILTINS(ArrayConstructor) +DECLARE_BUILTINS(NumberConstructor) { - auto env = GetEnvironment(); - DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - - Label newTargetIsHeapObject(env); - Label newTargetIsJSFunction(env); - Label slowPath(env); - Label slowPath1(env); - Label slowPath2(env); - Label exit(env); - - BRANCH(TaggedIsHeapObject(newTarget), &newTargetIsHeapObject, &slowPath1); - Bind(&newTargetIsHeapObject); - BRANCH(IsJSFunction(newTarget), &newTargetIsJSFunction, &slowPath); - Bind(&newTargetIsJSFunction); - { - Label fastGetHclass(env); - Label intialHClassIsHClass(env); - GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); - GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); - auto arrayFunc = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); - BRANCH(Equal(arrayFunc, newTarget), &fastGetHclass, &slowPath2); - Bind(&fastGetHclass); - GateRef intialHClass = Load(VariableType::JS_ANY(), newTarget, IntPtr(JSFunction::PROTO_OR_DYNCLASS_OFFSET)); - DEFVARIABLE(arrayLength, VariableType::INT64(), Int64(0)); - BRANCH(IsJSHClass(intialHClass), &intialHClassIsHClass, &slowPath2); - Bind(&intialHClassIsHClass); - { - Label noArg(env); - Label hasArg(env); - Label arrayCreate(env); - BRANCH(Int64Equal(numArgs, IntPtr(0)), &noArg, &hasArg); - Bind(&noArg); - { - Jump(&arrayCreate); - } - Bind(&hasArg); - { - Label hasOneArg(env); - BRANCH(Int64Equal(numArgs, IntPtr(1)), &hasOneArg, &slowPath); - Bind(&hasOneArg); - { - Label argIsNumber(env); - GateRef arg0 = GetArg(numArgs, IntPtr(0)); - BRANCH(TaggedIsNumber(arg0), &argIsNumber, &slowPath); - Bind(&argIsNumber); - { - Label argIsInt(env); - Label argIsDouble(env); - BRANCH(TaggedIsInt(arg0), &argIsInt, &argIsDouble); - Bind(&argIsInt); - { - Label validIntLength(env); - GateRef intLen = GetInt64OfTInt(arg0); - GateRef isGEZero = Int64GreaterThanOrEqual(intLen, Int64(0)); - GateRef isLEMaxLen = Int64LessThanOrEqual(intLen, Int64(JSArray::MAX_ARRAY_INDEX)); - BRANCH(BoolAnd(isGEZero, isLEMaxLen), &validIntLength, &slowPath); - Bind(&validIntLength); - { - arrayLength = intLen; - Jump(&arrayCreate); - } - } - Bind(&argIsDouble); - { - Label validDoubleLength(env); - GateRef doubleLength = GetDoubleOfTDouble(arg0); - GateRef doubleToInt = DoubleToInt(glue, doubleLength); - GateRef intToDouble = CastInt64ToFloat64(SExtInt32ToInt64(doubleToInt)); - GateRef doubleEqual = DoubleEqual(doubleLength, intToDouble); - GateRef doubleLEMaxLen = - DoubleLessThanOrEqual(doubleLength, Double(JSArray::MAX_ARRAY_INDEX)); - BRANCH(BoolAnd(doubleEqual, doubleLEMaxLen), &validDoubleLength, &slowPath); - Bind(&validDoubleLength); - { - arrayLength = SExtInt32ToInt64(doubleToInt); - Jump(&arrayCreate); - } - } - } - } - } - Bind(&arrayCreate); - { - Label lengthValid(env); - BRANCH(Int64GreaterThan(*arrayLength, Int64(JSObject::MAX_GAP)), &slowPath, &lengthValid); - Bind(&lengthValid); - { - NewObjectStubBuilder newBuilder(this); - newBuilder.SetParameters(glue, 0); - res = newBuilder.NewJSArrayWithSize(intialHClass, *arrayLength); - GateRef lengthOffset = IntPtr(JSArray::LENGTH_OFFSET); - Store(VariableType::INT32(), glue, *res, lengthOffset, TruncInt64ToInt32(*arrayLength)); - GateRef accessor = GetGlobalConstantValue(VariableType::JS_ANY(), glue, - ConstantIndex::ARRAY_LENGTH_ACCESSOR); - SetPropertyInlinedProps(glue, *res, intialHClass, accessor, - Int32(JSArray::LENGTH_INLINE_PROPERTY_INDEX)); - SetExtensibleToBitfield(glue, *res, true); - Jump(&exit); - } - } - } - Bind(&slowPath2); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); - GateRef argv = GetArgv(); - res = CallBuiltinRuntimeWithNewTarget(glue, { glue, nativeCode, func, thisValue, numArgs, argv, newTarget }, - name.c_str()); - Jump(&exit); - } - } - Bind(&slowPath); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); - GateRef argv = GetArgv(); - res = CallBuiltinRuntime(glue, { glue, nativeCode, func, thisValue, numArgs, argv }, true, name.c_str()); - Jump(&exit); - } - Bind(&slowPath1); - { - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(ArrayConstructor)); - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); - Jump(&exit); - } - - Bind(&exit); - Return(*res); + BuiltinsNumberStubBuilder builder(this, glue, thisValue, numArgs); + builder.GenNumberConstructor(nativeCode, func, newTarget); } -#define DECLARE_BUILTINS_OBJECT_STUB_BUILDER(type, method, retType, retDefaultValue) \ -DECLARE_BUILTINS(type##method) \ -{ \ - auto env = GetEnvironment(); \ - DEFVARIABLE(res, retType, retDefaultValue); \ - Label thisCollectionObj(env); \ - Label slowPath(env); \ - Label exit(env); \ - BuiltinsObjectStubBuilder builder(this, glue, thisValue, numArgs); \ - builder.method(&res, &exit, &slowPath); \ - Bind(&slowPath); \ - { \ - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ - Jump(&exit); \ - } \ - Bind(&exit); \ - Return(*res); \ +DECLARE_BUILTINS(ArrayConstructor) +{ + BuiltinsArrayStubBuilder builder(this); + builder.GenArrayConstructor(glue, nativeCode, func, newTarget, thisValue, numArgs); } -// Object.protetype.ToString -DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, ToString, VariableType::JS_ANY(), Undefined()); -// Object.protetype.Create -DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Create, VariableType::JS_ANY(), Undefined()); -// Object.protetype.Assign -DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Assign, VariableType::JS_ANY(), Undefined()); -// Object.protetype.HasOwnProperty -DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, HasOwnProperty, VariableType::JS_ANY(), TaggedFalse()); -// Object.protetype.Keys -DECLARE_BUILTINS_OBJECT_STUB_BUILDER(Object, Keys, VariableType::JS_ANY(), Undefined()); -#undef DECLARE_BUILTINS_OBJECT_STUB_BUILDER - DECLARE_BUILTINS(MapConstructor) { LinkedHashTableStubBuilder hashTableBuilder(this, glue); - hashTableBuilder.GenMapSetConstructor(nativeCode, func, newTarget, thisValue, numArgs); + hashTableBuilder.GenMapSetConstructor(nativeCode, func, newTarget, thisValue, + numArgs, GetCallArg0(numArgs), GetArgv()); } DECLARE_BUILTINS(SetConstructor) { LinkedHashTableStubBuilder hashTableBuilder(this, glue); - hashTableBuilder.GenMapSetConstructor(nativeCode, func, newTarget, thisValue, numArgs); -} - -#define DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(type, method, retType, retDefaultValue) \ -DECLARE_BUILTINS(type##method) \ -{ \ - auto env = GetEnvironment(); \ - DEFVARIABLE(res, retType, retDefaultValue); \ - Label slowPath(env); \ - Label exit(env); \ - BuiltinsCollectionStubBuilder builder(this, glue, thisValue, numArgs); \ - builder.method(&res, &exit, &slowPath); \ - Bind(&slowPath); \ - { \ - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ - Jump(&exit); \ - } \ - Bind(&exit); \ - Return(*res); \ -} - -// Set.protetype.Clear -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Clear, VariableType::JS_ANY(), Undefined()); -// Set.protetype.Values -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Values, VariableType::JS_ANY(), Undefined()); -// Set.protetype.Entries -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Entries, VariableType::JS_ANY(), Undefined()); -// Set.protetype.ForEach -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, ForEach, VariableType::JS_ANY(), Undefined()); -// Set.protetype.Add -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Add, VariableType::JS_ANY(), Undefined()); -// Set.protetype.Delete -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Delete, VariableType::JS_ANY(), Undefined()); -// Set.protetype.Has -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Set, Has, VariableType::JS_ANY(), Undefined()); -// Map.protetype.Clear -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Clear, VariableType::JS_ANY(), Undefined()); -// Map.protetype.Values -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Values, VariableType::JS_ANY(), Undefined()); -// Map.protetype.Entries -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Entries, VariableType::JS_ANY(), Undefined()); -// Map.protetype.Keys -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Keys, VariableType::JS_ANY(), Undefined()); -// Map.protetype.ForEach -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, ForEach, VariableType::JS_ANY(), Undefined()); -// Map.protetype.set -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Set, VariableType::JS_ANY(), Undefined()); -// Map.protetype.Delete -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Delete, VariableType::JS_ANY(), Undefined()); -// Map.protetype.Has -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Has, VariableType::JS_ANY(), Undefined()); -// Map.protetype.Get -DECLARE_BUILTINS_COLLECTION_STUB_BUILDER(Map, Get, VariableType::JS_ANY(), Undefined()); -#undef DECLARE_BUILTINS_COLLECTION_STUB_BUILDER - -#define DECLARE_BUILTINS_NUMBER_STUB_BUILDER(type, method, retType, retDefaultValue) \ -DECLARE_BUILTINS(type##method) \ -{ \ - auto env = GetEnvironment(); \ - DEFVARIABLE(res, retType, retDefaultValue); \ - Label slowPath(env); \ - Label exit(env); \ - BuiltinsNumberStubBuilder builder(this, glue, thisValue, numArgs); \ - builder.method(&res, &exit, &slowPath); \ - Bind(&slowPath); \ - { \ - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ - Jump(&exit); \ - } \ - Bind(&exit); \ - Return(*res); \ + hashTableBuilder.GenMapSetConstructor(nativeCode, func, newTarget, thisValue, + numArgs, GetCallArg0(numArgs), GetArgv()); } - -// Number.ParseFloat -DECLARE_BUILTINS_NUMBER_STUB_BUILDER(Number, ParseFloat, VariableType::JS_ANY(), Undefined()); -#undef DECLARE_BUILTINS_NUMBER_STUB_BUILDER - -#define DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER(type, method, retType, retDefaultValue) \ -DECLARE_BUILTINS(type##method) \ -{ \ - auto env = GetEnvironment(); \ - DEFVARIABLE(res, retType, retDefaultValue); \ - Label slowPath(env); \ - Label exit(env); \ - TypedArrayStubBuilder builder(this); \ - builder.method(glue, thisValue, numArgs, &res, &exit, &slowPath); \ - Bind(&slowPath); \ - { \ - auto name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(type##method)); \ - res = CallSlowPath(nativeCode, glue, thisValue, numArgs, func, newTarget, name.c_str()); \ - Jump(&exit); \ - } \ - Bind(&exit); \ - Return(*res); \ -} - -// TypedArray.Subarray -DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER(TypedArray, SubArray, VariableType::JS_ANY(), Undefined()); -DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER(TypedArray, GetByteLength, VariableType::JS_ANY(), Undefined()); -DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER(TypedArray, GetByteOffset, VariableType::JS_ANY(), Undefined()); -#undef DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/builtins_stubs.h b/ecmascript/compiler/builtins/builtins_stubs.h index 9dfd48e1ffc9cebec3286a077e47698ba53057e8..1292df763720cec4424e5c3f660cb87b8fb0a623 100644 --- a/ecmascript/compiler/builtins/builtins_stubs.h +++ b/ecmascript/compiler/builtins/builtins_stubs.h @@ -163,7 +163,24 @@ public: void GenerateCircuitImpl(GateRef glue, GateRef nativeCode, GateRef func, GateRef newTarget, \ GateRef thisValue, GateRef numArgs); \ }; - BUILTINS_STUB_LIST(DECLARE_BUILTINS_STUB_CLASS) + + +#define DECLARE_BUILTINS_STUB_CLASS_DYN(name, type, ...) \ + class type##name##StubBuilder : public BuiltinsStubBuilder { \ + public: \ + type##name##StubBuilder(CallSignature *callSignature, Environment *env) \ + : BuiltinsStubBuilder(callSignature, env) {} \ + ~type##name##StubBuilder() = default; \ + NO_MOVE_SEMANTIC(type##name##StubBuilder); \ + NO_COPY_SEMANTIC(type##name##StubBuilder); \ + void GenerateCircuit() override; \ + \ + private: \ + void GenerateCircuitImpl(GateRef glue, GateRef nativeCode, GateRef func, GateRef newTarget, \ + GateRef thisValue, GateRef numArgs); \ + }; + BUILTINS_STUB_LIST(DECLARE_BUILTINS_STUB_CLASS, DECLARE_BUILTINS_STUB_CLASS_DYN) +#undef DECLARE_BUILTINS_STUB_CLASS_DYN #undef DECLARE_BUILTINS_STUB_CLASS } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_BUILTINS_STUB_H diff --git a/ecmascript/compiler/typed_array_stub_builder.cpp b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.cpp similarity index 57% rename from ecmascript/compiler/typed_array_stub_builder.cpp rename to ecmascript/compiler/builtins/builtins_typedarray_stub_builder.cpp index 7e1d126d4ba9c38cee6cc9cee6cd2b782909ff35..baac1b477f9d437f8195f0b27ee8798342b49978 100644 --- a/ecmascript/compiler/typed_array_stub_builder.cpp +++ b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 @@ -13,14 +13,15 @@ * limitations under the License. */ -#include "ecmascript/compiler/typed_array_stub_builder.h" +#include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h" #include "ecmascript/base/typed_array_helper.h" #include "ecmascript/byte_array.h" +#include "ecmascript/compiler/builtins/builtins_array_stub_builder.h" #include "ecmascript/compiler/new_object_stub_builder.h" namespace panda::ecmascript::kungfu { -GateRef TypedArrayStubBuilder::IsDetachedBuffer(GateRef buffer) +GateRef BuiltinsTypedArrayStubBuilder::GetDataPointFromBuffer(GateRef arrBuf) { auto env = GetEnvironment(); Label entryPass(env); @@ -29,42 +30,11 @@ GateRef TypedArrayStubBuilder::IsDetachedBuffer(GateRef buffer) Label exit(env); Label isByteArray(env); Label notByteArray(env); - DEFVARIABLE(result, VariableType::BOOL(), False()); - BRANCH(IsByteArray(buffer), &isByteArray, ¬ByteArray); - Bind(&isByteArray); - { - Jump(&exit); - } - Bind(¬ByteArray); - { - GateRef dataSlot = GetArrayBufferData(buffer); - BRANCH(TaggedIsNull(dataSlot), &isNull, &exit); - Bind(&isNull); - { - result = True(); - Jump(&exit); - } - } - Bind(&exit); - auto ret = *result; - env->SubCfgExit(); - return ret; -} - -GateRef TypedArrayStubBuilder::GetDataPointFromBuffer(GateRef arrBuf) -{ - auto env = GetEnvironment(); - Label entryPass(env); - env->SubCfgEntry(&entryPass); - Label isNull(env); - Label exit(env); - Label isByteArray(env); - Label notByteArray(env); - DEFVARIABLE(result, VariableType::JS_ANY(), arrBuf); + DEFVARIABLE(result, VariableType::NATIVE_POINTER(), IntPtr(0)); BRANCH(IsByteArray(arrBuf), &isByteArray, ¬ByteArray); Bind(&isByteArray); { - result = PtrAdd(*result, IntPtr(ByteArray::DATA_OFFSET)); + result = ChangeByteArrayTaggedPointerToInt64(PtrAdd(arrBuf, IntPtr(ByteArray::DATA_OFFSET))); Jump(&exit); } Bind(¬ByteArray); @@ -79,7 +49,7 @@ GateRef TypedArrayStubBuilder::GetDataPointFromBuffer(GateRef arrBuf) return ret; } -GateRef TypedArrayStubBuilder::CheckTypedArrayIndexInRange(GateRef array, GateRef index) +GateRef BuiltinsTypedArrayStubBuilder::CheckTypedArrayIndexInRange(GateRef array, GateRef index) { auto env = GetEnvironment(); Label entryPass(env); @@ -105,7 +75,7 @@ GateRef TypedArrayStubBuilder::CheckTypedArrayIndexInRange(GateRef array, GateRe return ret; } -GateRef TypedArrayStubBuilder::LoadTypedArrayElement(GateRef glue, GateRef array, GateRef key, GateRef jsType) +GateRef BuiltinsTypedArrayStubBuilder::LoadTypedArrayElement(GateRef glue, GateRef array, GateRef key, GateRef jsType) { auto env = GetEnvironment(); Label entryPass(env); @@ -140,8 +110,8 @@ GateRef TypedArrayStubBuilder::LoadTypedArrayElement(GateRef glue, GateRef array return ret; } -GateRef TypedArrayStubBuilder::StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value, - GateRef jsType) +GateRef BuiltinsTypedArrayStubBuilder::StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value, + GateRef jsType) { auto env = GetEnvironment(); Label entryPass(env); @@ -168,7 +138,8 @@ GateRef TypedArrayStubBuilder::StoreTypedArrayElement(GateRef glue, GateRef arra return ret; } -GateRef TypedArrayStubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef array, GateRef index, GateRef jsType) +GateRef BuiltinsTypedArrayStubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef array, + GateRef index, GateRef jsType) { auto env = GetEnvironment(); Label entryPass(env); @@ -209,7 +180,7 @@ GateRef TypedArrayStubBuilder::FastGetPropertyByIndex(GateRef glue, GateRef arra return ret; } -GateRef TypedArrayStubBuilder::FastCopyElementToArray(GateRef glue, GateRef typedArray, GateRef array) +GateRef BuiltinsTypedArrayStubBuilder::FastCopyElementToArray(GateRef glue, GateRef typedArray, GateRef array) { auto env = GetEnvironment(); Label entryPass(env); @@ -264,7 +235,7 @@ GateRef TypedArrayStubBuilder::FastCopyElementToArray(GateRef glue, GateRef type return ret; } -GateRef TypedArrayStubBuilder::GetValueFromBuffer(GateRef buffer, GateRef index, GateRef offset, GateRef jsType) +GateRef BuiltinsTypedArrayStubBuilder::GetValueFromBuffer(GateRef buffer, GateRef index, GateRef offset, GateRef jsType) { auto env = GetEnvironment(); Label entryPass(env); @@ -414,7 +385,268 @@ GateRef TypedArrayStubBuilder::GetValueFromBuffer(GateRef buffer, GateRef index, return ret; } -void TypedArrayStubBuilder::SubArray(GateRef glue, GateRef thisValue, GateRef numArgs, +GateRef BuiltinsTypedArrayStubBuilder::CalculatePositionWithLength(GateRef position, GateRef length) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + DEFVARIABLE(result, VariableType::INT64(), Int64(0)); + Label positionLessThanZero(env); + Label positionNotLessThanZero(env); + Label resultNotGreaterThanZero(env); + Label positionLessThanLength(env); + Label positionNotLessThanLength(env); + Label afterCalculatePosition(env); + + BRANCH(Int64LessThan(position, Int64(0)), &positionLessThanZero, &positionNotLessThanZero); + Bind(&positionLessThanZero); + { + result = Int64Add(position, length); + BRANCH(Int64GreaterThan(*result, Int64(0)), &afterCalculatePosition, &resultNotGreaterThanZero); + Bind(&resultNotGreaterThanZero); + { + result = Int64(0); + Jump(&afterCalculatePosition); + } + } + Bind(&positionNotLessThanZero); + { + BRANCH(Int64LessThan(position, length), &positionLessThanLength, &positionNotLessThanLength); + Bind(&positionLessThanLength); + { + result = position; + Jump(&afterCalculatePosition); + } + Bind(&positionNotLessThanLength); + { + result = length; + Jump(&afterCalculatePosition); + } + } + Bind(&afterCalculatePosition); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +void BuiltinsTypedArrayStubBuilder::Filter(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisExists(env); + Label isEcmaObject(env); + Label isTypedArray(env); + Label isFastTypedArray(env); + Label defaultConstr(env); + Label prototypeIsEcmaObj(env); + Label isProtoChangeMarker(env); + Label accessorNotChanged(env); + BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists); + Bind(&thisExists); + BRANCH(IsEcmaObject(thisValue), &isEcmaObject, slowPath); + Bind(&isEcmaObject); + BRANCH(IsTypedArray(thisValue), &isTypedArray, slowPath); + Bind(&isTypedArray); + GateRef arrayType = GetObjectType(LoadHClass(thisValue)); + BRANCH(IsFastTypeArray(arrayType), &isFastTypedArray, slowPath); + Bind(&isFastTypedArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + GateRef prototype = GetPrototypeFromHClass(LoadHClass(thisValue)); + BRANCH(IsEcmaObject(prototype), &prototypeIsEcmaObj, slowPath); + Bind(&prototypeIsEcmaObj); + GateRef marker = GetProtoChangeMarkerFromHClass(LoadHClass(prototype)); + Branch(TaggedIsProtoChangeMarker(marker), &isProtoChangeMarker, slowPath); + Bind(&isProtoChangeMarker); + Branch(GetAccessorHasChanged(marker), slowPath, &accessorNotChanged); + Bind(&accessorNotChanged); + + Label arg0HeapObject(env); + Label callable(env); + GateRef callbackFnHandle = GetCallArg0(numArgs); + BRANCH(TaggedIsHeapObject(callbackFnHandle), &arg0HeapObject, slowPath); + Bind(&arg0HeapObject); + { + BRANCH(IsCallable(callbackFnHandle), &callable, slowPath); + Bind(&callable); + { + GateRef argHandle = GetCallArg1(numArgs); + GateRef thisLen = GetArrayLength(thisValue); + BuiltinsArrayStubBuilder arrayStubBuilder(this); + GateRef kept = arrayStubBuilder.NewArray(glue, ZExtInt32ToInt64(thisLen)); + DEFVARIABLE(i, VariableType::INT32(), Int32(0)); + DEFVARIABLE(newArrayLen, VariableType::INT32(), Int32(0)); + Label loopHead(env); + Label loopEnd(env); + Label next(env); + Label loopExit(env); + Jump(&loopHead); + LoopBegin(&loopHead); + { + Label hasException0(env); + Label notHasException0(env); + Label hasException1(env); + Label notHasException1(env); + Label retValueIsTrue(env); + BRANCH(Int32LessThan(*i, thisLen), &next, &loopExit); + Bind(&next); + { + GateRef kValue = FastGetPropertyByIndex(glue, thisValue, *i, arrayType); + BRANCH(HasPendingException(glue), &hasException0, ¬HasException0); + Bind(&hasException0); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException0); + { + GateRef key = IntToTaggedInt(*i); + GateRef retValue = JSCallDispatch(glue, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), + 0, Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, + { argHandle, kValue, key, thisValue }); + BRANCH(HasPendingException(glue), &hasException1, ¬HasException1); + Bind(&hasException1); + { + result->WriteVariable(Exception()); + Jump(exit); + } + Bind(¬HasException1); + { + BRANCH(TaggedIsTrue(FastToBoolean(retValue)), &retValueIsTrue, &loopEnd); + Bind(&retValueIsTrue); + { + arrayStubBuilder.SetValueWithElementsKind(glue, kept, kValue, *newArrayLen, + Boolean(true), Int32(static_cast(ElementsKind::NONE))); + newArrayLen = Int32Add(*newArrayLen, Int32(1)); + Jump(&loopEnd); + } + } + } + } + } + Bind(&loopEnd); + i = Int32Add(*i, Int32(1)); + LoopEnd(&loopHead); + Bind(&loopExit); + + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + GateRef newArray = newBuilder.NewTypedArray(glue, thisValue, arrayType, TruncInt64ToInt32(*newArrayLen)); + i = Int32(0); + Label loopHead2(env); + Label loopEnd2(env); + Label next2(env); + Label loopExit2(env); + Jump(&loopHead2); + LoopBegin(&loopHead2); + { + BRANCH(Int32LessThan(*i, *newArrayLen), &next2, &loopExit2); + Bind(&next2); + { + GateRef kValue = arrayStubBuilder.GetTaggedValueWithElementsKind(kept, *i); + StoreTypedArrayElement(glue, newArray, ZExtInt32ToInt64(*i), kValue, arrayType); + Jump(&loopEnd2); + } + } + Bind(&loopEnd2); + i = Int32Add(*i, Int32(1)); + LoopEnd(&loopHead2); + Bind(&loopExit2); + + result->WriteVariable(newArray); + Jump(exit); + } + } +} + +void BuiltinsTypedArrayStubBuilder::Slice(GateRef glue, GateRef thisValue, GateRef numArgs, + Variable *result, Label *exit, Label *slowPath) +{ + auto env = GetEnvironment(); + Label thisExists(env); + Label isEcmaObject(env); + Label isTypedArray(env); + Label isFastTypedArray(env); + Label defaultConstr(env); + BRANCH(TaggedIsUndefinedOrNull(thisValue), slowPath, &thisExists); + Bind(&thisExists); + BRANCH(IsEcmaObject(thisValue), &isEcmaObject, slowPath); + Bind(&isEcmaObject); + BRANCH(IsTypedArray(thisValue), &isTypedArray, slowPath); + Bind(&isTypedArray); + GateRef arrayType = GetObjectType(LoadHClass(thisValue)); + BRANCH(IsFastTypeArray(arrayType), &isFastTypedArray, slowPath); + Bind(&isFastTypedArray); + BRANCH(HasConstructor(thisValue), slowPath, &defaultConstr); + Bind(&defaultConstr); + + DEFVARIABLE(startPos, VariableType::INT64(), Int64(0)); + DEFVARIABLE(endPos, VariableType::INT64(), Int64(0)); + DEFVARIABLE(newArrayLen, VariableType::INT64(), Int64(0)); + Label startTagExists(env); + Label startTagIsInt(env); + Label afterCallArg(env); + Label endTagExists(env); + Label endTagIsInt(env); + Label adjustArrLen(env); + Label newTypedArray(env); + Label writeVariable(env); + Label copyBuffer(env); + GateRef thisLen = ZExtInt32ToInt64(GetArrayLength(thisValue)); + BRANCH(Int64GreaterThanOrEqual(IntPtr(0), numArgs), slowPath, &startTagExists); + Bind(&startTagExists); + { + GateRef startTag = GetCallArg0(numArgs); + BRANCH(TaggedIsInt(startTag), &startTagIsInt, slowPath); + Bind(&startTagIsInt); + { + startPos = SExtInt32ToInt64(TaggedGetInt(startTag)); + endPos = thisLen; + BRANCH(Int64GreaterThanOrEqual(IntPtr(1), numArgs), &afterCallArg, &endTagExists); + Bind(&endTagExists); + { + GateRef endTag = GetCallArg1(numArgs); + BRANCH(TaggedIsInt(endTag), &endTagIsInt, slowPath); + Bind(&endTagIsInt); + { + endPos = SExtInt32ToInt64(TaggedGetInt(endTag)); + Jump(&afterCallArg); + } + } + Bind(&afterCallArg); + { + startPos = CalculatePositionWithLength(*startPos, thisLen); + endPos = CalculatePositionWithLength(*endPos, thisLen); + BRANCH(Int64GreaterThan(*endPos, *startPos), &adjustArrLen, &newTypedArray); + Bind(&adjustArrLen); + { + newArrayLen = Int64Sub(*endPos, *startPos); + Jump(&newTypedArray); + } + } + } + } + Bind(&newTypedArray); + { + NewObjectStubBuilder newBuilder(this); + newBuilder.SetParameters(glue, 0); + GateRef newArray = newBuilder.NewTypedArray(glue, thisValue, arrayType, TruncInt64ToInt32(*newArrayLen)); + BRANCH(Int32Equal(TruncInt64ToInt32(*newArrayLen), Int32(0)), &writeVariable, ©Buffer); + Bind(©Buffer); + { + CallNGCRuntime(glue, RTSTUB_ID(CopyTypedArrayBuffer), {thisValue, newArray, TruncInt64ToInt32(*startPos), + TruncInt64ToInt32(*newArrayLen), newBuilder.GetElementSizeFromType(glue, arrayType)}); + Jump(&writeVariable); + } + Bind(&writeVariable); + { + result->WriteVariable(newArray); + Jump(exit); + } + } +} + +void BuiltinsTypedArrayStubBuilder::SubArray(GateRef glue, GateRef thisValue, GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); @@ -494,7 +726,7 @@ void TypedArrayStubBuilder::SubArray(GateRef glue, GateRef thisValue, GateRef nu Jump(exit); } -void TypedArrayStubBuilder::GetByteLength([[maybe_unused]] GateRef glue, GateRef thisValue, +void BuiltinsTypedArrayStubBuilder::GetByteLength([[maybe_unused]] GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); @@ -520,7 +752,7 @@ void TypedArrayStubBuilder::GetByteLength([[maybe_unused]] GateRef glue, GateRef Jump(exit); } -void TypedArrayStubBuilder::GetByteOffset([[maybe_unused]] GateRef glue, GateRef thisValue, +void BuiltinsTypedArrayStubBuilder::GetByteOffset([[maybe_unused]] GateRef glue, GateRef thisValue, [[maybe_unused]] GateRef numArgs, Variable *result, Label *exit, Label *slowPath) { auto env = GetEnvironment(); diff --git a/ecmascript/compiler/typed_array_stub_builder.h b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h similarity index 66% rename from ecmascript/compiler/typed_array_stub_builder.h rename to ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h index d94f7ed94a0044d775e7cc23d67a3520ddcdd4dc..e53bb449c7492c4b5d246bea14df488da7ee2297 100644 --- a/ecmascript/compiler/typed_array_stub_builder.h +++ b/ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023 Huawei Device Co., Ltd. + * 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 @@ -13,21 +13,21 @@ * limitations under the License. */ -#ifndef ECMASCRIPT_COMPILER_TYPED_ARRAY_STUB_BUILDER_H -#define ECMASCRIPT_COMPILER_TYPED_ARRAY_STUB_BUILDER_H +#ifndef ECMASCRIPT_COMPILER_BUILTINS_TYPEDARRAY_STUB_BUILDER_H +#define ECMASCRIPT_COMPILER_BUILTINS_TYPEDARRAY_STUB_BUILDER_H #include "ecmascript/compiler/stub_builder-inl.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_typed_array.h" namespace panda::ecmascript::kungfu { -class TypedArrayStubBuilder : public BuiltinsStubBuilder { +class BuiltinsTypedArrayStubBuilder : public BuiltinsStubBuilder { public: - explicit TypedArrayStubBuilder(StubBuilder *parent) + explicit BuiltinsTypedArrayStubBuilder(StubBuilder *parent) : BuiltinsStubBuilder(parent) {} - ~TypedArrayStubBuilder() override = default; - NO_MOVE_SEMANTIC(TypedArrayStubBuilder); - NO_COPY_SEMANTIC(TypedArrayStubBuilder); + ~BuiltinsTypedArrayStubBuilder() override = default; + NO_MOVE_SEMANTIC(BuiltinsTypedArrayStubBuilder); + NO_COPY_SEMANTIC(BuiltinsTypedArrayStubBuilder); void GenerateCircuit() override {} GateRef FastGetPropertyByIndex(GateRef glue, GateRef array, GateRef index, GateRef jsType); GateRef FastCopyElementToArray(GateRef glue, GateRef typedArray, GateRef array); @@ -35,14 +35,14 @@ public: GateRef StoreTypedArrayElement(GateRef glue, GateRef array, GateRef index, GateRef value, GateRef jsType); GateRef CheckTypedArrayIndexInRange(GateRef array, GateRef index); GateRef GetValueFromBuffer(GateRef buffer, GateRef index, GateRef offset, GateRef jsType); - GateRef IsDetachedBuffer(GateRef buffer); GateRef GetDataPointFromBuffer(GateRef arrBuf); - void SubArray(GateRef glue, GateRef numArgs, GateRef end, - Variable *result, Label *exit, Label *slowPath); - void GetByteLength(GateRef glue, GateRef numArgs, GateRef end, - Variable *result, Label *exit, Label *slowPath); - void GetByteOffset(GateRef glue, GateRef numArgs, GateRef end, - Variable *result, Label *exit, Label *slowPath); + GateRef CalculatePositionWithLength(GateRef position, GateRef length); + +#define DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER(method, ...) \ + void method(GateRef glue, GateRef numArgs, GateRef end, Variable *result, Label *exit, Label *slowPath); +BUILTINS_WITH_TYPEDARRAY_STUB_BUILDER(DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER) +#undef DECLARE_BUILTINS_TYPEDARRAY_STUB_BUILDER + GateRef GetViewedArrayBuffer(GateRef array) { GateRef offset = IntPtr(JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET); @@ -61,12 +61,6 @@ public: return Load(VariableType::INT32(), array, offset); } - GateRef GetArrayBufferData(GateRef buffer) - { - GateRef offset = IntPtr(JSArrayBuffer::DATA_OFFSET); - return Load(VariableType::JS_ANY(), buffer, offset); - } - GateRef GetArrayBufferByteLength(GateRef buffer) { GateRef offset = IntPtr(JSArrayBuffer::BYTE_LENGTH_OFFSET); @@ -76,8 +70,13 @@ public: GateRef GetExternalPointer(GateRef buffer) { GateRef offset = IntPtr(JSNativePointer::POINTER_OFFSET); - return Load(VariableType::JS_ANY(), buffer, offset); + return Load(VariableType::NATIVE_POINTER(), buffer, offset); + } +private: + GateRef ChangeByteArrayTaggedPointerToInt64(GateRef x) + { + return GetEnvironment()->GetBuilder()->ChangeTaggedPointerToInt64(x); } }; } // namespace panda::ecmascript::kungfu -#endif // ECMASCRIPT_COMPILER_TYPED_ARRAY_STUB_BUILDER_H \ No newline at end of file +#endif // ECMASCRIPT_COMPILER_BUILTINS_TYPEDARRAY_STUB_BUILDER_H \ No newline at end of file diff --git a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp index 819abe06bbb8fc3e9fbd496ab61eaad950839f41..82bf38415abb5728adbc0d5f059cff7532ad0862 100644 --- a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp +++ b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.cpp @@ -16,6 +16,7 @@ #include "ecmascript/compiler/builtins/linked_hashtable_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_stubs.h" +#include "ecmascript/compiler/hash_stub_builder.h" #include "ecmascript/compiler/new_object_stub_builder.h" #include "ecmascript/linked_hash_table.h" #include "ecmascript/js_set.h" @@ -72,7 +73,8 @@ void LinkedHashTableStubBuilder::Reh } Bind(¬Weak); - GateRef hash = GetHash(*key); + HashStubBuilder hashBuilder(this, glue_); + GateRef hash = hashBuilder.GetHash(*key); GateRef bucket = HashToBucket(newTable, hash); InsertNewEntry(newTable, bucket, *desEntry); GateRef desIndex = EntryToIndex(newTable, *desEntry); @@ -222,45 +224,6 @@ GateRef LinkedHashTableStubBuilder:: return ret; } -template -GateRef LinkedHashTableStubBuilder::GetHash(GateRef key) -{ - auto env = GetEnvironment(); - Label entryLabel(env); - Label exit(env); - env->SubCfgEntry(&entryLabel); - DEFVARIABLE(res, VariableType::INT32(), Int32(0)); - - Label symbolKey(env); - Label stringCheck(env); - BRANCH(TaggedIsSymbol(key), &symbolKey, &stringCheck); - Bind(&symbolKey); - { - res = Load(VariableType::INT32(), key, IntPtr(JSSymbol::HASHFIELD_OFFSET)); - Jump(&exit); - } - Bind(&stringCheck); - Label stringKey(env); - Label slowGetHash(env); - BRANCH(TaggedIsString(key), &stringKey, &slowGetHash); - Bind(&stringKey); - { - res = GetHashcodeFromString(glue_, key); - Jump(&exit); - } - Bind(&slowGetHash); - { - // GetHash(); - GateRef hash = CallRuntime(glue_, RTSTUB_ID(GetLinkedHash), { key }); - res = GetInt32OfTInt(hash); - Jump(&exit); - } - Bind(&exit); - auto ret = *res; - env->SubCfgExit(); - return ret; -} - template GateRef LinkedHashTableStubBuilder::HashObjectIsMatch( GateRef key, GateRef other) @@ -438,17 +401,13 @@ template GateRef LinkedHashTableStubBuilder: template GateRef LinkedHashTableStubBuilder::ForEach(GateRef thisValue, - GateRef srcLinkedTable, GateRef numArgs) + GateRef srcLinkedTable, GateRef callbackFnHandle, GateRef thisArg) { auto env = GetEnvironment(); Label entry(env); env->SubCfgEntry(&entry); Label exit(env); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - - // caller checked callbackFnHandle callable - GateRef callbackFnHandle = GetCallArg0(numArgs); - GateRef thisArg = GetCallArg1(numArgs); DEFVARIABLE(linkedTable, VariableType::JS_ANY(), srcLinkedTable); GateRef numberOfElements = GetNumberOfElements(*linkedTable); @@ -481,7 +440,8 @@ GateRef LinkedHashTableStubBuilder:: Label hasException(env); Label notHasException(env); GateRef retValue = JSCallDispatch(glue_, callbackFnHandle, Int32(NUM_MANDATORY_JSFUNC_ARGS), 0, - Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { thisArg, value, key, thisValue }); + Circuit::NullGate(), JSCallMode::CALL_THIS_ARG3_WITH_RETURN, { thisArg, value, key, thisValue }, + ProfileOperation(), false); BRANCH(HasPendingException(glue_), &hasException, ¬HasException); Bind(&hasException); { @@ -519,7 +479,7 @@ GateRef LinkedHashTableStubBuilder:: } } Bind(&loopEnd); - LoopEnd(&loopHead, env, glue_); + LoopEnd(&loopHead); Bind(&loopExit); Jump(&exit); @@ -529,9 +489,9 @@ GateRef LinkedHashTableStubBuilder:: } template GateRef LinkedHashTableStubBuilder::ForEach(GateRef thisValue, - GateRef linkedTable, GateRef numArgs); + GateRef linkedTable, GateRef callbackFnHandle, GateRef thisArg); template GateRef LinkedHashTableStubBuilder::ForEach(GateRef thisValue, - GateRef linkedTable, GateRef numArgs); + GateRef linkedTable, GateRef callbackFnHandle, GateRef thisArg); template GateRef LinkedHashTableStubBuilder::Insert( @@ -542,7 +502,8 @@ GateRef LinkedHashTableStubBuilder:: env->SubCfgEntry(&cfgEntry); Label exit(env); DEFVARIABLE(res, VariableType::JS_ANY(), linkedTable); - GateRef hash = GetHash(key); + HashStubBuilder hashBuilder(this, glue_); + GateRef hash = hashBuilder.GetHash(key); GateRef entry = FindElement(linkedTable, key, hash); Label findEntry(env); Label notFind(env); @@ -588,7 +549,8 @@ GateRef LinkedHashTableStubBuilder:: env->SubCfgEntry(&cfgEntry); Label exit(env); DEFVARIABLE(res, VariableType::JS_ANY(), TaggedFalse()); - GateRef hash = GetHash(key); + HashStubBuilder hashBuilder(this, glue_); + GateRef hash = hashBuilder.GetHash(key); GateRef entry = FindElement(linkedTable, key, hash); Label findEntry(env); BRANCH(Int32Equal(entry, Int32(-1)), &exit, &findEntry); @@ -623,7 +585,9 @@ GateRef LinkedHashTableStubBuilder:: GateRef size = GetNumberOfElements(linkedTable); BRANCH(Int32Equal(size, Int32(0)), &exit, &nonEmpty); Bind(&nonEmpty); - GateRef hash = GetHash(key); + HashStubBuilder hashBuilder(this, glue_); + GateRef hash = hashBuilder.GetHash(key); + GateRef entry = FindElement(linkedTable, key, hash); Label findEntry(env); BRANCH(Int32Equal(entry, Int32(-1)), &exit, &findEntry); @@ -668,7 +632,7 @@ template void LinkedHashTableStubBuilder::St template void LinkedHashTableStubBuilder::GenMapSetConstructor( - GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs) + GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, GateRef arg0, GateRef argv) { auto env = GetEnvironment(); DEFVARIABLE(returnValue, VariableType::JS_ANY(), Undefined()); @@ -705,7 +669,7 @@ void LinkedHashTableStubBuilder::Gen Bind(&fastGetHClass); Label isUndefinedOrNull(env); - BRANCH(TaggedIsUndefinedOrNull(GetCallArg0(numArgs)), &isUndefinedOrNull, &slowPath); + BRANCH(TaggedIsUndefinedOrNull(arg0), &isUndefinedOrNull, &slowPath); Bind(&isUndefinedOrNull); StoreHashTableToNewObject(newTargetHClass, returnValue); @@ -725,7 +689,7 @@ void LinkedHashTableStubBuilder::Gen name = BuiltinsStubCSigns::GetName(BUILTINS_STUB_ID(SetConstructor)); } returnValue = CallBuiltinRuntimeWithNewTarget(glue_, {glue_, nativeCode, func, thisValue, - numArgs, GetArgv(), newTarget}, name.c_str()); + numArgs, argv, newTarget}, name.c_str()); Jump(&exit); Bind(&exit); @@ -733,9 +697,35 @@ void LinkedHashTableStubBuilder::Gen } template void LinkedHashTableStubBuilder::GenMapSetConstructor( - GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs); + GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, + GateRef arg0, GateRef argv); template void LinkedHashTableStubBuilder::GenMapSetConstructor( - GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs); + GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, + GateRef arg0, GateRef argv); + +template +GateRef LinkedHashTableStubBuilder::GetLinked(GateRef jsThis) +{ + GateRef linkedTableOffset = GetLinkedOffset(); + return Load(VariableType::JS_ANY(), jsThis, linkedTableOffset); +} + +template GateRef LinkedHashTableStubBuilder::GetLinked( + GateRef jsThis); +template GateRef LinkedHashTableStubBuilder::GetLinked( + GateRef jsThis); + +template +void LinkedHashTableStubBuilder::SetLinked(GateRef jsThis, GateRef newTable) +{ + GateRef linkedTableOffset = GetLinkedOffset(); + Store(VariableType::JS_ANY(), glue_, jsThis, linkedTableOffset, newTable); +} + +template void LinkedHashTableStubBuilder::SetLinked( + GateRef jsThis, GateRef newTable); +template void LinkedHashTableStubBuilder::SetLinked( + GateRef jsThis, GateRef newTable); template GateRef LinkedHashTableStubBuilder::Get( @@ -746,7 +736,8 @@ GateRef LinkedHashTableStubBuilder:: env->SubCfgEntry(&cfgEntry); Label exit(env); DEFVARIABLE(res, VariableType::JS_ANY(), Undefined()); - GateRef hash = GetHash(key); + HashStubBuilder hashBuilder(this, glue_); + GateRef hash = hashBuilder.GetHash(key); GateRef entry = FindElement(linkedTable, key, hash); Label findEntry(env); Branch(Int32Equal(entry, Int32(-1)), &exit, &findEntry); @@ -764,4 +755,21 @@ GateRef LinkedHashTableStubBuilder:: template GateRef LinkedHashTableStubBuilder::Get( GateRef linkedTable, GateRef key); + +template +GateRef LinkedHashTableStubBuilder::GetLinkedOffset() +{ + int32_t linkedTableOffset = 0; + if constexpr (std::is_same_v) { + linkedTableOffset = JSMap::LINKED_MAP_OFFSET; + } else { + static_assert(std::is_same_v); + linkedTableOffset = JSSet::LINKED_SET_OFFSET; + } + return IntPtr(linkedTableOffset); +} + +template GateRef LinkedHashTableStubBuilder::GetLinkedOffset(); +template GateRef LinkedHashTableStubBuilder::GetLinkedOffset(); + } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h index e426d47e8e4e063b55f34ac2fcbe84b91f1ba831..857597b57f2afe368097fc9d7b5827a8c8a338b9 100644 --- a/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h +++ b/ecmascript/compiler/builtins/linked_hashtable_stub_builder.h @@ -20,10 +20,10 @@ namespace panda::ecmascript::kungfu { template -class LinkedHashTableStubBuilder : public BuiltinsStubBuilder { +class LinkedHashTableStubBuilder : public StubBuilder { public: - explicit LinkedHashTableStubBuilder(BuiltinsStubBuilder *parent, GateRef glue) - : BuiltinsStubBuilder(parent), glue_(glue) {} + explicit LinkedHashTableStubBuilder(StubBuilder *parent, GateRef glue) + : StubBuilder(parent), glue_(glue) {} ~LinkedHashTableStubBuilder() override = default; NO_MOVE_SEMANTIC(LinkedHashTableStubBuilder); NO_COPY_SEMANTIC(LinkedHashTableStubBuilder); @@ -31,13 +31,18 @@ public: GateRef Create(GateRef numberOfElements); GateRef Clear(GateRef linkedTable); - GateRef ForEach(GateRef thisValue, GateRef linkedTable, GateRef numArgs); + GateRef ForEach(GateRef thisValue, GateRef linkedTable, GateRef callbackFnHandle, GateRef thisArg); GateRef Insert(GateRef linkedTable, GateRef key, GateRef value); GateRef Delete(GateRef linkedTable, GateRef key); GateRef Has(GateRef linkedTable, GateRef key); GateRef Get(GateRef linkedTable, GateRef key); - void GenMapSetConstructor(GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs); + void GenMapSetConstructor(GateRef nativeCode, GateRef func, GateRef newTarget, GateRef thisValue, GateRef numArgs, + GateRef arg0, GateRef argv); + + GateRef GetLinked(GateRef jsThis); + + void SetLinked(GateRef jsThis, GateRef newTable); private: GateRef IsKey(GateRef key) @@ -56,7 +61,6 @@ private: return Int32Add(bucket, Int32(LinkedHashTableType::ELEMENTS_START_INDEX)); } - GateRef GetHash(GateRef key); GateRef HashObjectIsMatch(GateRef key, GateRef other); GateRef FindElement(GateRef linkedTable, GateRef key, GateRef hash); GateRef GetKey(GateRef linkedTable, GateRef entry) @@ -202,6 +206,7 @@ private: GateRef ComputeCapacity(GateRef atLeastSpaceFor); void RemoveEntry(GateRef linkedTable, GateRef entry); void StoreHashTableToNewObject(GateRef newTargetHClass, Variable& returnValue); + GateRef GetLinkedOffset(); GateRef glue_; }; diff --git a/ecmascript/compiler/builtins_lowering.cpp b/ecmascript/compiler/builtins_lowering.cpp index 679d62ebad13d736be089f6cf1006d44e8067143..8857b9f5cb64044f6fbf4bb2ab3ea35607c4b80f 100644 --- a/ecmascript/compiler/builtins_lowering.cpp +++ b/ecmascript/compiler/builtins_lowering.cpp @@ -14,7 +14,6 @@ */ #include "ecmascript/compiler/builtins_lowering.h" - #include "ecmascript/global_env.h" namespace panda::ecmascript::kungfu { @@ -25,32 +24,29 @@ void BuiltinLowering::LowerTypedCallBuitin(GateRef gate) auto idGate = acc_.GetValueIn(gate, valuesIn - 1); auto id = static_cast(acc_.GetConstantValue(idGate)); switch (id) { - case BUILTINS_STUB_ID(FLOOR): - LowerTypedFloor(gate); - break; - case BUILTINS_STUB_ID(LocaleCompare): + case BUILTINS_STUB_ID(StringLocaleCompare): LowerTypedLocaleCompare(gate); break; - case BUILTINS_STUB_ID(SORT): + case BUILTINS_STUB_ID(ArraySort): LowerTypedArraySort(gate); break; - case BUILTINS_STUB_ID(STRINGIFY): + case BUILTINS_STUB_ID(JsonStringify): LowerTypedStringify(gate); break; - case BUILTINS_STUB_ID(MAP_PROTO_ITERATOR): - case BUILTINS_STUB_ID(SET_PROTO_ITERATOR): - case BUILTINS_STUB_ID(STRING_PROTO_ITERATOR): - case BUILTINS_STUB_ID(ARRAY_PROTO_ITERATOR): - case BUILTINS_STUB_ID(TYPED_ARRAY_PROTO_ITERATOR): + case BUILTINS_STUB_ID(MapProtoIterator): + case BUILTINS_STUB_ID(SetProtoIterator): + case BUILTINS_STUB_ID(StringProtoIterator): + case BUILTINS_STUB_ID(ArrayProtoIterator): + case BUILTINS_STUB_ID(TypeArrayProtoIterator): LowerBuiltinIterator(gate, id); break; - case BUILTINS_STUB_ID(MAP_ITERATOR_PROTO_NEXT): - case BUILTINS_STUB_ID(SET_ITERATOR_PROTO_NEXT): - case BUILTINS_STUB_ID(STRING_ITERATOR_PROTO_NEXT): - case BUILTINS_STUB_ID(ARRAY_ITERATOR_PROTO_NEXT): + case BUILTINS_STUB_ID(MapIteratorProtoNext): + case BUILTINS_STUB_ID(SetIteratorProtoNext): + case BUILTINS_STUB_ID(StringIteratorProtoNext): + case BUILTINS_STUB_ID(ArrayIteratorProtoNext): LowerIteratorNext(gate, id); break; - case BUILTINS_STUB_ID(ITERATOR_PROTO_RETURN): + case BUILTINS_STUB_ID(IteratorProtoReturn): LowerIteratorReturn(gate, id); break; case BUILTINS_STUB_ID(NumberConstructor): @@ -113,19 +109,6 @@ GateRef BuiltinLowering::TypedFloor(GateRef gate) return ret; } -void BuiltinLowering::LowerTypedSqrt(GateRef gate) -{ - Environment env(gate, circuit_, &builder_); - GateRef param = acc_.GetValueIn(gate, 0); - // 20.2.2.32 - // If value is NAN or negative, include -NaN and -Infinity but not -0.0, the result is NaN - // Assembly instruction support NAN and negative - auto ret = builder_.Sqrt(param); - acc_.SetMachineType(ret, MachineType::F64); - acc_.SetGateType(ret, GateType::NJSValue()); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); -} - GateRef BuiltinLowering::IntToTaggedIntPtr(GateRef x) { GateRef val = builder_.SExtInt32ToInt64(x); @@ -204,11 +187,11 @@ GateRef BuiltinLowering::LowerCallTargetCheck(Environment *env, GateRef gate) GateRef idGate = acc_.GetValueIn(gate, 1); BuiltinsStubCSigns::ID id = static_cast(acc_.GetConstantValue(idGate)); switch (id) { - case BuiltinsStubCSigns::ID::MAP_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::SET_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::STRING_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::ARRAY_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::TYPED_ARRAY_PROTO_ITERATOR: { + case BuiltinsStubCSigns::ID::MapProtoIterator: + case BuiltinsStubCSigns::ID::SetProtoIterator: + case BuiltinsStubCSigns::ID::StringProtoIterator: + case BuiltinsStubCSigns::ID::ArrayProtoIterator: + case BuiltinsStubCSigns::ID::TypeArrayProtoIterator: { return LowerCallTargetCheckWithDetector(gate, id); } case BuiltinsStubCSigns::ID::NumberConstructor: { @@ -241,27 +224,27 @@ GateRef BuiltinLowering::LowerCallTargetCheckWithDetector(GateRef gate, Builtins JSType expectType = JSType::INVALID; uint8_t detectorIndex = 0; switch (id) { - case BuiltinsStubCSigns::ID::MAP_PROTO_ITERATOR: { + case BuiltinsStubCSigns::ID::MapProtoIterator: { expectType = JSType::JS_MAP; detectorIndex = GlobalEnv::MAP_ITERATOR_DETECTOR_INDEX; break; } - case BuiltinsStubCSigns::ID::SET_PROTO_ITERATOR: { + case BuiltinsStubCSigns::ID::SetProtoIterator: { expectType = JSType::JS_SET; detectorIndex = GlobalEnv::SET_ITERATOR_DETECTOR_INDEX; break; } - case BuiltinsStubCSigns::ID::STRING_PROTO_ITERATOR: { + case BuiltinsStubCSigns::ID::StringProtoIterator: { expectType = JSType::STRING_FIRST; detectorIndex = GlobalEnv::STRING_ITERATOR_DETECTOR_INDEX; break; } - case BuiltinsStubCSigns::ID::ARRAY_PROTO_ITERATOR: { + case BuiltinsStubCSigns::ID::ArrayProtoIterator: { expectType = JSType::JS_ARRAY; detectorIndex = GlobalEnv::ARRAY_ITERATOR_DETECTOR_INDEX; break; } - case BuiltinsStubCSigns::ID::TYPED_ARRAY_PROTO_ITERATOR: { + case BuiltinsStubCSigns::ID::TypeArrayProtoIterator: { expectType = JSType::JS_TYPED_ARRAY_FIRST; detectorIndex = GlobalEnv::TYPED_ARRAY_ITERATOR_DETECTOR_INDEX; break; @@ -289,30 +272,19 @@ GateRef BuiltinLowering::CheckPara(GateRef gate, GateRef funcCheck) return funcCheck; } switch (id) { - case BuiltinsStubCSigns::ID::FLOOR: { - if (acc_.GetNumValueIn(gate) <= 2U) { - return funcCheck; - } - GateRef para = acc_.GetValueIn(gate, 2); - GateRef paracheck = builder_.TaggedIsNumber(para); - return builder_.BoolAnd(paracheck, funcCheck); - } - case BuiltinsStubCSigns::ID::SQRT: - // NumberSpeculativeRetype is checked - return funcCheck; - case BuiltinsStubCSigns::ID::LocaleCompare: - case BuiltinsStubCSigns::ID::SORT: - case BuiltinsStubCSigns::ID::STRINGIFY: - case BuiltinsStubCSigns::ID::MAP_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::SET_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::STRING_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::ARRAY_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::TYPED_ARRAY_PROTO_ITERATOR: - case BuiltinsStubCSigns::ID::MAP_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::SET_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::STRING_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::ARRAY_ITERATOR_PROTO_NEXT: - case BuiltinsStubCSigns::ID::ITERATOR_PROTO_RETURN: + case BuiltinsStubCSigns::ID::StringLocaleCompare: + case BuiltinsStubCSigns::ID::ArraySort: + case BuiltinsStubCSigns::ID::JsonStringify: + case BuiltinsStubCSigns::ID::MapProtoIterator: + case BuiltinsStubCSigns::ID::SetProtoIterator: + case BuiltinsStubCSigns::ID::StringProtoIterator: + case BuiltinsStubCSigns::ID::ArrayProtoIterator: + case BuiltinsStubCSigns::ID::TypeArrayProtoIterator: + case BuiltinsStubCSigns::ID::MapIteratorProtoNext: + case BuiltinsStubCSigns::ID::SetIteratorProtoNext: + case BuiltinsStubCSigns::ID::StringIteratorProtoNext: + case BuiltinsStubCSigns::ID::ArrayIteratorProtoNext: + case BuiltinsStubCSigns::ID::IteratorProtoReturn: case BuiltinsStubCSigns::ID::NumberConstructor: // Don't need check para return funcCheck; @@ -339,23 +311,23 @@ void BuiltinLowering::LowerBuiltinIterator(GateRef gate, BuiltinsStubCSigns::ID GateRef obj = acc_.GetValueIn(gate, 0); GateRef result = Circuit::NullGate(); switch (id) { - case BUILTINS_STUB_ID(MAP_PROTO_ITERATOR): { + case BUILTINS_STUB_ID(MapProtoIterator): { result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSMapIterator, { glue, obj }); break; } - case BUILTINS_STUB_ID(SET_PROTO_ITERATOR): { + case BUILTINS_STUB_ID(SetProtoIterator): { result = builder_.CallStub(glue, gate, CommonStubCSigns::CreateJSSetIterator, { glue, obj }); break; } - case BUILTINS_STUB_ID(STRING_PROTO_ITERATOR): { + case BUILTINS_STUB_ID(StringProtoIterator): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(CreateStringIterator), { obj }, true); break; } - case BUILTINS_STUB_ID(ARRAY_PROTO_ITERATOR): { + case BUILTINS_STUB_ID(ArrayProtoIterator): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSArrayIterator), { obj }, true); break; } - case BUILTINS_STUB_ID(TYPED_ARRAY_PROTO_ITERATOR): { + case BUILTINS_STUB_ID(TypeArrayProtoIterator): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(NewJSTypedArrayIterator), { obj }, true); break; } @@ -371,19 +343,19 @@ void BuiltinLowering::LowerIteratorNext(GateRef gate, BuiltinsStubCSigns::ID id) GateRef thisObj = acc_.GetValueIn(gate, 0); GateRef result = Circuit::NullGate(); switch (id) { - case BUILTINS_STUB_ID(MAP_ITERATOR_PROTO_NEXT): { + case BUILTINS_STUB_ID(MapIteratorProtoNext): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(MapIteratorNext), { thisObj }, true); break; } - case BUILTINS_STUB_ID(SET_ITERATOR_PROTO_NEXT): { + case BUILTINS_STUB_ID(SetIteratorProtoNext): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(SetIteratorNext), { thisObj }, true); break; } - case BUILTINS_STUB_ID(STRING_ITERATOR_PROTO_NEXT): { + case BUILTINS_STUB_ID(StringIteratorProtoNext): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(StringIteratorNext), { thisObj }, true); break; } - case BUILTINS_STUB_ID(ARRAY_ITERATOR_PROTO_NEXT): { + case BUILTINS_STUB_ID(ArrayIteratorProtoNext): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(ArrayIteratorNext), { thisObj }, true); break; } @@ -399,7 +371,7 @@ void BuiltinLowering::LowerIteratorReturn(GateRef gate, BuiltinsStubCSigns::ID i GateRef thisObj = acc_.GetValueIn(gate, 0); GateRef result = Circuit::NullGate(); switch (id) { - case BUILTINS_STUB_ID(ITERATOR_PROTO_RETURN): { + case BUILTINS_STUB_ID(IteratorProtoReturn): { result = LowerCallRuntime(glue, gate, RTSTUB_ID(IteratorReturn), { thisObj }, true); break; } diff --git a/ecmascript/compiler/builtins_lowering.h b/ecmascript/compiler/builtins_lowering.h index 49e6aeb0f15155519fe9906da3f0b19bb7ee6aad..df58303345b47449b1d3b9c58f3578bf4af7bbfe 100644 --- a/ecmascript/compiler/builtins_lowering.h +++ b/ecmascript/compiler/builtins_lowering.h @@ -28,7 +28,6 @@ public: ~BuiltinLowering() = default; void LowerTypedCallBuitin(GateRef gate); GateRef LowerCallTargetCheck(Environment *env, GateRef gate); - void LowerTypedSqrt(GateRef gate); GateRef CheckPara(GateRef gate, GateRef funcCheck); void LowerTypedLocaleCompare(GateRef gate); void LowerTypedArraySort(GateRef gate); diff --git a/ecmascript/compiler/bytecode_circuit_builder.cpp b/ecmascript/compiler/bytecode_circuit_builder.cpp index a5932ab58d69965905a8b40cc22392633ffe4a5a..dc810679193169272a7563cfc9641f4d571b572d 100644 --- a/ecmascript/compiler/bytecode_circuit_builder.cpp +++ b/ecmascript/compiler/bytecode_circuit_builder.cpp @@ -17,6 +17,7 @@ #include "ecmascript/base/number_helper.h" #include "ecmascript/compiler/gate_accessor.h" +#include "ecmascript/deoptimizer/deoptimizer.h" #include "ecmascript/ts_types/ts_manager.h" #include "libpandafile/bytecode_instruction-inl.h" @@ -386,10 +387,6 @@ void BytecodeCircuitBuilder::BuildCircuitArgs() } } argAcc_.CollectArgs(); - if (HasTypes()) { - argAcc_.FillArgsGateType(&typeRecorder_); - } - BuildFrameArgs(); } @@ -410,6 +407,51 @@ void BytecodeCircuitBuilder::BuildFrameArgs() argAcc_.SetFrameArgs(frameArgs); } +void BytecodeCircuitBuilder::BuildOSRArgs() +{ + // offset -1 : glue + (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_GLUE), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::NJSValue()); + // offset -2 : argc + GateRef argc = method_->IsFastCall() + ? circuit_->GetConstantGate(MachineType::I64, 0, GateType::NJSValue()) + : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ARGS), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::TaggedValue()); + // offset -3 : func + (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_FUNCTION), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::TaggedValue()); + // offset -4 : new_target + GateRef newTarget = + method_->IsFastCall() + ? circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::UndefinedType()) + : circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NEW_TARGET), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::TaggedValue()); + // offset -5 : this_object + (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_THIS_OBJECT), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::TaggedValue()); + // offset -6 : numargs + (void)circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_NUM_ARGS), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::TaggedValue()); + for (size_t argIdx = 1; argIdx <= method_->GetNumArgsWithCallField(); argIdx++) { + // common args + argAcc_.NewArg(method_->IsFastCall() ? static_cast(FastCallArgIdx::NUM_OF_ARGS) + : static_cast(CommonArgIdx::NUM_OF_ARGS) + argIdx); + } + + auto &args = argAcc_.args_; + if (args.size() == 0) { + GateAccessor(circuit_).GetArgsOuts(args); + std::reverse(args.begin(), args.end()); + if (method_->IsFastCall() && args.size() >= static_cast(FastCallArgIdx::NUM_OF_ARGS)) { + args.insert(args.begin() + static_cast(CommonArgIdx::ACTUAL_ARGC), argc); + // 3: newtarget index + args.insert(args.begin() + static_cast(CommonArgIdx::NEW_TARGET), newTarget); + } + } + + BuildFrameArgs(); +} + std::vector BytecodeCircuitBuilder::CreateGateInList( const BytecodeInfo &info, const GateMetaData *meta) { @@ -695,7 +737,7 @@ void BytecodeCircuitBuilder::NewByteCode(BytecodeRegion &bb) // handle return.dyn and returnundefined bytecodes gate = NewReturn(bb); } else if (bytecodeInfo.IsMov()) { - frameStateBuilder_.UpdateMoveValues(bytecodeInfo, iterator.Index()); + frameStateBuilder_.UpdateMoveValues(bytecodeInfo); } else if (!bytecodeInfo.IsDiscarded()) { LOG_ECMA(FATAL) << "this branch is unreachable"; UNREACHABLE(); @@ -757,13 +799,162 @@ void BytecodeCircuitBuilder::BuildSubCircuit() } } +bool BytecodeCircuitBuilder::FindOsrLoopHeadBB() +{ + int32_t loopBackBcIndex {-1}; + for (size_t k = 0; k < pcOffsets_.size(); k++) { + if (static_cast(pcOffsets_[k] - pcOffsets_[0]) == osrOffset_) { + loopBackBcIndex = k; + } + } + if (loopBackBcIndex == -1) { + LOG_COMPILER(ERROR) << "Unable to find the loop back of OSR."; + return false; + } + auto &rpoList = frameStateBuilder_.GetRpoList(); + for (auto &bbId : rpoList) { + auto &bb = RegionAt(bbId); + if (bb.end == static_cast(loopBackBcIndex)) { + frameStateBuilder_.SetOsrLoopHeadBB(bb); + return true; + } + } + LOG_COMPILER(ERROR) << "Unable to find the loop head bb of OSR."; + return false; +} + +void BytecodeCircuitBuilder::GenDeoptAndReturnForOsrLoopExit(BytecodeRegion &osrLoopExitBB) +{ + frameStateBuilder_.AdvanceToNextBB(osrLoopExitBB, true); + GateRef state = frameStateBuilder_.GetCurrentState(); + GateRef depend = frameStateBuilder_.GetCurrentDepend(); + std::string comment = Deoptimizier::DisplayItems(DeoptType::OSRLOOPEXIT); + GateRef type = + circuit_->GetConstantGate(MachineType::I64, static_cast(DeoptType::OSRLOOPEXIT), GateType::NJSValue()); + GateRef condition = circuit_->GetConstantGate(MachineType::I1, 0, GateType::NJSValue()); + GateRef deopt = circuit_->NewGate(circuit_->DeoptCheck(), MachineType::I1, + {state, depend, condition, gateAcc_.GetFrameState(depend), type}, + GateType::NJSValue(), comment.c_str()); + GateRef dependRelay = circuit_->NewGate(circuit_->DependRelay(), {deopt, depend}); + GateRef undef = + circuit_->GetConstantGate(MachineType::I64, JSTaggedValue::VALUE_UNDEFINED, GateType::TaggedValue()); + circuit_->NewGate(circuit_->Return(), {state, dependRelay, undef, circuit_->GetReturnRoot()}); +} + +void BytecodeCircuitBuilder::CollectCacheBBforOSRLoop(BytecodeRegion *bb) +{ + catchBBOfOSRLoop_.insert(bb); + for (BytecodeRegion *succBB : bb->succs) { + CollectCacheBBforOSRLoop(succBB); + } +} + +void BytecodeCircuitBuilder::HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB) +{ + if (!osrLoopBodyBB.trys.empty()) { + GateRef state = frameStateBuilder_.GetCurrentState(); + GateRef depend = frameStateBuilder_.GetCurrentDepend(); + auto getException = + circuit_->NewGate(circuit_->GetException(), MachineType::I64, {state, depend}, GateType::AnyType()); + frameStateBuilder_.UpdateAccumulator(getException); + frameStateBuilder_.UpdateStateDepend(state, getException); + } + // collect catch BB. + if (!osrLoopBodyBB.catches.empty()) { + for (BytecodeRegion *targetBB : osrLoopBodyBB.catches) { + CollectCacheBBforOSRLoop(targetBB); + } + } + EnumerateBlock(osrLoopBodyBB, [this, &osrLoopBodyBB](const BytecodeInfo &bytecodeInfo) -> bool { + NewByteCode(osrLoopBodyBB); + if (bytecodeInfo.IsJump() || bytecodeInfo.IsThrow()) { + return false; + } + return true; + }); + bool needFallThrough = true; + if (!osrLoopBodyBB.IsEmptryBlock()) { + const BytecodeInfo &bytecodeInfo = GetBytecodeInfo(osrLoopBodyBB.end); + needFallThrough = bytecodeInfo.needFallThrough(); + } + // fallThrough or empty merge osrLoopBodyBB + if (needFallThrough) { + ASSERT(osrLoopBodyBB.succs.size() == 1); // 1: fall through + auto &bbNext = RegionAt(osrLoopBodyBB.succs[0]->id); + frameStateBuilder_.MergeIntoSuccessor(osrLoopBodyBB, bbNext); + bbNext.expandedPreds.push_back({osrLoopBodyBB.id, osrLoopBodyBB.end, false}); + } +} + +void BytecodeCircuitBuilder::BuildOsrCircuit() +{ + if (!FindOsrLoopHeadBB()) { + LOG_COMPILER(FATAL) << "invalid osr offset"; + } + circuit_->SetIsOsr(); + auto &entryBlock = RegionAt(0); + frameStateBuilder_.InitEntryBB(entryBlock); + std::set osrLoopExitBBIds; + auto &rpoList = frameStateBuilder_.GetRpoList(); + for (auto &bbId : rpoList) { + auto &bb = RegionAt(bbId); + if (frameStateBuilder_.IsOsrLoopExit(bb)) { + // The loop exit BB is in front of the loop head BB. At this time, + // the loop exit BB does not have the context object, and the processing of the loop exit BB is delayed. + if (frameStateBuilder_.IsContextExists(bb.id)) { + GenDeoptAndReturnForOsrLoopExit(bb); + } else { + osrLoopExitBBIds.insert(bbId); + } + continue; + } + + // Processes only the BBs related to the loop specified by the OSR. + if (!IsEntryBlock(bb.id) && frameStateBuilder_.OutOfOsrLoop(bb) && !IsCacheBBOfOSRLoop(bb)) { + continue; + } + + frameStateBuilder_.AdvanceToNextBB(bb); + if (IsEntryBlock(bb.id)) { + if (NeedCheckSafePointAndStackOver()) { + GateRef state = frameStateBuilder_.GetCurrentState(); + GateRef depend = frameStateBuilder_.GetCurrentDepend(); + auto stackCheck = circuit_->NewGate(circuit_->CheckSafePointAndStackOver(), {state, depend}); + bb.dependCache = stackCheck; + frameStateBuilder_.UpdateStateDepend(stackCheck, stackCheck); + } + auto *bbNext = &RegionAt(bb.id + 1); + while (!IsEntryBlock(bbNext->id) && frameStateBuilder_.OutOfOsrLoop(*bbNext)) { + bbNext = &RegionAt(bbNext->id + 1); + } + frameStateBuilder_.MergeIntoSuccessor(bb, *bbNext); + bbNext->expandedPreds.push_back({bb.id, bb.end, false}); + continue; + } + + HandleOsrLoopBody(bb); + } + for (size_t bbId : osrLoopExitBBIds) { + auto &bb = RegionAt(bbId); + GenDeoptAndReturnForOsrLoopExit(bb); + } +} + void BytecodeCircuitBuilder::BuildCircuit() { - // create arg gates array - BuildCircuitArgs(); - frameStateBuilder_.DoBytecodeAnalysis(); - // build states sub-circuit of each block - BuildSubCircuit(); + if (IsOSR()) { + // create osr arg gates array + BuildOSRArgs(); + frameStateBuilder_.DoBytecodeAnalysis(); + // build states sub-circuit of osr block + BuildOsrCircuit(); + } else { + // create arg gates array + BuildCircuitArgs(); + frameStateBuilder_.DoBytecodeAnalysis(); + // build states sub-circuit of each block + BuildSubCircuit(); + } if (IsLogEnabled()) { PrintGraph("Bytecode2Gate"); LOG_COMPILER(INFO) << "\033[34m" << "============= " diff --git a/ecmascript/compiler/bytecode_circuit_builder.h b/ecmascript/compiler/bytecode_circuit_builder.h index 52e1ec694593444bd3ec765c408026c6b8676652..4050e77fb4dadab13fe73b20d38f1c4b1b13824c 100644 --- a/ecmascript/compiler/bytecode_circuit_builder.h +++ b/ecmascript/compiler/bytecode_circuit_builder.h @@ -17,27 +17,20 @@ #define ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H #include -#include #include #include #include -#include #include "ecmascript/compiler/argument_accessor.h" #include "ecmascript/compiler/bytecode_info_collector.h" #include "ecmascript/compiler/bytecodes.h" #include "ecmascript/compiler/circuit.h" -#include "ecmascript/compiler/compiler_log.h" #include "ecmascript/compiler/ecma_opcode_des.h" #include "ecmascript/compiler/frame_states.h" -#include "ecmascript/compiler/loop_analysis.h" #include "ecmascript/compiler/pgo_type/pgo_type_recorder.h" -#include "ecmascript/compiler/type_recorder.h" #include "ecmascript/interpreter/interpreter-inl.h" #include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/method_literal.h" -#include "ecmascript/compiler/compiler_log.h" -#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h" namespace panda::ecmascript::kungfu { struct ExceptionItem { @@ -216,23 +209,18 @@ public: BytecodeCircuitBuilder(const JSPandaFile *jsPandaFile, const MethodLiteral *methodLiteral, const MethodPcInfo &methodPCInfo, - TSManager *tsManager, Circuit *circuit, Bytecodes *bytecodes, - bool hasTypes, bool enableLog, bool enableTypeLowering, std::string name, const CString &recordName, PGOProfilerDecoder *decoder, - bool isInline, - bool enableOptTrackField) - : tsManager_(tsManager), circuit_(circuit), graph_(circuit->chunk()), file_(jsPandaFile), + bool isInline) + : circuit_(circuit), graph_(circuit->chunk()), file_(jsPandaFile), method_(methodLiteral), gateAcc_(circuit), argAcc_(circuit, method_), - typeRecorder_(jsPandaFile, method_, tsManager, recordName, decoder, methodPCInfo, bytecodes, - enableOptTrackField), pgoTypeRecorder_(*decoder, jsPandaFile, method_->GetMethodId().GetOffset()), - hasTypes_(hasTypes), enableLog_(enableLog), enableTypeLowering_(enableTypeLowering), + enableLog_(enableLog), enableTypeLowering_(enableTypeLowering), pcOffsets_(methodPCInfo.pcOffsets), frameStateBuilder_(this, circuit, methodLiteral), methodName_(name), recordName_(recordName), @@ -284,6 +272,11 @@ public: return true; } + void SetOsrOffset(int32_t offset) + { + osrOffset_ = offset; + } + bool NeedCheckSafePointAndStackOver() const { return !isInline_ && !method_->IsNoGC(); @@ -332,11 +325,6 @@ public: suspendAndResumeGates_.emplace_back(gate); }; - inline bool HasTypes() const - { - return hasTypes_; - } - template void EnumerateBlock(BytecodeRegion &bb, const Callback &cb) { @@ -389,7 +377,7 @@ public: return pgoTypeRecorder_.GetElementsKindsForUser(GetPcOffsetByGate(gate)); } - std::vector GetTransitionElementsKindsForUser(GateRef gate) const + PUBLIC_API std::vector GetTransitionElementsKindsForUser(GateRef gate) const { return pgoTypeRecorder_.GetTransitionElementsKindsForUser(GetPcOffsetByGate(gate)); } @@ -512,16 +500,6 @@ public: return bbId == 1; } - TSManager *GetTSManager() const - { - return tsManager_; - } - - const TypeRecorder *GetTypeRecorder() const - { - return &typeRecorder_; - } - const PGOTypeRecorder *GetPGOTypeRecorder() const { return &pgoTypeRecorder_; @@ -575,6 +553,16 @@ public: GateType::AnyType()); } + bool IsOSR() const + { + return osrOffset_ != MachineCode::INVALID_OSR_OFFSET; + } + + bool IsCacheBBOfOSRLoop(const BytecodeRegion &bb) const + { + return catchBBOfOSRLoop_.find(&bb) != catchBBOfOSRLoop_.end(); + } + private: void CollectTryCatchBlockInfo(ExceptionInfo &Exception); void BuildCatchBlocks(const ExceptionInfo &Exception); @@ -582,6 +570,7 @@ private: void BuildRegions(const ExceptionInfo &Exception); // build circuit void BuildCircuitArgs(); + void BuildOSRArgs(); std::vector CreateGateInList(const BytecodeInfo &info, const GateMetaData *meta); GateRef NewConst(const BytecodeInfo &info); void NewJSGate(BytecodeRegion &bb); @@ -591,6 +580,11 @@ private: void MergeThrowGate(BytecodeRegion &bb, uint32_t bcIndex); void MergeExceptionGete(BytecodeRegion &bb, const BytecodeInfo& bytecodeInfo, uint32_t bcIndex); void BuildSubCircuit(); + bool FindOsrLoopHeadBB(); + void GenDeoptAndReturnForOsrLoopExit(BytecodeRegion& osrLoopExitBB); + void CollectCacheBBforOSRLoop(BytecodeRegion *bb); + void HandleOsrLoopBody(BytecodeRegion &osrLoopBodyBB); + void BuildOsrCircuit(); void UpdateCFG(); void CollectTryPredsInfo(); @@ -609,7 +603,6 @@ private: return *graph_[i]; } - TSManager *tsManager_; Circuit *circuit_; std::vector> byteCodeToJSGates_; std::unordered_map jsGatesToByteCode_; @@ -618,9 +611,8 @@ private: const MethodLiteral *method_ {nullptr}; GateAccessor gateAcc_; ArgumentAccessor argAcc_; - TypeRecorder typeRecorder_; PGOTypeRecorder pgoTypeRecorder_; - bool hasTypes_ {false}; + int32_t osrOffset_ {MachineCode::INVALID_OSR_OFFSET}; bool enableLog_ {false}; bool enableTypeLowering_ {false}; std::vector suspendAndResumeGates_ {}; @@ -638,6 +630,7 @@ private: size_t numOfLiveBB_ {0}; bool isInline_ {false}; uint32_t methodId_ {0}; + std::set catchBBOfOSRLoop_{}; }; } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_CLASS_LINKER_BYTECODE_CIRCUIT_IR_BUILDER_H diff --git a/ecmascript/compiler/call_signature.cpp b/ecmascript/compiler/call_signature.cpp index 966c557c34a2ac13d249e5f6b1ca11637ff6b29d..4f4af0bdaff1d63a4006b189a9e9ce1783f4fcf5 100644 --- a/ecmascript/compiler/call_signature.cpp +++ b/ecmascript/compiler/call_signature.cpp @@ -1447,6 +1447,20 @@ DEF_CALL_SIGNATURE(StringGetEnd) callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); } +DEF_CALL_SIGNATURE(ClearJitCompiledCodeFlags) +{ + // 1 : 1 input parameters + CallSignature ClearJitCompiledCodeFlags("ClearJitCompiledCodeFlags", 0, 1, + ArgumentsOrder::DEFAULT_ORDER, VariableType::VOID()); + *callSign = ClearJitCompiledCodeFlags; + std::array params = { // 1 : 1 input parameters + VariableType::JS_POINTER(), + }; + callSign->SetParameters(params.data()); + callSign->SetGCLeafFunction(true); + callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); +} + #define PUSH_CALL_ARGS_AND_DISPATCH_SIGNATURE_COMMON(name) \ /* 1 : 1 input parameters */ \ CallSignature signature(#name, 0, 1, \ @@ -1775,6 +1789,23 @@ DEF_CALL_SIGNATURE(DebugPrintInstruction) callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); } +DEF_CALL_SIGNATURE(DebugOsrEntry) +{ + // 2 : 2 input parameters + CallSignature debugOsrEntry("DebugOsrEntry", 0, 2, + ArgumentsOrder::DEFAULT_ORDER, VariableType::VOID()); + *callSign = debugOsrEntry; + // 2 : 2 input parameters + std::array params = { + VariableType::NATIVE_POINTER(), + VariableType::NATIVE_POINTER(), + }; + callSign->SetVariadicArgs(true); + callSign->SetParameters(params.data()); + callSign->SetGCLeafFunction(true); + callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); +} + DEF_CALL_SIGNATURE(Comment) { // 1 : 1 input parameters @@ -1866,20 +1897,6 @@ DEF_CALL_SIGNATURE(InsertLocalToShareRSet) callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); } -DEF_CALL_SIGNATURE(FloatSqrt) -{ - // 1 : 1 input parameters - CallSignature index("FloatSqrt", 0, 1, ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); - *callSign = index; - // 1 : 1 input parameters - std::array params = { - VariableType::FLOAT64(), - }; - callSign->SetParameters(params.data()); - callSign->SetGCLeafFunction(true); - callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); -} - #define DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(NAME) \ DEF_CALL_SIGNATURE(NAME) \ { \ @@ -1907,11 +1924,17 @@ DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatSin) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatSinh) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatTan) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatTanh) +DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatExp) +DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatExpm1) +DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatTrunc) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatFloor) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatLog) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatLog2) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatLog10) DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatLog1p) +DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatCbrt) +DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatClz32) +DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME(FloatCeil) #undef DEF_FLOAT_UNARY_CALL_SIGNATURE_BY_NAME @@ -1954,6 +1977,20 @@ DEF_CALL_SIGNATURE(FindElementWithCache) callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); } +DEF_CALL_SIGNATURE(NumberIsFinite) +{ + // 1 : 1 input parameters + CallSignature index("NumberIsFinite", 0, 1, ArgumentsOrder::DEFAULT_ORDER, VariableType::BOOL()); + *callSign = index; + // 1 : 1 input parameters + std::array params = { + VariableType::FLOAT64(), + }; + callSign->SetParameters(params.data()); + callSign->SetGCLeafFunction(true); + callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); +} + DEF_CALL_SIGNATURE(DoubleToInt) { // 2 : 2 input parameters @@ -2344,6 +2381,22 @@ DEF_CALL_SIGNATURE(CreateJSMapIterator) callSign->SetCallConv(CallSignature::CallConv::CCallConv); } +DEF_CALL_SIGNATURE(JSMapGet) +{ + // 3 : 3 input parameters + CallSignature signature("JSMapGet", 0, 3, + ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); + *callSign = signature; + // 3 : 3 input parameters + std::array params = { + VariableType::NATIVE_POINTER(), // glue + VariableType::JS_ANY(), // obj + VariableType::JS_ANY(), // key + }; + callSign->SetParameters(params.data()); + callSign->SetCallConv(CallSignature::CallConv::CCallConv); +} + DEF_CALL_SIGNATURE(FastStringEqual) { // 3 : 3 input parameters @@ -2391,4 +2444,23 @@ DEF_CALL_SIGNATURE(DeleteObjectProperty) callSign->SetParameters(params.data()); callSign->SetCallConv(CallSignature::CallConv::CCallConv); } + +DEF_CALL_SIGNATURE(CopyTypedArrayBuffer) +{ + // 5 : 5 input parameters + CallSignature CopyTypedArrayBuffer("CopyTypedArrayBuffer", 0, 5, + ArgumentsOrder::DEFAULT_ORDER, VariableType::JS_ANY()); + *callSign = CopyTypedArrayBuffer; + // 5 : 5 input parameters + std::array params = { + VariableType::JS_POINTER(), + VariableType::JS_POINTER(), + VariableType::INT32(), + VariableType::INT32(), + VariableType::INT32() + }; + callSign->SetParameters(params.data()); + callSign->SetGCLeafFunction(true); + callSign->SetTargetKind(CallSignature::TargetKind::RUNTIME_STUB_NO_GC); +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/call_signature.h b/ecmascript/compiler/call_signature.h index f6529e6f6e4c7a89bf9dde460feaad56d20d1f4e..44e5a88fc900bbc190e4834846f9be87a8d10ef9 100644 --- a/ecmascript/compiler/call_signature.h +++ b/ecmascript/compiler/call_signature.h @@ -432,6 +432,7 @@ private: V(DebugPrint) \ V(DebugPrintCustom) \ V(DebugPrintInstruction) \ + V(DebugOsrEntry) \ V(Comment) \ V(FatalPrint) \ V(FatalPrintCustom) \ @@ -441,7 +442,6 @@ private: V(DoubleToInt) \ V(DoubleToLength) \ V(FloatMod) \ - V(FloatSqrt) \ V(FloatAcos) \ V(FloatAcosh) \ V(FloatAsin) \ @@ -455,12 +455,19 @@ private: V(FloatSinh) \ V(FloatTan) \ V(FloatTanh) \ + V(FloatTrunc) \ V(FloatLog) \ V(FloatLog2) \ V(FloatLog10) \ V(FloatLog1p) \ + V(FloatExp) \ + V(FloatExpm1) \ + V(FloatCbrt) \ + V(FloatClz32) \ V(FloatFloor) \ V(FloatPow) \ + V(FloatCeil) \ + V(NumberIsFinite) \ V(FindElementWithCache) \ V(MarkingBarrier) \ V(StoreBarrier) \ @@ -497,6 +504,7 @@ private: V(Getnextpropname) \ V(CreateJSSetIterator) \ V(CreateJSMapIterator) \ + V(JSMapGet) \ V(JSHClassFindProtoTransitions) \ V(NumberHelperStringToDouble) \ V(GetStringToListCacheArray) \ @@ -504,7 +512,10 @@ private: V(LocaleCompareNoGc) \ V(StringGetStart) \ V(StringGetEnd) \ - V(ArrayTrim) + V(ArrayTrim) \ + V(OptimizedFastJmp) \ + V(ClearJitCompiledCodeFlags) \ + V(CopyTypedArrayBuffer) #define DECL_CALL_SIGNATURE(name) \ class name##CallSignature final { \ diff --git a/ecmascript/compiler/circuit.cpp b/ecmascript/compiler/circuit.cpp index b485abfe413495f2f0f0a14d1c9d34336df8244f..81cac27461fdb762ef5ec1c3308ff38ed28dd77a 100644 --- a/ecmascript/compiler/circuit.cpp +++ b/ecmascript/compiler/circuit.cpp @@ -239,9 +239,9 @@ void Circuit::SetMark(GateRef gate, MarkCode mark) const const_cast(LoadGatePtrConst(gate))->SetMark(mark, GetTime()); } -void Circuit::Verify(GateRef gate) const +void Circuit::Verify(GateRef gate, const std::string& methodName) const { - LoadGatePtrConst(gate)->Verify(IsArch64()); + LoadGatePtrConst(gate)->Verify(IsArch64(), methodName); } GateRef Circuit::NullGate() diff --git a/ecmascript/compiler/circuit.h b/ecmascript/compiler/circuit.h index 3c3562c16fec93215db1e4b76a6e8cbbecf5f013..144177b7c2a871356cd882f3761cbb7fc0d1ece7 100644 --- a/ecmascript/compiler/circuit.h +++ b/ecmascript/compiler/circuit.h @@ -61,7 +61,7 @@ public: void PrintAllGatesWithBytecode() const; void GetAllGates(std::vector& gates) const; static GateRef NullGate(); - void Verify(GateRef gate) const; + void Verify(GateRef gate, const std::string& methodName = "") const; panda::ecmascript::FrameType GetFrameType() const; void SetFrameType(panda::ecmascript::FrameType type); GateRef GetConstantGate(MachineType machineType, uint64_t value, GateType type); @@ -184,16 +184,6 @@ public: return metaBuilder_.JSBytecode(valuesIn, methodId, opcode, pcOffset, bcIndex, flags); } - const GateMetaData* TypedBinaryOp(uint64_t value, TypedBinOp binOp, PGOTypeRef type) - { - return metaBuilder_.TypedBinaryOp(value, binOp, type); - } - - const GateMetaData* TypedCallTargetCheckOp(uint32_t numIns, uint64_t value, TypedCallTargetCheckOp checkOp) - { - return metaBuilder_.TypedCallTargetCheckOp(numIns, value, checkOp); - } - GateRef DeadGate() { if (dead_ == NullGate()) { @@ -216,6 +206,16 @@ public: bool GetDebugInfo(GateRef g, size_t &index) const; + bool IsOsr() const + { + return isOsr_; + } + + void SetIsOsr() + { + isOsr_ = true; + } + private: static const size_t CIRCUIT_SPACE = 1U << 30U; // 1GB public: @@ -280,6 +280,7 @@ private: std::map initialEnvCache_ {}; panda::ecmascript::FrameType frameType_ {FrameType::OPTIMIZED_FRAME}; bool isArch64_ { false }; + bool isOsr_ { false }; Chunk chunk_; GateRef root_ { NullGate() }; diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index 9764b4d56d0a7b7e732baf965f22006427dfa687..63e3c2153ff7e50be1b4b2bb1e13b4663f92f5d4 100644 --- a/ecmascript/compiler/circuit_builder.cpp +++ b/ecmascript/compiler/circuit_builder.cpp @@ -22,16 +22,17 @@ #include "ecmascript/compiler/lcr_circuit_builder.h" #include "ecmascript/compiler/mcr_circuit_builder.h" #include "ecmascript/compiler/rt_call_signature.h" +#include "ecmascript/compiler/share_gate_meta_data.h" #include "ecmascript/deoptimizer/deoptimizer.h" #include "ecmascript/global_env.h" #include "ecmascript/ic/proto_change_details.h" +#include "ecmascript/js_array_iterator.h" #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_function.h" #include "ecmascript/js_thread.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/mem/region.h" #include "ecmascript/method.h" -#include "ecmascript/js_array_iterator.h" namespace panda::ecmascript::kungfu { @@ -311,20 +312,21 @@ void CircuitBuilder::ClearConstantCache(GateRef gate) GetCircuit()->ClearConstantCache(machineType, value, gateType); } -GateRef CircuitBuilder::DeoptCheck(GateRef condition, GateRef frameState, DeoptType type) +void CircuitBuilder::DeoptCheck(GateRef condition, GateRef frameState, DeoptType type) { std::string comment = Deoptimizier::DisplayItems(type); auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); ASSERT(acc_.GetOpCode(frameState) == OpCode::FRAME_STATE); - GateRef ret = GetCircuit()->NewGate(circuit_->DeoptCheck(), + GateRef deoptCheck = GetCircuit()->NewGate(circuit_->DeoptCheck(), MachineType::I1, { currentControl, currentDepend, condition, frameState, Int64(static_cast(type))}, GateType::NJSValue(), comment.c_str()); - auto dependRelay = DependRelay(ret, currentDepend); - currentLabel->SetControl(ret); + // Add a state output to avoid schedule a phi node to deoptCheck's BB by mistake + GateRef trueBB = circuit_->NewGate(circuit_->OrdinaryBlock(), { deoptCheck }); + auto dependRelay = DependRelay(trueBB, currentDepend); + currentLabel->SetControl(trueBB); currentLabel->SetDepend(dependRelay); - return ret; } GateRef CircuitBuilder::GetSuperConstructor(GateRef ctor) @@ -737,6 +739,28 @@ GateRef CircuitBuilder::IsEcmaObject(GateRef obj) return ret; } +GateRef CircuitBuilder::CheckJSType(GateRef object, JSType jsType) +{ + Label entryPass(env_); + SubCfgEntry(&entryPass); + DEFVALUE(result, env_, VariableType::BOOL(), False()); + Label heapObj(env_); + Label exit(env_); + GateRef isHeapObject = TaggedIsHeapObject(object); + BRANCH_CIR2(isHeapObject, &heapObj, &exit); + Bind(&heapObj); + { + GateRef objectType = GetObjectType(LoadHClass(object)); + GateRef checkType = Int32Equal(objectType, Int32(static_cast(jsType))); + result = LogicAnd(isHeapObject, checkType); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + SubCfgExit(); + return ret; +} + GateRef CircuitBuilder::GetObjectFromConstPool(GateRef glue, GateRef hirGate, GateRef constPool, GateRef module, GateRef index, ConstPoolType type) { diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index a5ddc8f1c3eb9537aaa0062fef88a405a063287c..cf171fe582ce1081132cd85f472595364894d922 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -19,25 +19,27 @@ #include "ecmascript/base/number_helper.h" #include "ecmascript/compiler/assembler/assembler.h" #include "ecmascript/compiler/builtins/builtins_call_signature.h" -#include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/call_signature.h" +#include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/gate.h" #include "ecmascript/compiler/gate_accessor.h" +#include "ecmascript/compiler/lcr_gate_meta_data.h" +#include "ecmascript/compiler/pgo_type/pgo_type_location.h" +#include "ecmascript/compiler/share_gate_meta_data.h" #include "ecmascript/compiler/variable_type.h" #include "ecmascript/global_env_constants.h" -#include "ecmascript/compiler/pgo_type/pgo_type_location.h" -#include "ecmascript/jspandafile/constpool_value.h" #include "ecmascript/js_hclass.h" #include "ecmascript/js_runtime_options.h" #include "ecmascript/js_tagged_value.h" +#include "ecmascript/jspandafile/constpool_value.h" #include "ecmascript/tagged_array.h" -#include namespace panda::ecmascript::kungfu { using namespace panda::ecmascript; #define DEFVALUE(varname, cirBuilder, type, val) \ Variable varname(cirBuilder, type, cirBuilder->NextVariableId(), val) +class BuiltinsTypedArrayStubBuilder; class BuiltinsStringStubBuilder; class CompilationConfig; class Environment; @@ -61,6 +63,7 @@ class PostSchedule; V(Int64Add, Add, MachineType::I64) \ V(DoubleAdd, Add, MachineType::F64) \ V(PtrAdd, Add, MachineType::ARCH) \ + V(DoubleExp, Exp, MachineType::F64) \ V(Int16Sub, Sub, MachineType::I16) \ V(Int32Sub, Sub, MachineType::I32) \ V(Int64Sub, Sub, MachineType::I64) \ @@ -92,7 +95,11 @@ class PostSchedule; V(Int32LSR, Lsr, MachineType::I32) \ V(Int64LSR, Lsr, MachineType::I64) \ V(Int32ASR, Asr, MachineType::I32) \ - V(Int64ASR, Asr, MachineType::I64) + V(Int64ASR, Asr, MachineType::I64) \ + V(Int32Min, Min, MachineType::I32) \ + V(DoubleMin, Min, MachineType::F64) \ + V(Int32Max, Max, MachineType::I32) \ + V(DoubleMax, Max, MachineType::F64) #define UNARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH(V) \ V(BoolNot, Rev, MachineType::I1) \ @@ -101,6 +108,7 @@ class PostSchedule; V(CastDoubleToInt64, Bitcast, MachineType::I64) \ V(CastInt64ToFloat64, Bitcast, MachineType::F64) \ V(CastInt32ToFloat32, Bitcast, MachineType::F32) \ + V(CastFloat32ToInt32, Bitcast, MachineType::I32) \ V(SExtInt32ToInt64, Sext, MachineType::I64) \ V(SExtInt1ToInt64, Sext, MachineType::I64) \ V(SExtInt1ToInt32, Sext, MachineType::I32) \ @@ -116,6 +124,7 @@ class PostSchedule; V(SExtInt32ToPtr, Sext, MachineType::ARCH) \ V(ZExtInt16ToInt32, Zext, MachineType::I32) \ V(ZExtInt16ToInt64, Zext, MachineType::I64) \ + V(DoubleTrunc, DoubleTrunc, MachineType::F64) \ V(TruncInt16ToInt8, Trunc, MachineType::I8) \ V(TruncInt64ToInt32, Trunc, MachineType::I32) \ V(TruncPtrToInt32, Trunc, MachineType::I32) \ @@ -135,7 +144,12 @@ class PostSchedule; V(SExtInt16ToInt64, Sext, MachineType::I64) \ V(SExtInt16ToInt32, Sext, MachineType::I32) \ V(SExtInt8ToInt32, Sext, MachineType::I32) \ - V(SExtInt8ToInt64, Sext, MachineType::I64) + V(SExtInt8ToInt64, Sext, MachineType::I64) \ + V(Abs, Abs, MachineType::I32) \ + V(FAbs, Abs, MachineType::F64) \ + V(CountLeadingZeroes32, Clz32, MachineType::I32) \ + V(DoubleCeil, Ceil, MachineType::F64) \ + V(DoubleFloor, Floor, MachineType::F64) #define UNARY_ARITHMETIC_METHOD_LIST_WITH_BITWIDTH_PRIVATE(V) \ V(ChangeTaggedPointerToInt64, TaggedToInt64, MachineType::I64) @@ -183,7 +197,7 @@ public: GateRef Arguments(size_t index); GateRef DefaultCase(GateRef switchBranch); GateRef DependRelay(GateRef state, GateRef depend); - GateRef DeoptCheck(GateRef condition, GateRef frameState, DeoptType type); + void DeoptCheck(GateRef condition, GateRef frameState, DeoptType type); GateRef GetElementsArray(GateRef object); GateRef GetLengthOfTaggedArray(GateRef array); GateRef GetLengthOfJSTypedArray(GateRef array); @@ -207,6 +221,7 @@ public: GateRef IsJsCOWArray(GateRef obj); GateRef IsCOWArray(GateRef objectType); GateRef IsTaggedArray(GateRef object); + GateRef CheckJSType(GateRef object, JSType jsType); GateRef IsMutantTaggedArray(GateRef objectType); GateRef SwitchCase(GateRef switchBranch, int64_t value); GateRef Int8(int8_t val); @@ -484,33 +499,33 @@ public: GateRef FlattenTreeStringCheck(GateRef gate); GateRef HClassStableArrayCheck(GateRef gate, GateRef frameState, ArrayMetaDataAccessor accessor); GateRef ArrayGuardianCheck(GateRef frameState); - GateRef TypedArrayCheck(GateRef gate, GateType type, TypedArrayMetaDateAccessor::Mode mode, + GateRef TypedArrayCheck(GateRef gate, ParamType paramType, TypedArrayMetaDateAccessor::Mode mode, OnHeapMode onHeap = OnHeapMode::NONE); - GateRef LoadTypedArrayLength(GateRef gate, GateType type, OnHeapMode onHeap = OnHeapMode::NONE); + GateRef LoadTypedArrayLength(GateRef gate, ParamType paramType, OnHeapMode onHeap = OnHeapMode::NONE); GateRef RangeGuard(GateRef gate, uint32_t left, uint32_t right); GateRef BuiltinPrototypeHClassCheck(GateRef gate, BuiltinTypeId type, ElementsKind kind, bool isPrototypeOfPrototype); GateRef OrdinaryHasInstanceCheck(GateRef target, GateRef jsFunc, std::vector &expectedHCIndexes); GateRef IndexCheck(GateRef gate, GateRef index); - GateRef ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex, + GateRef ObjectTypeCheck(bool isHeapObject, GateRef gate, GateRef hclassIndex, GateRef frameState = Gate::InvalidGateRef); GateRef TryPrimitiveTypeCheck(GateType type, GateRef gate); GateRef CallTargetCheck(GateRef gate, GateRef function, GateRef id, const char* comment = nullptr); GateRef CallTargetCheck(GateRef gate, GateRef function, GateRef id, std::vector params, const char* comment = nullptr); - GateRef JSCallTargetFromDefineFuncCheck(GateType type, GateRef func, GateRef gate); + GateRef JSCallTargetFromDefineFuncCheck(GateRef func, GateRef gate); template - GateRef JSCallTargetTypeCheck(GateType type, GateRef func, GateRef methodIndex, GateRef gate); + GateRef JSCallTargetTypeCheck(GateRef func, GateRef methodIndex, GateRef gate); template - GateRef JSCallThisTargetTypeCheck(GateType type, GateRef func, GateRef gate); + GateRef JSCallThisTargetTypeCheck(GateRef func, GateRef gate); template - inline GateRef JSNoGCCallThisTargetTypeCheck(GateType type, GateRef func, GateRef methodId, GateRef gate); - GateRef TypeOfCheck(GateRef gate, GateType type); - GateRef TypedTypeOf(GateType type); + inline GateRef JSNoGCCallThisTargetTypeCheck(GateRef func, GateRef methodId, GateRef gate); + GateRef TypeOfCheck(GateRef gate, ParamType paramType); + GateRef TypedTypeOf(ParamType paramType); GateRef TypedCallOperator(GateRef hirGate, MachineType type, const std::vector& inList, bool isSideEffect); inline GateRef TypedCallBuiltin(GateRef hirGate, const std::vector &args, BuiltinsStubCSigns::ID id, bool isSideEffect); - GateRef TypeConvert(MachineType type, GateType typeFrom, GateType typeTo, const std::vector& inList); + GateRef TypeConvert(MachineType type, ParamType typeFrom, GateType typeTo, const std::vector& inList); GateRef Int32CheckRightIsZero(GateRef right); GateRef RemainderIsNegativeZero(GateRef left, GateRef right); GateRef Float64CheckRightIsZero(GateRef right); @@ -519,6 +534,9 @@ public: GateRef LexVarIsHoleCheck(GateRef value); GateRef IsUndefinedOrHoleCheck(GateRef value); GateRef IsNotUndefinedOrHoleCheck(GateRef value); + GateRef IsEcmaObjectCheck(GateRef obj); + GateRef IsDataViewCheck(GateRef obj); + GateRef IsTaggedBooleanCheck(GateRef value); GateRef Int32UnsignedUpperBoundCheck(GateRef value, GateRef upperBound); GateRef Int32DivWithCheck(GateRef left, GateRef right); GateType GetGateTypeOfValueType(ValueType type); @@ -527,20 +545,18 @@ public: GateRef InsertTypedArrayCheck(GateType type, GateRef array); GateRef ArrayConstructorCheck(GateRef gate); GateRef ObjectConstructorCheck(GateRef gate); - GateRef InsertTypedBinaryop(GateRef left, GateRef right, GateType leftType, GateType rightType, - GateType gateType, PGOTypeRef pgoType, TypedBinOp op); + GateRef InsertTypedBinaryop(GateRef left, GateRef right, TypedBinOp op); GateRef InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, GateRef right); - GateRef TypedConditionJump(MachineType type, TypedJumpOp jumpOp, uint32_t weight, GateType typeVal, + GateRef TypedConditionJump(MachineType type, TypedJumpOp jumpOp, uint32_t weight, ParamType paramType, const std::vector& inList); GateRef TypedNewAllocateThis(GateRef ctor, GateRef hclassIndex, GateRef frameState); GateRef TypedSuperAllocateThis(GateRef superCtor, GateRef newTarget, GateRef frameState); template - inline GateRef TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType, GateType gateType, - PGOTypeRef pgoType); + inline GateRef TypedBinaryOp(GateRef x, GateRef y, ParamType paramType); template - inline GateRef TypedUnaryOp(GateRef x, GateType xType, GateType gateType); + inline GateRef TypedUnaryOp(GateRef x, ParamType paramType); template - inline GateRef TypedConditionJump(GateRef x, GateType xType, uint32_t weight); + inline GateRef TypedConditionJump(GateRef x, ParamType paramType, uint32_t weight); GateRef Convert(GateRef gate, ValueType src, ValueType dst); GateRef ConvertBoolToTaggedBoolean(GateRef gate); GateRef ConvertTaggedBooleanToBool(GateRef gate); @@ -589,7 +605,7 @@ public: GateRef StartAllocate(); GateRef FinishAllocate(GateRef value); - inline GateRef PrimitiveToNumber(GateRef x, VariableType type); + inline GateRef PrimitiveToNumber(GateRef x, ParamType paramType); inline GateRef GetValueFromTaggedArray(GateRef array, GateRef index); inline GateRef GetValueFromTaggedArray(VariableType valType, GateRef array, GateRef index); inline GateRef GetValueFromJSArrayWithElementsKind(VariableType type, GateRef array, GateRef index); @@ -668,7 +684,7 @@ public: inline GateRef TaggedIsBigInt(GateRef obj); inline GateRef TaggedIsString(GateRef obj); inline GateRef TaggedIsStringIterator(GateRef obj); - inline GateRef TaggedIsShared(GateRef obj); + inline GateRef TaggedIsSharedObj(GateRef obj); inline GateRef TaggedIsStringOrSymbol(GateRef obj); inline GateRef TaggedIsSymbol(GateRef obj); inline GateRef TaggedIsProtoChangeMarker(GateRef obj); @@ -681,6 +697,8 @@ public: inline GateRef TaggedObjectIsShared(GateRef obj); inline GateRef TaggedObjectBothAreString(GateRef x, GateRef y); inline GateRef TaggedObjectIsEcmaObject(GateRef obj); + inline GateRef TaggedObjectIsByteArray(GateRef obj); + inline GateRef TaggedObjectIsDataView(GateRef obj); inline GateRef IsSpecialHole(GateRef x); inline GateRef IsNotSpecialHole(GateRef x); inline GateRef TaggedTrue(); @@ -702,6 +720,8 @@ public: GateRef NumberToString(GateRef number); GateRef TaggedPointerToInt64(GateRef x); GateRef GetLengthFromString(GateRef value); + GateRef Rotl(GateRef word, uint32_t shift); + GateRef CalcHashcodeForInt(GateRef value); GateRef GetHashcodeFromString(GateRef glue, GateRef value); GateRef TryGetHashcodeFromString(GateRef string); GateRef IsIntegerString(GateRef string); @@ -715,6 +735,19 @@ public: GateRef charSize, VariableType type); void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger); GateRef StringFromSingleCharCode(GateRef gate); + GateRef NumberIsNaN(GateRef gate); + GateRef NumberIsFinite(GateRef gate); + GateRef NumberIsInteger(GateRef gate); + GateRef NumberIsSafeInteger(GateRef gate); + GateRef ArrayBufferIsView(GateRef gate); + GateRef DataViewGet( + GateRef thisobj, GateRef index, GateRef dataViewCallID, GateRef isLittleEndian, GateRef frameState); + GateRef DataViewSet(GateRef thisobj, + GateRef index, + GateRef value, + GateRef dataViewCallID, + GateRef isLittleEndian, + GateRef frameState); GateRef ToNumber(GateRef gate, GateRef value, GateRef glue); GateRef IsASCIICharacter(GateRef gate); @@ -765,6 +798,9 @@ public: MemoryOrder order = MemoryOrder::Default()); // cast operation + inline GateRef Int16ToBigEndianInt16(GateRef x); + inline GateRef Int32ToBigEndianInt32(GateRef x); + inline GateRef Int64ToBigEndianInt64(GateRef x); inline GateRef GetInt64OfTInt(GateRef x); inline GateRef GetInt32OfTInt(GateRef x); inline GateRef TaggedCastToIntPtr(GateRef x); @@ -774,6 +810,8 @@ public: inline GateRef GetDoubleOfTNumber(GateRef x); inline GateRef DoubleToInt(GateRef x, Label *exit); inline GateRef DoubleToInt(GateRef glue, GateRef x, size_t typeBits); + inline GateRef DoubleCheckINFInRangeInt32(GateRef x); + inline GateRef DoubleInRangeInt32(GateRef x); inline GateRef Int32ToTaggedPtr(GateRef x); inline GateRef Int64ToTaggedPtr(GateRef x); inline GateRef Int32ToTaggedInt(GateRef x); @@ -792,8 +830,8 @@ public: inline GateRef DoubleIsINF(GateRef x); static MachineType GetMachineTypeFromVariableType(VariableType type); - // Unary / BinaryOp - GateRef BuildMathBuiltinOp(const GateMetaData* op, std::vector args); + // Opcode with control and depend inputs from label and value inputs args + GateRef BuildControlDependOp(const GateMetaData* op, std::vector args); template inline GateRef BinaryOp(GateRef x, GateRef y); template @@ -849,6 +887,7 @@ private: CompilationConfig *cmpCfg_ {nullptr}; friend StubBuilder; friend BuiltinsStringStubBuilder; + friend BuiltinsTypedArrayStubBuilder; friend TypedBytecodeLowering; friend NTypeBytecodeLowering; friend PGOHCRLowering; diff --git a/ecmascript/compiler/codegen/llvm/llvm_ir_builder.cpp b/ecmascript/compiler/codegen/llvm/llvm_ir_builder.cpp index 31355bd2b2e0461f8a2afc6ac1f50e75a977408a..6bba197fd011ea38297509cc22ea52977f3843aa 100644 --- a/ecmascript/compiler/codegen/llvm/llvm_ir_builder.cpp +++ b/ecmascript/compiler/codegen/llvm/llvm_ir_builder.cpp @@ -45,6 +45,8 @@ #endif #include "llvm/IR/Instructions.h" +#include "llvm/IR/Intrinsics.h" +#include "llvm/IR/IRBuilder.h" #if defined(__clang__) #pragma clang diagnostic pop @@ -204,6 +206,14 @@ void LLVMIRBuilder::InitializeHandlers() {OpCode::MUL_WITH_OVERFLOW, &LLVMIRBuilder::HandleMulWithOverflow}, {OpCode::EXTRACT_VALUE, &LLVMIRBuilder::HandleExtractValue}, {OpCode::SQRT, &LLVMIRBuilder::HandleSqrt}, + {OpCode::EXP, &LLVMIRBuilder::HandleExp}, + {OpCode::ABS, &LLVMIRBuilder::HandleAbs}, + {OpCode::MIN, &LLVMIRBuilder::HandleMin}, + {OpCode::MAX, &LLVMIRBuilder::HandleMax}, + {OpCode::CLZ32, &LLVMIRBuilder::HandleClz32}, + {OpCode::DOUBLE_TRUNC, &LLVMIRBuilder::HandleDoubleTrunc}, + {OpCode::CEIL, &LLVMIRBuilder::HandleCeil}, + {OpCode::FLOOR, &LLVMIRBuilder::HandleFloor}, {OpCode::READSP, &LLVMIRBuilder::HandleReadSp}, {OpCode::FINISH_ALLOCATE, &LLVMIRBuilder::HandleFinishAllocate}, }; @@ -1981,6 +1991,165 @@ void LLVMIRBuilder::VisitSqrt(GateRef gate, GateRef e1) } } +void LLVMIRBuilder::HandleExp(GateRef gate) +{ + GateRef base = acc_.GetIn(gate, 0U); + GateRef power = acc_.GetIn(gate, 1U); + VisitExp(gate, base, power); +} + +void LLVMIRBuilder::VisitExp([[maybe_unused]] GateRef gate, [[maybe_unused]] GateRef e1, [[maybe_unused]] GateRef e2) +{ +#ifdef SUPPORT_LLVM_INTRINSICS_WITH_CALLS + llvm::Value *e1Value = llvm::unwrap(GetLValue(e1)); + llvm::Value *e2Value = llvm::unwrap(GetLValue(e2)); + + [[maybe_unused]] auto machineType = acc_.GetMachineType(gate); + ASSERT(machineType == MachineType::F64); + ASSERT(acc_.GetMachineType(e1) == machineType); + ASSERT(acc_.GetMachineType(e2) == machineType); + + llvm::Value *result = nullptr; + + constexpr double one = 1.0; + if (acc_.IsConstant(e1) && acc_.GetFloat64FromConstant(e1) == std::exp(one)) { + llvm::Intrinsic::ID llvmId = llvm::Intrinsic::exp; + result = llvm::unwrap(builder_)->CreateUnaryIntrinsic(llvmId, e2Value); + } else { + llvm::Intrinsic::ID llvmId = llvm::Intrinsic::pow; + result = llvm::unwrap(builder_)->CreateBinaryIntrinsic(llvmId, e1Value, e2Value); + } +#else + UNREACHABLE(); +#endif +} + +void LLVMIRBuilder::HandleCeil(GateRef gate) +{ + GateRef param = acc_.GetIn(gate, 0); + VisitCeil(gate, param); +} + +void LLVMIRBuilder::VisitCeil(GateRef gate, GateRef e1) +{ + llvm::Value *e1Value = llvm::unwrap(GetLValue(e1)); + ASSERT(acc_.GetMachineType(e1) == acc_.GetMachineType(gate)); + llvm::Intrinsic::ID llvmId = llvm::Intrinsic::ceil; + llvm::Value *result = llvm::unwrap(builder_)->CreateUnaryIntrinsic(llvmId, e1Value); + Bind(gate, llvm::wrap(result)); + + if (IsLogEnabled()) { + SetDebugInfo(gate, llvm::wrap(result)); + } +} + +template +static llvm::CallInst *BuildLLVMIntrinsic(llvm::IRBuilder<> *builder, llvm::Intrinsic::ID llvmId, Ts... inputs) +{ + static_assert((std::is_same_v && ...)); + if constexpr (sizeof...(inputs) == 1) { + return builder->CreateUnaryIntrinsic(llvmId, inputs...); + } else { + static_assert(sizeof...(inputs) == 2); + return builder->CreateBinaryIntrinsic(llvmId, inputs...); + } +} + +void LLVMIRBuilder::HandleAbs(GateRef gate) +{ + VisitAbs(gate, acc_.GetIn(gate, 0)); +} + +void LLVMIRBuilder::VisitAbs(GateRef gate, GateRef e1) +{ + auto machineType = acc_.GetMachineType(gate); + ASSERT(acc_.GetMachineType(e1) == machineType); + llvm::Intrinsic::ID llvmId = 0; + auto *builder = llvm::unwrap(builder_); + llvm::Value *value = llvm::unwrap(GetLValue(e1)); + LLVMValueRef result; + if (machineType == MachineType::I32) { + llvmId = llvm::Intrinsic::abs; + llvm::Type *type = llvm::Type::getInt1Ty(*llvm::unwrap(context_)); + llvm::Value *poison = llvm::Constant::getIntegerValue(type, llvm::APInt(1, 0)); + result = llvm::wrap(BuildLLVMIntrinsic(builder, llvmId, value, poison)); + } else if (machineType == MachineType::F64) { + llvmId = llvm::Intrinsic::fabs; + result = llvm::wrap(BuildLLVMIntrinsic(builder, llvmId, value)); + } else { + LOG_ECMA(FATAL) << "`Abs` type should be untagged double or signed int"; + UNREACHABLE(); + } + Bind(gate, result); + + if (IsLogEnabled()) { + SetDebugInfo(gate, result); + } +} + +void LLVMIRBuilder::HandleMin(GateRef gate) +{ + VisitMin(gate, acc_.GetIn(gate, 0), acc_.GetIn(gate, 1U)); +} + +void LLVMIRBuilder::VisitMin(GateRef gate, GateRef e1, GateRef e2) +{ + auto machineType = acc_.GetMachineType(gate); + ASSERT(acc_.GetMachineType(e1) == machineType); + ASSERT(acc_.GetMachineType(e2) == machineType); + llvm::Intrinsic::ID llvmId = 0; + if (machineType == MachineType::I32) { + llvmId = llvm::Intrinsic::smin; + } else if (machineType == MachineType::F64) { + llvmId = llvm::Intrinsic::minimum; + } else { + LOG_ECMA(FATAL) << "`Min` type should be untagged double or signed int"; + UNREACHABLE(); + } + VisitIntrinsic(gate, llvmId, e1, e2); +} + +void LLVMIRBuilder::HandleMax(GateRef gate) +{ + VisitMax(gate, acc_.GetIn(gate, 0), acc_.GetIn(gate, 1U)); +} + +void LLVMIRBuilder::VisitMax(GateRef gate, GateRef e1, GateRef e2) +{ + auto machineType = acc_.GetMachineType(gate); + ASSERT(acc_.GetMachineType(e1) == machineType); + ASSERT(acc_.GetMachineType(e2) == machineType); + llvm::Intrinsic::ID llvmId = 0; + if (machineType == MachineType::I32) { + llvmId = llvm::Intrinsic::smax; + } else if (machineType == MachineType::F64) { + llvmId = llvm::Intrinsic::maximum; + } else { + LOG_ECMA(FATAL) << "`Max` type should be untagged double or signed int"; + UNREACHABLE(); + } + VisitIntrinsic(gate, llvmId, e1, e2); +} + +void LLVMIRBuilder::HandleFloor(GateRef gate) +{ + VisitIntrinsic(gate, llvm::Intrinsic::floor, acc_.GetIn(gate, 0)); +} + +template +void LLVMIRBuilder::VisitIntrinsic(GateRef gate, llvm::Intrinsic::ID llvmId, Ts... inputs) +{ + static_assert((std::is_same_v && ...)); + + auto *builder = llvm::unwrap(builder_); + LLVMValueRef result = llvm::wrap(BuildLLVMIntrinsic(builder, llvmId, llvm::unwrap(GetLValue(inputs))...)); + Bind(gate, result); + + if (IsLogEnabled()) { + SetDebugInfo(gate, result); + } +} + LLVMIntPredicate LLVMIRBuilder::ConvertLLVMPredicateFromICMP(ICmpCondition cond) { switch (cond) { @@ -2102,6 +2271,25 @@ void LLVMIRBuilder::HandleChangeInt64ToTagged(GateRef gate) VisitChangeInt64ToTagged(gate, acc_.GetIn(gate, 0)); } +void LLVMIRBuilder::HandleDoubleTrunc(GateRef gate) +{ + GateRef param = acc_.GetIn(gate, 0); + VisitDoubleTrunc(gate, param); +} + +void LLVMIRBuilder::VisitDoubleTrunc(GateRef gate, GateRef e1) +{ + llvm::Value *e1Value = llvm::unwrap(GetLValue(e1)); + ASSERT(acc_.GetMachineType(e1) == acc_.GetMachineType(gate)); + llvm::Intrinsic::ID llvmId = llvm::Intrinsic::trunc; + llvm::Value *result = llvm::unwrap(builder_)->CreateUnaryIntrinsic(llvmId, e1Value); + Bind(gate, llvm::wrap(result)); + + if (IsLogEnabled()) { + SetDebugInfo(gate, llvm::wrap(result)); + } +} + void LLVMIRBuilder::VisitIntDiv(GateRef gate, GateRef e1, GateRef e2) { LLVMValueRef e1Value = GetLValue(e1); @@ -2418,6 +2606,26 @@ void LLVMIRBuilder::HandleDeoptCheck(GateRef gate) Bind(gate, result); } +void LLVMIRBuilder::HandleClz32(GateRef gate) +{ + VisitClz32(gate, acc_.GetIn(gate, 0)); +} + +void LLVMIRBuilder::VisitClz32(GateRef gate, GateRef param) +{ + LLVMValueRef value = GetLValue(param); + LLVMValueRef trueConst = LLVMConstInt(GetInt1T(), 0, true); + + llvm::CallInst *result = llvm::unwrap(builder_)->CreateBinaryIntrinsic(llvm::Intrinsic::ctlz, + llvm::unwrap(value), + llvm::unwrap(trueConst)); + Bind(gate, llvm::wrap(result)); + + if (IsLogEnabled()) { + SetDebugInfo(gate, value); + } +} + LLVMTypeRef LLVMIRBuilder::GetExperimentalDeoptTy() { auto fnTy = LLVMFunctionType(GetTaggedHPtrT(), nullptr, 0, 1); diff --git a/ecmascript/compiler/codegen/llvm/llvm_ir_builder.h b/ecmascript/compiler/codegen/llvm/llvm_ir_builder.h index 36060206b89ca854cd6c8d0f983922deb98266e3..849ddd332d9151ce651a2bd6c2d6a5f327fa1e5e 100644 --- a/ecmascript/compiler/codegen/llvm/llvm_ir_builder.h +++ b/ecmascript/compiler/codegen/llvm/llvm_ir_builder.h @@ -311,6 +311,8 @@ private: LLVMValueRef CanonicalizeToPtr(LLVMValueRef value, LLVMTypeRef ptrType) const; LLVMValueRef GetCurrentFrameType(LLVMValueRef currentSpFrameAddr); void SetFunctionCallConv(); + template + void VisitIntrinsic(GateRef gate, unsigned llvmId, Ts... inputs); bool IsLogEnabled() const { diff --git a/ecmascript/compiler/codegen/maple/litecg_ir_builder.cpp b/ecmascript/compiler/codegen/maple/litecg_ir_builder.cpp index 440aa4a1ea8d593ee88534c47d4c8719440306c7..43bd5751aac481f6348c2a438b5afd3b1ee76f26 100644 --- a/ecmascript/compiler/codegen/maple/litecg_ir_builder.cpp +++ b/ecmascript/compiler/codegen/maple/litecg_ir_builder.cpp @@ -30,6 +30,7 @@ #include "ecmascript/frames.h" #include "ecmascript/js_thread.h" #include "ecmascript/method.h" +#include "triple.h" #include "lmir_builder.h" namespace panda::ecmascript::kungfu { @@ -74,6 +75,9 @@ LiteCGIRBuilder::LiteCGIRBuilder(const std::vector> *schedu slotSize_ = sizeof(uint64_t); slotType_ = lmirBuilder_->i64Type; InitializeHandlers(); + if (cfg != nullptr) { + maple::Triple::GetTriple().Init(cfg->IsAArch64()); + } } LiteCGIRBuilder::~LiteCGIRBuilder() @@ -153,7 +157,9 @@ void LiteCGIRBuilder::AddFunc() std::string funcName = lmirModule_->GetFuncName(methodLiteral_, jsPandaFile_); FunctionBuilder funcBuilder = lmirBuilder_->DefineFunction(funcName); funcBuilder.Param(lmirBuilder_->i64Type, "glue"); - if (!methodLiteral_->IsFastCall()) { + if (circuit_->IsOsr()) { + funcBuilder.Param(lmirBuilder_->i64PtrType, "interpSp"); + } else if (!methodLiteral_->IsFastCall()) { funcBuilder.Param(lmirBuilder_->i64Type, "actualArgc") .Param(lmirBuilder_->i64RefType, "func") .Param(lmirBuilder_->i64RefType, "new_target") @@ -298,6 +304,11 @@ void LiteCGIRBuilder::GenPrologue(maple::litecg::Function &function) } else if (frameType == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) { reservedSlotsSize = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_); lmirBuilder_->SetFuncFrameResverdSlot(reservedSlotsSize); + if (circuit_->IsOsr()) { + SaveFrameTypeOnFrame(methodLiteral_->IsFastCall() ? FrameType::OPTIMIZED_JS_FAST_CALL_FUNCTION_FRAME + : frameType); + return; + } auto ArgList = circuit_->GetArgRoot(); auto uses = acc_.Uses(ArgList); for (auto useIt = uses.begin(); useIt != uses.end(); ++useIt) { @@ -509,6 +520,7 @@ void LiteCGIRBuilder::InitializeHandlers() {OpCode::SQRT, &LiteCGIRBuilder::HandleSqrt}, {OpCode::READSP, &LiteCGIRBuilder::HandleReadSp}, {OpCode::FINISH_ALLOCATE, &LiteCGIRBuilder::HandleFinishAllocate}, + {OpCode::INITVREG, &LiteCGIRBuilder::HandleInitVreg}, }; illegalOpHandlers_ = {OpCode::NOP, OpCode::CIRCUIT_ROOT, @@ -575,6 +587,11 @@ void LiteCGIRBuilder::HandleParameter(GateRef gate) void LiteCGIRBuilder::VisitParameter(GateRef gate) { + std::vector outs; + acc_.GetOuts(gate, outs); + if (outs.empty()) { + return; + } size_t argth = static_cast(acc_.TryGetValue(gate)); Var ¶m = lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), argth); SaveGate2Expr(gate, lmirBuilder_->GenExprFromVar(param)); @@ -1822,6 +1839,168 @@ void LiteCGIRBuilder::VisitReadSp(GateRef gate) SaveGate2Expr(gate, result); } +void LiteCGIRBuilder::HandleInitVreg(GateRef gate) +{ + ASSERT(acc_.GetOpCode(gate) == OpCode::INITVREG); + VisitInitVreg(gate); +} + +void LiteCGIRBuilder::VisitInitVreg(GateRef gate) +{ + size_t vregNumber = acc_.GetInitOffset(gate); + BB &bb = GetOrCreateBB(instID2bbID_[acc_.GetId(gate)]); + LiteCGType *i64 = lmirBuilder_->i64Type; + LiteCGType *i64Ptr = lmirBuilder_->i64PtrType; + LiteCGType *i64Ref = lmirBuilder_->i64RefType; + LiteCGType *i32 = lmirBuilder_->i32Type; + switch (vregNumber) { + case INIT_VRGE_GLUE: { + // init glue + Expr glue = lmirBuilder_->GenExprFromVar( + lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 0)); // 0 : osr first param - glue + SaveGate2Expr(gate, glue); + return; + } + case INIT_VRGE_ARGS: { + // init argc + SaveGate2Expr(gate, lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, 0))); + return; + } + case INIT_VRGE_FUNCTION: { + // init func + PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref); + // load from frame + Expr sp = lmirBuilder_->GenExprFromVar( + lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1)); // 1 : osr second param - sp + Expr offsetFrame = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64()))); + Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame); + Expr offsetFunc = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetFunctionOffset(!circuit_->IsArch64()))); + Expr addrFunc = lmirBuilder_->Add(i64Ptr, frame, offsetFunc); + Expr ldrFunc = lmirBuilder_->Iread(i64Ref, addrFunc, lmirBuilder_->CreatePtrType(i64Ptr)); + lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrFunc, vreg)); + if (circuit_->GetFrameType() == FrameType::OPTIMIZED_JS_FUNCTION_FRAME) { + // reset jsfunc on OptJSFuncFrame + Expr fpAddr = CallingFp(false); + Expr frameAddr = lmirBuilder_->Cvt(fpAddr.GetType(), lmirBuilder_->i64Type, fpAddr); + size_t reservedOffset = OptimizedJSFunctionFrame::ComputeReservedJSFuncOffset(slotSize_); + Expr frameJSFuncSlotAddr = + lmirBuilder_->Sub(frameAddr.GetType(), frameAddr, + lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(slotType_, reservedOffset))); + Expr jsFuncAddr = lmirBuilder_->Cvt(frameJSFuncSlotAddr.GetType(), + lmirBuilder_->CreatePtrType(slotType_), frameJSFuncSlotAddr); + Expr jsFuncValue = lmirBuilder_->Cvt(lmirBuilder_->i64PtrType, slotType_, lmirBuilder_->Regread(vreg)); + auto &stmt = lmirBuilder_->Iassign(jsFuncValue, jsFuncAddr, jsFuncAddr.GetType()); + lmirBuilder_->AppendStmt(bb, stmt); + } + SaveGate2Expr(gate, lmirBuilder_->Regread(vreg)); + return; + } + case INIT_VRGE_NEW_TARGET: { + // init new_target + PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref); + // load func from interpreter sp + Expr sp = lmirBuilder_->GenExprFromVar( + lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1)); // 1 : osr second param - sp + Expr offsetFrame = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64()))); + Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame); + Expr offsetFunc = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetFunctionOffset(!circuit_->IsArch64()))); + Expr addrFunc = lmirBuilder_->Add(i64Ptr, frame, offsetFunc); + Expr func = lmirBuilder_->Iread(i64Ref, addrFunc, lmirBuilder_->CreatePtrType(i64Ptr)); + // load method from func + Expr offsetMethod = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(lmirBuilder_->i64PtrType, JSFunctionBase::METHOD_OFFSET)); + Expr addrMethod = lmirBuilder_->Add(i64Ptr, func, offsetMethod); + Expr method = lmirBuilder_->Iread(i64Ptr, addrMethod, lmirBuilder_->CreatePtrType(i64Ptr)); + // load callField from method + Expr offsetCF = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64Ptr, Method::CALL_FIELD_OFFSET)); + Expr addrCF = lmirBuilder_->Add(i64Ptr, method, offsetCF); + Expr cf = lmirBuilder_->Iread(i64, addrCF, lmirBuilder_->CreatePtrType(i64)); + // cal new target offset from callField + Expr offsetNVSB = + lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, MethodLiteral::NumVregsBits::START_BIT)); + Expr offsetNVSZ = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64, (1LLU << MethodLiteral::NumVregsBits::SIZE) - 1)); + Expr offsetHFSB = + lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, MethodLiteral::HaveFuncBit::START_BIT)); + Expr offsetHFSZ = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64, (1LLU << MethodLiteral::HaveFuncBit::SIZE) - 1)); + Expr const0 = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, 0)); + Expr numVregs = lmirBuilder_->Cvt( + i64, i32, lmirBuilder_->And(i64, lmirBuilder_->LShr(i64, cf, offsetNVSB), offsetNVSZ)); + Expr haveFunc = lmirBuilder_->Cvt( + i64, i32, + lmirBuilder_->ICmp(i64, lmirBuilder_->And(i64, lmirBuilder_->LShr(i64, cf, offsetHFSB), offsetHFSZ), + const0, IntCmpCondition::kNE)); + Expr size = lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64Ptr, JSTaggedValue::TaggedTypeSize())); + Expr offsetNewTarget = lmirBuilder_->Mul( + i64Ptr, lmirBuilder_->ZExt(i32, i64Ptr, lmirBuilder_->Add(i32, numVregs, haveFunc)), size); + // load new target from sp + Expr addrNewTarget = lmirBuilder_->Add(i64Ptr, sp, offsetNewTarget); + Expr ldrNewTarget = lmirBuilder_->Iread(i64Ref, addrNewTarget, lmirBuilder_->CreatePtrType(i64Ptr)); + lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrNewTarget, vreg)); + SaveGate2Expr(gate, lmirBuilder_->Regread(vreg)); + return; + } + case INIT_VRGE_THIS_OBJECT: { + // init this + PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref); + // load from frame + Expr sp = lmirBuilder_->GenExprFromVar( + lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1)); // 1 : osr second param - sp + Expr offsetFrame = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64()))); + Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame); + Expr offsetThis = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetThisOffset(!circuit_->IsArch64()))); + Expr addrThis = lmirBuilder_->Add(i64Ptr, frame, offsetThis); + Expr ldrThis = lmirBuilder_->Iread(i64Ref, addrThis, lmirBuilder_->CreatePtrType(i64Ptr)); + lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrThis, vreg)); + SaveGate2Expr(gate, lmirBuilder_->Regread(vreg)); + return; + } + case INIT_VRGE_NUM_ARGS: { + // init numargs + SaveGate2Expr(gate, lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64, 0))); + return; + } + case INIT_VRGE_ENV: { + // init env + PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref); + // load from frame + Expr sp = lmirBuilder_->GenExprFromVar( + lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1)); // 1 : osr second param - sp + Expr offsetFrame = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetSize(!circuit_->IsArch64()))); + Expr frame = lmirBuilder_->Sub(i64Ptr, sp, offsetFrame); + Expr offsetEnv = lmirBuilder_->ConstVal( + lmirBuilder_->CreateIntConst(i64Ptr, AsmInterpretedFrame::GetEnvOffset(!circuit_->IsArch64()))); + Expr addrEnv = lmirBuilder_->Add(i64Ptr, frame, offsetEnv); + Expr ldrEnv = lmirBuilder_->Iread(i64Ref, addrEnv, lmirBuilder_->CreatePtrType(i64Ptr)); + lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrEnv, vreg)); + SaveGate2Expr(gate, lmirBuilder_->Regread(vreg)); + return; + } + default: { + // init vregs + PregIdx vreg = lmirBuilder_->CreatePreg(i64Ref); + // load from sp + Expr sp = lmirBuilder_->GenExprFromVar( + lmirBuilder_->GetParam(lmirBuilder_->GetCurFunction(), 1)); // 1 : osr second param - sp + Expr offset = + lmirBuilder_->ConstVal(lmirBuilder_->CreateIntConst(i64Ptr, vregNumber * sizeof(JSTaggedType))); + Expr addr = lmirBuilder_->Add(i64Ptr, sp, offset); + Expr ldrVreg = lmirBuilder_->Iread(i64Ref, addr, lmirBuilder_->CreatePtrType(i64Ptr)); + lmirBuilder_->AppendStmt(bb, lmirBuilder_->Regassign(ldrVreg, vreg)); + SaveGate2Expr(gate, lmirBuilder_->Regread(vreg)); + return; + } + } +} + void LiteCGIRBuilder::HandleFPTrunc(GateRef gate) { VisitFPTrunc(gate, acc_.GetIn(gate, 0)); diff --git a/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn index bc8ece60be1d26cdecebb6ed91e2609810b39658..6057afeef0b539973eb2eae7275d852bee32e7ba 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/maple_be/BUILD.gn @@ -29,7 +29,6 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_ipa/include", "${MAPLEALL_ROOT}/maple_ipa/include/old", "${MAPLEALL_ROOT}/maple_phase/include", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", ] deps_libcg = [ @@ -286,7 +285,7 @@ ohos_static_library("libmplad") { sources = src_libmplad include_dirs = include_directories output_dir = "${root_out_dir}/lib/${HOST_ARCH}" - + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -296,6 +295,7 @@ ohos_source_set("libcglowerer") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcglowerer include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -307,6 +307,7 @@ ohos_static_library("libmplbe") { deps = deps_libmplbe include_dirs = include_directories output_dir = "${root_out_dir}/lib/${HOST_ARCH}" + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -316,6 +317,7 @@ ohos_source_set("libcgaarch64") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcgaarch64 include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -325,6 +327,7 @@ ohos_source_set("libcgx8664") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcgx8664 include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -334,6 +337,7 @@ ohos_source_set("libcgx86phases") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcgx86phases include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -343,6 +347,7 @@ ohos_source_set("libcgriscv64") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcgriscv64 include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -352,6 +357,7 @@ ohos_static_library("libcgark") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcgark include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -361,6 +367,7 @@ ohos_source_set("libcgphases") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcgphases include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } @@ -372,6 +379,7 @@ ohos_static_library("libcg") { include_dirs = include_directories deps = deps_libcg output_dir = "${root_out_dir}/lib/${HOST_ARCH}" + external_deps = [ "bounds_checking_function:libsec_static" ] part_name = "ets_runtime" subsystem_name = "arkcompiler" } diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h index ac77307a9bcae7f60c3c75f97b1bbb72d7fa5147..925e359008f7cdfc1e30f8a9334e968a6ac9bdfc 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_cgfunc.h @@ -830,7 +830,7 @@ public: void SetLmbcTotalStkUsed(int32 offset) { - lmbcArgInfo->lmbcTotalStkUsed = offset; + lmbcArgInfo->lmbcTotalStkUsed = static_cast(offset); } void SetLmbcCallReturnType(MIRType *ty) diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_reg_info.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_reg_info.h index 42ceaaaa16a0d4020ec0192cfd781f05960f381f..cf0c0cc5f7c747717d8e50db0e57d2e91da14a92 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_reg_info.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/aarch64/aarch64_reg_info.h @@ -122,6 +122,11 @@ public: return R17; } + bool IsReservedReg(regno_t regNO) const + { + return (regNO == R16); + } + void Init() override; void Fini() override; void SaveCalleeSavedReg(MapleSet savedRegs) override; diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/abstract_mmir.def b/ecmascript/compiler/codegen/maple/maple_be/include/cg/abstract_mmir.def index da6f99ea8018967b4c0994deef8bce476b5ee2db..689e32c31365d87b166ab3e7a24efd6889cefe79 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/abstract_mmir.def +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/abstract_mmir.def @@ -52,16 +52,24 @@ DEFINE_MOP(MOP_sext_rr_64_32, {&OpndDesc::Reg64ID,&OpndDesc::Reg32IS},ISABSTRACT|ISCONVERSION,0,"sext_r64_r32","",1) /* int2float conversion */ - DEFINE_MOP(MOP_cvt_fr_u32, {&OpndDesc::Reg32FD,&OpndDesc::Reg32IS},ISABSTRACT|ISCONVERSION,0,"cvt_fr_u32","",1) - DEFINE_MOP(MOP_cvt_fr_u64, {&OpndDesc::Reg64FD,&OpndDesc::Reg64IS},ISABSTRACT|ISCONVERSION,0,"cvt_fr_u64","",1) - DEFINE_MOP(MOP_cvt_fr_i32, {&OpndDesc::Reg32FD,&OpndDesc::Reg32IS},ISABSTRACT|ISCONVERSION,0,"cvt_fr_i32","",1) - DEFINE_MOP(MOP_cvt_fr_i64, {&OpndDesc::Reg64FD,&OpndDesc::Reg64IS},ISABSTRACT|ISCONVERSION,0,"cvt_fr_i64","",1) + DEFINE_MOP(MOP_cvt_f32_u32, {&OpndDesc::Reg32FD, &OpndDesc::Reg32IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f32_u32", "", 1) + DEFINE_MOP(MOP_cvt_f64_u32, {&OpndDesc::Reg64FD, &OpndDesc::Reg32IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f64_u32", "", 1) + DEFINE_MOP(MOP_cvt_f32_u64, {&OpndDesc::Reg32FD, &OpndDesc::Reg64IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f32_u64", "", 1) + DEFINE_MOP(MOP_cvt_f64_u64, {&OpndDesc::Reg64FD, &OpndDesc::Reg64IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f64_u64", "", 1) + DEFINE_MOP(MOP_cvt_f32_i32, {&OpndDesc::Reg32FD, &OpndDesc::Reg32IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f32_i32", "", 1) + DEFINE_MOP(MOP_cvt_f64_i32, {&OpndDesc::Reg64FD, &OpndDesc::Reg32IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f64_i32", "", 1) + DEFINE_MOP(MOP_cvt_f32_i64, {&OpndDesc::Reg32FD, &OpndDesc::Reg64IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f32_i64", "", 1) + DEFINE_MOP(MOP_cvt_f64_i64, {&OpndDesc::Reg64FD, &OpndDesc::Reg64IS}, ISABSTRACT | ISCONVERSION, 0, "cvt_f64_i64", "", 1) /* float2int conversion */ - DEFINE_MOP(MOP_cvt_rf_u32, {&OpndDesc::Reg32ID,&OpndDesc::Reg32FS},ISABSTRACT|ISCONVERSION,0,"cvt_rf_u32","",1) - DEFINE_MOP(MOP_cvt_rf_u64, {&OpndDesc::Reg64ID,&OpndDesc::Reg64FS},ISABSTRACT|ISCONVERSION,0,"cvt_rf_u64","",1) - DEFINE_MOP(MOP_cvt_rf_i32, {&OpndDesc::Reg32ID,&OpndDesc::Reg32FS},ISABSTRACT|ISCONVERSION,0,"cvt_rf_i32","",1) - DEFINE_MOP(MOP_cvt_rf_i64, {&OpndDesc::Reg64ID,&OpndDesc::Reg64FS},ISABSTRACT|ISCONVERSION,0,"cvt_rf_i64","",1) + DEFINE_MOP(MOP_cvt_u32_f32, {&OpndDesc::Reg32ID, &OpndDesc::Reg32FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_u32_f32", "", 1) + DEFINE_MOP(MOP_cvt_u64_f32, {&OpndDesc::Reg64ID, &OpndDesc::Reg32FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_u64_f32", "", 1) + DEFINE_MOP(MOP_cvt_u32_f64, {&OpndDesc::Reg32ID, &OpndDesc::Reg64FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_u32_f64", "", 1) + DEFINE_MOP(MOP_cvt_u64_f64, {&OpndDesc::Reg64ID, &OpndDesc::Reg64FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_u64_f64", "", 1) + DEFINE_MOP(MOP_cvt_i32_f32, {&OpndDesc::Reg32ID, &OpndDesc::Reg32FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_i32_f32", "", 1) + DEFINE_MOP(MOP_cvt_i64_f32, {&OpndDesc::Reg64ID, &OpndDesc::Reg32FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_i64_f32", "", 1) + DEFINE_MOP(MOP_cvt_i32_f64, {&OpndDesc::Reg32ID, &OpndDesc::Reg64FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_i32_f64", "", 1) + DEFINE_MOP(MOP_cvt_i64_f64, {&OpndDesc::Reg64ID, &OpndDesc::Reg64FS}, ISABSTRACT | ISCONVERSION, 0, "cvt_i64_f64", "", 1) /* float conversion */ DEFINE_MOP(MOP_cvt_ff_64_32, {&OpndDesc::Reg64FD,&OpndDesc::Reg32FS},ISABSTRACT|ISCONVERSION,0,"cvt_ff_64_32","",1) diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/reg_alloc_lsra.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/reg_alloc_lsra.h index b25bc1850d9f35e5936496e02fcbcf6df3fb91a6..f86b9f11fb7763bf5c107616fba4b16ddae6719b 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/reg_alloc_lsra.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/reg_alloc_lsra.h @@ -773,7 +773,7 @@ public: regno_t HandleSpillForLi(LiveInterval &li); MemOperand *GetSpillMem(uint32 vregNO, bool isDest, Insn &insn, regno_t regNO, bool &isOutOfRange, uint32 bitSize) const; - void InsertCallerSave(Insn &insn, Operand &opnd, bool isDef); + void InsertCallerSave(Insn &insn, Operand &opnd, bool isDef, uint32 spillIdx); uint32 GetRegFromMask(uint32 mask, regno_t offset, const LiveInterval &li); uint32 FindAvailablePhyReg(LiveInterval &li); uint32 AssignPhysRegs(LiveInterval &li); diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/assembler/util.h b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/assembler/util.h index cb9a42ddcc5a82c4a924a43e4e8ec616a6704854..90850f36dd5a6fd44c9721f4027841d8dacf8a68 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/assembler/util.h +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/assembler/util.h @@ -68,11 +68,12 @@ inline bool Is64Bits(uint64 val) return val >= ~uint64(0x7FFFFFFFFFFFFFFFU) || val <= 0x7FFFFFFFFFFFFFFFU; } -inline int64 CalculateLabelSymIdx(int64 funcUniqueId, int64 labelIdx) +inline int64 CalculateLabelSymIdx(uint32 funcUniqueId, uint32 labelIdx) { - /* 16: make sure stIdx is large enough to be unique */ - const int kLeftShiftBits = 16; - return ((funcUniqueId << kLeftShiftBits) + labelIdx) * (-1); /* -1: BBLabel's stIdx is negative */ + /* 32: make sure stIdx is large enough to be unique */ + const int kLeftShiftBits = 32; + /* -1: BBLabel's stIdx is negative */ + return static_cast((static_cast(funcUniqueId) << kLeftShiftBits) + labelIdx) * (-1); } inline int64 CalculateStrLabelSymIdx(uint64 size, int64 labelIdx, size_t strTableSize = 0) diff --git a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_abstract_mapping.def b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_abstract_mapping.def index 19a38332676017e3b94d836b0f3b002612fc82f3..5fbcf6514794c5679571026039491ad6e0c750b6 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_abstract_mapping.def +++ b/ecmascript/compiler/codegen/maple/maple_be/include/cg/x86_64/x64_abstract_mapping.def @@ -113,16 +113,24 @@ DEFINE_MAPPING(abstract::MOP_zext_rr_64_32, x64::MOP_movl_r_r) DEFINE_MAPPING(abstract::MOP_sext_rr_64_32, x64::MOP_movslq_r_r) /* Floating CvtOp int2float */ -DEFINE_MAPPING(abstract::MOP_cvt_fr_u64, x64::MOP_cvtsi2sdq_r) -DEFINE_MAPPING(abstract::MOP_cvt_fr_u32, x64::MOP_cvtsi2sdq_r) -DEFINE_MAPPING(abstract::MOP_cvt_fr_i32, x64::MOP_cvtsi2sdl_r) -DEFINE_MAPPING(abstract::MOP_cvt_fr_i64, x64::MOP_cvtsi2sdq_r) +DEFINE_MAPPING(abstract::MOP_cvt_f64_u64, x64::MOP_cvtsi2sdq_r) +DEFINE_MAPPING(abstract::MOP_cvt_f64_u32, x64::MOP_cvtsi2sdq_r) +DEFINE_MAPPING(abstract::MOP_cvt_f32_u64, x64::MOP_cvtsi2ssq_r) +DEFINE_MAPPING(abstract::MOP_cvt_f32_u32, x64::MOP_cvtsi2ssq_r) +DEFINE_MAPPING(abstract::MOP_cvt_f32_i64, x64::MOP_cvtsi2ssq_r) +DEFINE_MAPPING(abstract::MOP_cvt_f32_i32, x64::MOP_cvtsi2ssl_r) +DEFINE_MAPPING(abstract::MOP_cvt_f64_i64, x64::MOP_cvtsi2sdq_r) +DEFINE_MAPPING(abstract::MOP_cvt_f64_i32, x64::MOP_cvtsi2sdl_r) /* Floating CvtOp float2int */ -DEFINE_MAPPING(abstract::MOP_cvt_rf_u32, x64::MOP_cvttss2siq_r) -DEFINE_MAPPING(abstract::MOP_cvt_rf_u64, x64::MOP_cvttsd2siq_r) -DEFINE_MAPPING(abstract::MOP_cvt_rf_i32, x64::MOP_cvttss2sil_r) -DEFINE_MAPPING(abstract::MOP_cvt_rf_i64, x64::MOP_cvttsd2siq_r) +DEFINE_MAPPING(abstract::MOP_cvt_u32_f32, x64::MOP_cvttss2siq_r) +DEFINE_MAPPING(abstract::MOP_cvt_u64_f64, x64::MOP_cvttsd2siq_r) +DEFINE_MAPPING(abstract::MOP_cvt_i32_f32, x64::MOP_cvttss2sil_r) +DEFINE_MAPPING(abstract::MOP_cvt_i64_f64, x64::MOP_cvttsd2siq_r) +DEFINE_MAPPING(abstract::MOP_cvt_i32_f64, x64::MOP_cvttsd2sil_r) +DEFINE_MAPPING(abstract::MOP_cvt_i32_f32, x64::MOP_cvttss2sil_r) +DEFINE_MAPPING(abstract::MOP_cvt_u32_f64, x64::MOP_cvttsd2siq_r) +DEFINE_MAPPING(abstract::MOP_cvt_u32_f32, x64::MOP_cvttss2siq_r) /* Floating CvtOp float2float */ DEFINE_MAPPING(abstract::MOP_cvt_ff_64_32, x64::MOP_cvtss2sd_r) diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp index e30eb21967fbb0a877ae78fde24fa28393934533..b3aa50ac319595eb62a9cf041262043287d023a5 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/be/becommon.cpp @@ -612,7 +612,7 @@ std::pair BECommon::GetFieldOffset(MIRStructType &structType, Fiel uint64 fieldSizeBits = fieldTypeSize * kBitsPerByte; auto originAlign = GetTypeAlign(fieldTyIdx); auto fieldAlign = fieldAttr.IsPacked() ? 1 : std::min(originAlign, structPack); - uint64 fieldAlignBits = fieldAlign * kBitsPerByte; + uint64 fieldAlignBits = static_cast(fieldAlign * kBitsPerByte); CHECK_FATAL(fieldAlign != 0, "fieldAlign should not equal 0"); if (structType.GetKind() != kTypeUnion) { if (fieldType->GetKind() == kTypeBitField) { @@ -660,7 +660,7 @@ std::pair BECommon::GetFieldOffset(MIRStructType &structType, Fiel allocedSizeInBits = RoundUp(allocedSizeInBits, fieldAlignBits); } allocedSize = RoundUp(allocedSize, fieldAlign); - offset = (allocedSizeInBits / fieldAlignBits) * fieldAlign; + offset = static_cast((allocedSizeInBits / fieldAlignBits) * fieldAlign); leftOverBits = true; } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp index ff2e25ddfad77aed3bafcc72b5d87db749bd07a6..7343e64298bcb93a41736235503df5f053f24652 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/be/lower.cpp @@ -426,10 +426,10 @@ BaseNode *CGLowerer::LowerFarray(ArrayNode &array) if (constvalNode->GetConstVal()->GetKind() == kConstInt) { const MIRIntConst *pIntConst = static_cast(constvalNode->GetConstVal()); CHECK_FATAL(JAVALANG || !pIntConst->IsNegative(), "Array index should >= 0."); - uint64 eleOffset = pIntConst->GetExtValue() * eSize; + uint64 eleOffset = static_cast(pIntConst->GetExtValue() * eSize); if (farrayType->GetKind() == kTypeJArray) { - eleOffset += RTSupport::GetRTSupportInstance().GetArrayContentOffset(); + eleOffset += static_cast(RTSupport::GetRTSupportInstance().GetArrayContentOffset()); } BaseNode *baseNode = NodeConvert(array.GetPrimType(), *array.GetBase()); @@ -454,7 +454,7 @@ BaseNode *CGLowerer::LowerFarray(ArrayNode &array) if ((farrayType->GetKind() == kTypeJArray) && (resNode->GetOpCode() == OP_constval)) { ConstvalNode *idxNode = static_cast(resNode); - uint64 idx = safe_cast(idxNode->GetConstVal())->GetExtValue(); + uint64 idx = static_cast(safe_cast(idxNode->GetConstVal())->GetExtValue()); MIRIntConst *eConst = GlobalTables::GetIntConstTable().GetOrCreateIntConst(idx * eSize, arrayType); rMul = mirModule.CurFuncCodeMemPool()->New(eConst); rMul->SetPrimType(array.GetPrimType()); @@ -506,7 +506,7 @@ BaseNode *CGLowerer::LowerArrayDim(ArrayNode &array, int32 dim) item = NodeConvert(array.GetPrimType(), *array.GetIndex(static_cast(static_cast(i)))); int64 offsetSize = 1; for (int32 j = i + 1; j < dim; ++j) { - offsetSize *= arrayType->GetSizeArrayItem(static_cast(j)); + offsetSize *= static_cast(arrayType->GetSizeArrayItem(static_cast(j))); } MIRIntConst *offsetCst = mirModule.CurFuncCodeMemPool()->New( offsetSize, *GlobalTables::GetTypeTable().GetTypeFromTyIdx(array.GetPrimType())); @@ -577,7 +577,7 @@ BaseNode *CGLowerer::LowerArray(ArrayNode &array, const BaseNode &parent) if (resNode->GetOpCode() == OP_constval) { /* index is a constant, we can calculate the offset now */ ConstvalNode *idxNode = static_cast(resNode); - uint64 idx = safe_cast(idxNode->GetConstVal())->GetExtValue(); + uint64 idx = static_cast(safe_cast(idxNode->GetConstVal())->GetExtValue()); MIRIntConst *eConst = GlobalTables::GetIntConstTable().GetOrCreateIntConst(idx * eSize, arrayTypes); rMul = mirModule.CurFuncCodeMemPool()->New(eConst); rMul->SetPrimType(array.GetPrimType()); @@ -671,7 +671,7 @@ BaseNode *CGLowerer::LowerCArray(ArrayNode &array) uint64 indexVal = 0; if (index->op == OP_constval) { ConstvalNode *constNode = static_cast(index); - indexVal = (static_cast(constNode->GetConstVal()))->GetExtValue(); + indexVal = static_cast((static_cast(constNode->GetConstVal()))->GetExtValue()); isConst = true; MIRIntConst *newConstNode = mirModule.GetMemPool()->New( indexVal * mpyDim, *GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(array.GetPrimType()))); @@ -733,7 +733,7 @@ BaseNode *CGLowerer::LowerCArray(ArrayNode &array) if (resNode->op == OP_constval) { // index is a constant, we can calculate the offset now ConstvalNode *idxNode = static_cast(resNode); - uint64 idx = static_cast(idxNode->GetConstVal())->GetExtValue(); + uint64 idx = static_cast(static_cast(idxNode->GetConstVal())->GetExtValue()); MIRIntConst *econst = mirModule.GetMemPool()->New( idx * esize, *GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(array.GetPrimType()))); rMul = mirModule.CurFuncCodeMemPool()->New(econst); @@ -782,7 +782,7 @@ StmtNode *CGLowerer::WriteBitField(const std::pair &byteBitOffsets } // if space not enough in the unit with size of primType, we would make an extra assignment from next bound auto bitsRemained = (bitOffset + bitSize) - primTypeBitSize; - auto bitsExtracted = primTypeBitSize - bitOffset; + auto bitsExtracted = primTypeBitSize - static_cast(bitOffset); if (CGOptions::IsBigEndian()) { bitOffset = 0; } @@ -2240,6 +2240,7 @@ void CGLowerer::LowerEntry(MIRFunction &func) retSt->SetSKind(kStVar); std::string retName(".return."); MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(func.GetStIdx().Idx()); + DEBUG_ASSERT(funcSt != nullptr, "null ptr check"); retName += funcSt->GetName(); retSt->SetNameStrIdx(retName); MIRType *pointType = beCommon.BeGetOrCreatePointerType(*func.GetReturnType()); @@ -2737,7 +2738,7 @@ BaseNode *CGLowerer::LowerExpr(BaseNode &parent, BaseNode &expr, BlockNode &blkN case OP_sizeoftype: { CHECK(static_cast(expr).GetTyIdx() < beCommon.GetSizeOfTypeSizeTable(), "index out of range in CGLowerer::LowerExpr"); - int64 typeSize = beCommon.GetTypeSize(static_cast(expr).GetTyIdx()); + int64 typeSize = static_cast(beCommon.GetTypeSize(static_cast(expr).GetTyIdx())); return mirModule.GetMIRBuilder()->CreateIntConst(typeSize, PTY_u32); } @@ -2828,6 +2829,7 @@ BaseNode *CGLowerer::LowerDreadToThreadLocal(BaseNode &expr, const BlockNode &bl return result; } MIRSymbol *symbol = GlobalTables::GetGsymTable().GetSymbolFromStidx(stIdx.Idx()); + CHECK_FATAL(symbol != nullptr, "symbol should not be nullptr"); if (symbol->IsThreadLocal()) { // iread <* u32> 0 (regread u64 %addr) diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/be/switch_lowerer.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/be/switch_lowerer.cpp index c0fa64ca31d937c4183a36d621b77c362d3a5eed..70b63738e00a0af83bc94fa239eb4d9c53bf9c65 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/be/switch_lowerer.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/be/switch_lowerer.cpp @@ -118,7 +118,7 @@ RangeGotoNode *SwitchLowerer::BuildRangeGotoNode(int32 startIdx, int32 endIdx) */ while ((stmt->GetCasePair(i).first != (lastCaseTag + 1)) && (stmt->GetCasePair(i).first != lastCaseTag)) { /* fill in a gap in the case tags */ - curTag = (++lastCaseTag) - node->GetTagOffset(); + curTag = static_cast((++lastCaseTag) - node->GetTagOffset()); if (stmt->GetDefaultLabel() != 0) { node->AddRangeGoto(curTag, stmt->GetDefaultLabel()); } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp index 75fd0ede9c05bb37d9531e651dd9f5085aa84b39..69d78afe64a9dc14be8e4a4721024f309914b05e 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_abi.cpp @@ -155,7 +155,7 @@ PrimType IsVectorArrayType(MIRType *ty, uint32 &arraySize) MIRArrayType *arrayTy = static_cast(fieldTy); MIRType *arrayElemTy = arrayTy->GetElemType(); arraySize = arrayTy->GetSizeArrayItem(0); - if (arrayTy->GetDim() == k1BitSize && arraySize <= static_cast(k4BitSize) && + if (arrayTy->GetDim() == k1BitSize && arraySize <= static_cast(k4BitSize) && IsPrimitiveVector(arrayElemTy->GetPrimType())) { return arrayElemTy->GetPrimType(); } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp index cc1ebc1fd327fc825a42673234aa79014fc35ce0..93e9693e31b2ab27ca1ab57d792e3cbbcadb9fd5 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_cgfunc.cpp @@ -956,7 +956,7 @@ bool AArch64CGFunc::CheckIfSplitOffsetWithAdd(const MemOperand &memOpnd, uint32 int32 q0 = opndVal / maxPimm; int32 addend = q0 * maxPimm; int32 r0 = opndVal - addend; - int32 alignment = memOpnd.GetImmediateOffsetAlignment(bitLen); + int32 alignment = static_cast(memOpnd.GetImmediateOffsetAlignment(bitLen)); int32 r1 = static_cast(r0) & ((1u << static_cast(alignment)) - 1); addend = addend + r1; return (addend > 0); @@ -2258,7 +2258,7 @@ void AArch64CGFunc::SelectBlkassignoff(BlkassignoffNode &bNode, Operand *src) if (offset < 0) { /* length of ALL stack based args for this call, this location is where the next large agg resides, its addr will then be passed */ - offset = LmbcFindTotalStkUsed(parmList) + LmbcTotalRegsUsed(); + offset = static_cast(LmbcFindTotalStkUsed(parmList) + LmbcTotalRegsUsed()); } SetLmbcTotalStkUsed(offset + bNode.blockSize); /* next use */ SetLmbcArgInfo(regResult, PTY_i64, 0, 1); /* 1 reg for ptr */ @@ -2811,7 +2811,7 @@ RegOperand *AArch64CGFunc::LmbcStructReturnLoad(int32 offset) Operand *AArch64CGFunc::SelectIreadfpoff(const BaseNode &parent, IreadFPoffNode &ireadoff) { - uint32 offset = ireadoff.GetOffset(); + uint32 offset = static_cast(ireadoff.GetOffset()); PrimType primType = ireadoff.GetPrimType(); uint32 bytelen = GetPrimTypeSize(primType); uint32 bitlen = bytelen * kBitsPerByte; @@ -3045,32 +3045,6 @@ Operand *AArch64CGFunc::SelectIntConst(const MIRIntConst &intConst) false); } -template -Operand *SelectLiteral(T *c, MIRFunction *func, uint32 labelIdx, AArch64CGFunc *cgFunc) -{ - MIRSymbol *st = func->GetSymTab()->CreateSymbol(kScopeLocal); - std::string lblStr(".LB_"); - MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(func->GetStIdx().Idx()); - std::string funcName = funcSt->GetName(); - lblStr += funcName; - lblStr += std::to_string(labelIdx); - st->SetNameStrIdx(lblStr); - st->SetStorageClass(kScPstatic); - st->SetSKind(kStConst); - st->SetKonst(c); - cgFunc->SetLocalSymLabelIndex(*st, labelIdx); - PrimType primType = c->GetType().GetPrimType(); - st->SetTyIdx(TyIdx(primType)); - uint32 typeBitSize = GetPrimTypeBitSize(primType); - - if ((T::GetPrimType() == PTY_f32 || T::GetPrimType() == PTY_f64)) { - return static_cast(&cgFunc->GetOrCreateMemOpnd(*st, 0, typeBitSize)); - } else { - CHECK_FATAL(false, "Unsupported const type"); - } - return nullptr; -} - Operand *AArch64CGFunc::HandleFmovImm(PrimType stype, int64 val, MIRConst &mirConst, const BaseNode &parent) { Operand *result; @@ -3089,12 +3063,6 @@ Operand *AArch64CGFunc::HandleFmovImm(PrimType stype, int64 val, MIRConst &mirCo MOperator mopFmov = (is64Bits ? MOP_xdfmovri : MOP_wsfmovri); GetCurBB()->AppendInsn(GetInsnBuilder()->BuildInsn(mopFmov, *result, *newOpnd0)); } else { - if (is64Bits) { // For DoubleConst, use ldr .literal - uint32 labelIdxTmp = GetLabelIdx(); - result = SelectLiteral(static_cast(&mirConst), &GetFunction(), labelIdxTmp++, this); - SetLabelIdx(labelIdxTmp); - return result; - } Operand *newOpnd0 = &CreateImmOperand(val, GetPrimTypeSize(stype) * kBitsPerByte, false); PrimType itype = (stype == PTY_f32) ? PTY_i32 : PTY_i64; RegOperand ®Opnd = LoadIntoRegister(*newOpnd0, itype); @@ -3857,7 +3825,7 @@ void AArch64CGFunc::SelectMpy(Operand &resOpnd, Operand &opnd0, Operand &opnd1, return; } else if (immValue > 2) { // immValue should larger than 2 - uint32 zeroNum = __builtin_ffsll(immValue) - 1; + uint32 zeroNum = static_cast(__builtin_ffsll(immValue) - 1); int64 headVal = static_cast(immValue) >> zeroNum; /* * if (headVal - 1) & (headVal - 2) == 0, that is (immVal >> zeroNum) - 1 == 1 << n @@ -5714,6 +5682,7 @@ void AArch64CGFunc::SelectRangeGoto(RangeGotoNode &rangeGotoNode, Operand &srcOp lblSt->SetKonst(arrayConst); std::string lblStr(".LB_"); MIRSymbol *funcSt = GlobalTables::GetGsymTable().GetSymbolFromStidx(GetFunction().GetStIdx().Idx()); + CHECK_FATAL(funcSt != nullptr, "funcSt should not be nullptr"); uint32 labelIdxTmp = GetLabelIdx(); lblStr += funcSt->GetName(); lblStr += std::to_string(labelIdxTmp++); @@ -6814,9 +6783,9 @@ bool AArch64CGFunc::GenRetCleanup(const IntrinsiccallNode *cleanupNode, bool for if (minByteOffset < INT_MAX) { int32 refLocBase = memLayout->GetRefLocBaseLoc(); uint32 refNum = memLayout->GetSizeOfRefLocals() / kAarch64OffsetAlign; - CHECK_FATAL((refLocBase + (refNum - 1) * kAarch64IntregBytelen) < std::numeric_limits::max(), - "out of range"); - int32 refLocEnd = refLocBase + (refNum - 1) * kAarch64IntregBytelen; + CHECK_FATAL((static_cast(refLocBase) + (refNum - 1) * kAarch64IntregBytelen) < + static_cast(std::numeric_limits::max()), "out of range"); + int32 refLocEnd = refLocBase + static_cast((refNum - 1) * kAarch64IntregBytelen); int32 realMin = minByteOffset < refLocBase ? refLocBase : minByteOffset; int32 realMax = maxByteOffset > refLocEnd ? refLocEnd : maxByteOffset; if (forEA) { @@ -6872,7 +6841,7 @@ bool AArch64CGFunc::GenRetCleanup(const IntrinsiccallNode *cleanupNode, bool for srcOpnds->PushOpnd(parmRegOpnd1); SelectCopy(parmRegOpnd1, PTY_a64, vReg0, PTY_a64); - uint32 realRefNum = (realMax - realMin) / kAarch64OffsetAlign + 1; + uint32 realRefNum = static_cast((realMax - realMin) / kAarch64OffsetAlign + 1); ImmOperand &countOpnd = CreateImmOperand(realRefNum, k64BitSize, true); @@ -9612,7 +9581,7 @@ void AArch64CGFunc::SelectMPLProfCounterInc(const IntrinsiccallNode &intrnNode) DEBUG_ASSERT(mirConst != nullptr, "nullptr check"); CHECK_FATAL(mirConst->GetKind() == kConstInt, "expect MIRIntConst type"); MIRIntConst *mirIntConst = safe_cast(mirConst); - int64 offset = GetPrimTypeSize(PTY_u64) * mirIntConst->GetExtValue(); + int64 offset = static_cast(GetPrimTypeSize(PTY_u64)) * mirIntConst->GetExtValue(); if (!CGOptions::IsQuiet()) { maple::LogInfo::MapleLogger(kLlInfo) << "At counter table offset: " << offset << std::endl; @@ -9645,7 +9614,7 @@ void AArch64CGFunc::SelectMPLProfCounterInc(const IntrinsiccallNode &intrnNode) DEBUG_ASSERT(mirConst != nullptr, "nullptr check"); CHECK_FATAL(mirConst->GetKind() == kConstInt, "expect MIRIntConst type"); MIRIntConst *mirIntConst = safe_cast(mirConst); - int64 idx = GetPrimTypeSize(PTY_u32) * mirIntConst->GetExtValue(); + int64 idx = static_cast(GetPrimTypeSize(PTY_u32)) * mirIntConst->GetExtValue(); if (!CGOptions::IsQuiet()) { maple::LogInfo::MapleLogger(kLlErr) << "Id index " << idx << std::endl; } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_ebo.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_ebo.cpp index 434aa3e882be425042fbc1ef65cb1c60c2fa10e7..25efd4ccd7d2420b4e778c957a3e447c8ba80a12 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_ebo.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_ebo.cpp @@ -467,7 +467,7 @@ int32 AArch64Ebo::GetOffsetVal(const MemOperand &memOpnd) const val += static_cast(offset->GetOffsetValue()); if (offset->IsSymOffset() || offset->IsSymAndImmOffset()) { - val += offset->GetSymbol()->GetStIdx().Idx(); + val += static_cast(offset->GetSymbol()->GetStIdx().Idx()); } } return val; diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_insn.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_insn.cpp index d44299b49b0a87b1811ade3f949e65a244a4fd4a..6c9abaf0ac12789d25f8ad22f33b485a2e243dd4 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_insn.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_insn.cpp @@ -55,7 +55,7 @@ void A64OpndEmitVisitor::Visit(maplebe::RegOperand *v) EmitVectorOperand(*v); } else { /* FP reg cannot be reffield. 8~0, 16~1, 32~2, 64~3. 8 is 1000b, has 3 zero. */ - uint32 regSet = __builtin_ctz(static_cast(opndSize)) - 3; + uint32 regSet = static_cast(__builtin_ctz(static_cast(opndSize)) - 3); (void)emitter.Emit(AArch64CG::intRegNames[regSet][regNO]); } break; diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_obj_emitter.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_obj_emitter.cpp index c6db53578b7230bb7e480f806e4210f5ac7b2128..7cc4fa7e84ff90fe73d50467f4c6e8c5432123e1 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_obj_emitter.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_obj_emitter.cpp @@ -174,7 +174,7 @@ void AArch64ObjEmitter::HandleTextSectionFixup() } case kAArch64LdrPCRelLo12: case kAArch64AddPCRelLo12: { - int32 relOffset = fixup->GetRelOffset(); + int32 relOffset = static_cast(fixup->GetRelOffset()); uint32 offset = fixup->GetOffset(); uint64 type = R_AARCH64_ADD_ABS_LO12_NC; int64 rodataSecSymIdx = ~rodataSection->GetIndex() + 1; @@ -1380,7 +1380,7 @@ uint32 AArch64ObjEmitter::GenLoadPairInsn(const Insn &insn) const divisor = k4ByteSize; } uint32 imm7Mask = 0x7f; - opnd |= (static_cast(offsetValue / divisor) & imm7Mask) << kShiftFifteen; + opnd |= (static_cast((offsetValue / divisor) & imm7Mask) << kShiftFifteen); uint32 specialOpCode = 0; if (memOpnd.IsPostIndexed()) { @@ -1459,7 +1459,7 @@ uint32 AArch64ObjEmitter::GenLoadPairFloatInsn(const Insn &insn) const divisor = k4ByteSize; } uint32 imm7Mask = 0x7f; - opnd |= (static_cast(offsetValue / divisor) & imm7Mask) << kShiftFifteen; + opnd |= (static_cast(static_cast(offsetValue) / divisor) & imm7Mask) << kShiftFifteen; uint32 specialOpCode = 0; if (memOpnd.IsPostIndexed()) { @@ -1496,7 +1496,7 @@ uint32 AArch64ObjEmitter::GenStorePairFloatInsn(const Insn &insn) const divisor = k4ByteSize; } uint32 imm7Mask = 0x7f; - opnd |= (static_cast(offsetValue / divisor) & imm7Mask) << kShiftFifteen; + opnd |= (static_cast(static_cast(offsetValue) / divisor) & imm7Mask) << kShiftFifteen; uint32 specialOpCode = 0; if (memOpnd.IsPostIndexed()) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp index 1f14e65f270a15e8450340466db39bfbce2cb143..e5f11bad4ad049b0c5bdba7da1f02f38836e993d 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_proepilog.cpp @@ -643,8 +643,10 @@ void AArch64GenProEpilog::GeneratePushRegs() memLayout->GetSizeOfLocals()); } else { offset = (static_cast(memLayout->RealStackFrameSize() - - (aarchCGFunc.SizeOfCalleeSaved() - (kDivide2 * kAarch64IntregBytelen))) - /* for FP/LR */ - memLayout->SizeOfArgsToStackPass() - cgFunc.GetFunction().GetFrameReseverdSlot()); + (static_cast(aarchCGFunc.SizeOfCalleeSaved()) - + (kDivide2 * static_cast(kAarch64IntregBytelen)))) - /* for FP/LR */ + static_cast(memLayout->SizeOfArgsToStackPass()) - + static_cast(cgFunc.GetFunction().GetFrameReseverdSlot())); } if (cgFunc.GetCG()->IsStackProtectorStrong() || cgFunc.GetCG()->IsStackProtectorAll()) { @@ -706,7 +708,8 @@ void AArch64GenProEpilog::GeneratePushRegs() int64 fpToCurSpDistance = (cgFunc.GetMemlayout()->SizeOfArgsToStackPass() + cgFunc.GetFunction().GetFrameReseverdSlot()); int32 fp2PrevFrameSPDelta = - static_cast(cgFunc.GetMemlayout())->RealStackFrameSize() - fpToCurSpDistance; + static_cast(static_cast(cgFunc.GetMemlayout())->RealStackFrameSize()) - + fpToCurSpDistance; emitMemoryManager.funcFpSPDeltaSaver(emitMemoryManager.codeSpace, cgFunc.GetName(), fp2PrevFrameSPDelta); } } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_prop.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_prop.cpp index 80e7824561f4728e64087aa4ec4f93035c8646d1..4381fd03aec363dc70df80fc4e3551a539de1fa9 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_prop.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_prop.cpp @@ -1630,6 +1630,7 @@ bool CopyRegProp::IsValidCopyProp(const RegOperand &dstReg, const RegOperand &sr srcll = regll->GetLiveInterval(srcRegNO); static_cast(regll)->CheckInterference(*dstll, *srcll); BB *useBB = useInsn->GetBB(); + DEBUG_ASSERT(useBB != nullptr, "useBB is null"); if (dstll->IsConflictWith(srcRegNO) && /* support override value when the version is not transphi */ (((useBB->IsInPhiDef(srcRegNO) || useBB->IsInPhiList(srcRegNO)) && useBB->HasCriticalEdge()) || diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reg_info.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reg_info.cpp index 96a0bce9dc52cb2f890a46a1b7ee7732ddde6c89..c5a38217f85b9ff67091436421f2e61455511c56 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reg_info.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_reg_info.cpp @@ -24,7 +24,7 @@ void AArch64RegInfo::Init() { for (regno_t regNO = kRinvalid; regNO < kMaxRegNum; ++regNO) { /* when yieldpoint is enabled, x19 is reserved. */ - if (IsYieldPointReg(regNO)) { + if (IsYieldPointReg(regNO) || IsReservedReg(regNO)) { continue; } if (regNO == R29 && GetCurrFunction()->UseFP()) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_validbit_opt.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_validbit_opt.cpp index 2c20bcc67f11e911269ee320a4f65f1c08a6974c..f8505b225334584a5b921c3da6837d3f90349de2 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_validbit_opt.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/aarch64/aarch64_validbit_opt.cpp @@ -94,7 +94,7 @@ void AArch64ValidBitOpt::SetValidBits(Insn &insn) uint32 shiftBits = static_cast(static_cast(opnd).GetValue()); auto &dstOpnd = static_cast(insn.GetOperand(kInsnFirstOpnd)); auto &srcOpnd = static_cast(insn.GetOperand(kInsnSecondOpnd)); - if ((static_cast(srcOpnd.GetValidBitsNum()) - shiftBits) <= 0) { + if ((static_cast(srcOpnd.GetValidBitsNum()) - shiftBits) <= 0) { dstOpnd.SetValidBitsNum(k1BitSize); } else { dstOpnd.SetValidBitsNum(srcOpnd.GetValidBitsNum() - shiftBits); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg.cpp index 77ddb48d79f881dc4a56a698284297832db5c394..9d9baf4c7c599cb4d03816c58174dda6cb856377 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/cg.cpp @@ -239,7 +239,7 @@ static void AppendReferenceOffsets64(const BECommon &beCommon, MIRStructType &cu auto fieldSize = beCommon.GetTypeSize(fieldTypeIdx); auto fieldAlign = beCommon.GetTypeAlign(fieldTypeIdx); int64 myOffset = static_cast(RoundUp(curOffset, fieldAlign)); - int64 nextOffset = myOffset + fieldSize; + int64 nextOffset = myOffset + static_cast(fieldSize); if (!CGOptions::IsQuiet()) { LogInfo::MapleLogger() << " field: " << fieldName << "\n"; diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/emit.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/emit.cpp index 4378582156c94b297db4a95559fda05468838960..0b887cdfc9d26d8b5e236d41e5deb8a412098c83 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/emit.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/emit.cpp @@ -595,7 +595,7 @@ void Emitter::EmitBitFieldConstant(StructEmitInfo &structEmitInfo, MIRConst &mir structEmitInfo.GetCombineBitFieldValue()); } if (CGOptions::IsBigEndian()) { - uint64 beValue = fieldValue.GetExtValue(); + uint64 beValue = static_cast(fieldValue.GetExtValue()); if (fieldValue.IsNegative()) { beValue = beValue - ((beValue >> fieldSize) << fieldSize); } @@ -1333,6 +1333,7 @@ MIRAddroffuncConst *Emitter::GetAddroffuncConst(const MIRSymbol &mirSymbol, MIRA /* point addr data. */ MIRAddrofConst *pAddr = safe_cast(pAddrConst); MIRSymbol *symAddrSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(pAddr->GetSymbolIndex().Idx()); + DEBUG_ASSERT(symAddrSym != nullptr, "null ptr check"); MIRAggConst *methodAddrAggConst = safe_cast(symAddrSym->GetKonst()); MIRAggConst *addrAggConst = safe_cast(methodAddrAggConst->GetConstVecItem(0)); MIRConst *funcAddrConst = addrAggConst->GetConstVecItem(0); @@ -1345,9 +1346,10 @@ MIRAddroffuncConst *Emitter::GetAddroffuncConst(const MIRSymbol &mirSymbol, MIRA namemangler::kMuidFuncDefTabPrefixStr + cg->GetMIRModule()->GetFileNameAsPostfix(); MIRSymbol *funDefTabSy = GlobalTables::GetGsymTable().GetSymbolFromStrIdx( GlobalTables::GetStrTable().GetStrIdxFromName(funcDefTabName)); + DEBUG_ASSERT(funDefTabSy != nullptr, "null ptr check"); MIRAggConst &funDefTabAggConst = static_cast(*funDefTabSy->GetKonst()); MIRIntConst *funcAddrIndexConst = safe_cast(funcAddrConst); - uint64 indexDefTab = funcAddrIndexConst->GetExtValue(); + uint64 indexDefTab = static_cast(funcAddrIndexConst->GetExtValue()); MIRAggConst *defTabAggConst = safe_cast(funDefTabAggConst.GetConstVecItem(indexDefTab)); MIRConst *funcConst = defTabAggConst->GetConstVecItem(0); if (funcConst->GetKind() == kConstAddrofFunc) { @@ -1363,7 +1365,7 @@ MIRAddroffuncConst *Emitter::GetAddroffuncConst(const MIRSymbol &mirSymbol, MIRA int64 Emitter::GetFieldOffsetValue(const std::string &className, const MIRIntConst &intConst, const std::map &strIdx2Type) { - uint64 idx = intConst.GetExtValue(); + uint64 idx = static_cast(intConst.GetExtValue()); bool isDefTabIndex = idx & 0x1; int64 fieldIdx = idx >> 1; if (isDefTabIndex) { @@ -1592,7 +1594,7 @@ void Emitter::EmitIntConst(const MIRSymbol &mirSymbol, MIRAggConst &aggConst, ui std::string widthFlag = ".quad"; #endif /* USE_32BIT_REF */ int64 fieldOffset = GetFieldOffsetValue(typeName, *intConst, strIdx2Type); - uint64 fieldIdx = intConst->GetExtValue(); + uint64 fieldIdx = static_cast(intConst->GetExtValue()); bool isDefTabIndex = fieldIdx & 0x1; if (isDefTabIndex) { /* it's def table index. */ @@ -1800,7 +1802,7 @@ void Emitter::EmitArrayConstant(MIRConst &mirConst) DEBUG_ASSERT(false, "should not run here"); } } - int64 iNum = (arrayType.GetSizeArrayItem(0) > 0) ? (static_cast(arrayType.GetSizeArrayItem(0))) - uNum : 0; + int64 iNum = (arrayType.GetSizeArrayItem(0) > 0) ? (static_cast(arrayType.GetSizeArrayItem(0)) - uNum) : 0; if (iNum > 0) { if (!cg->GetMIRModule()->IsCModule()) { CHECK_FATAL(!Globals::GetInstance()->GetBECommon()->IsEmptyOfTypeSizeTable(), "container empty check"); @@ -3053,6 +3055,7 @@ void Emitter::EmitMuidTable(const std::vector &vec, const std::map< MIRAddrofConst *symAddr = safe_cast(mirConst); CHECK_FATAL(symAddr != nullptr, "call static_cast failed in EmitMuidTable"); MIRSymbol *symAddrSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(symAddr->GetSymbolIndex().Idx()); + DEBUG_ASSERT(symAddrSym != nullptr, "null ptr check"); if (isConstString) { EmitAddressString(symAddrSym->GetName() + " - . + "); Emit(kDataRefIsOffset); @@ -3292,7 +3295,6 @@ void Emitter::EmitDIFormSpecification(unsigned int dwform) void Emitter::EmitDIAttrValue(DBGDie *die, DBGDieAttr *attr, DwAt attrName, DwTag tagName, DebugInfo *di) { MapleVector &attrvec = die->GetAttrVec(); - switch (attr->GetDwForm()) { case DW_FORM_string: { const std::string &name = GlobalTables::GetStrTable().GetStringFromStrIdx(attr->GetId()); @@ -3567,6 +3569,7 @@ void Emitter::EmitDIDebugInfoSection(DebugInfo *mirdi) for (size_t i = 0; i < diae->GetAttrPairs().size(); i += k2ByteSize) { DBGDieAttr *attr = LFindAttribute(die->GetAttrVec(), DwAt(apl[i])); + DEBUG_ASSERT(attr != nullptr, "null ptr check"); if (!LShouldEmit(unsigned(apl[i + 1]))) { continue; } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/isel.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/isel.cpp index b739fd2b09eb758751312c5ed6566e302054b518..0ecf1851490e8267d314efbe5563fffe6f9d52b2 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/isel.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/isel.cpp @@ -743,7 +743,7 @@ MirTypeInfo MPISel::GetMirTypeInfoFormFieldIdAndMirType(FieldID fieldId, MIRType DEBUG_ASSERT((mirType->IsMIRStructType() || mirType->IsMIRUnionType()), "non-structure"); MIRStructType *structType = static_cast(mirType); mirType = structType->GetFieldType(fieldId); - mirTypeInfo.offset = static_cast(cgFunc->GetBecommon().GetFieldOffset(*structType, fieldId).first); + mirTypeInfo.offset = static_cast(cgFunc->GetBecommon().GetFieldOffset(*structType, fieldId).first); } mirTypeInfo.primType = mirType->GetPrimType(); // aggSize for AggType @@ -1091,30 +1091,24 @@ void MPISel::SelectCvtFloat2Int(RegOperand &resOpnd, Operand &opnd0, PrimType to { uint32 toSize = GetPrimTypeBitSize(toType); bool isSigned = !IsPrimitiveUnsigned(toType); - PrimType newToType = toType; - // cvt f64/32 -> u16 / u8 -> cvt f u32 + cvt u32 -> u8 - if (toSize < k32BitSize) { - newToType = isSigned ? PTY_i32 : PTY_u32; - } - uint32 newToSize = GetPrimTypeBitSize(newToType); - RegOperand &tmpFloatOpnd = cgFunc->GetOpndBuilder()->CreateVReg(newToSize, kRegTyFloat); - SelectFloatCvt(tmpFloatOpnd, opnd0, newToType, fromType); + + // Due to fp precision, should use one insn to perform cvt. + RegOperand ®Opnd0 = SelectCopy2Reg(opnd0, fromType); MOperator mOp = abstract::MOP_undef; - if (newToSize == k32BitSize) { - mOp = isSigned ? abstract::MOP_cvt_rf_i32 : abstract::MOP_cvt_rf_u32; - } else if (newToSize == k64BitSize) { - mOp = isSigned ? abstract::MOP_cvt_rf_i64 : abstract::MOP_cvt_rf_u64; - } else { - CHECK_FATAL(false, "niy"); + switch (fromType) { + case PTY_f64: + mOp = (toSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_i32_f64 : abstract::MOP_cvt_u32_f64) : + ((isSigned) ? abstract::MOP_cvt_i64_f64 : abstract::MOP_cvt_u64_f64); + break; + case PTY_f32: + mOp = (toSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_i32_f32 : abstract::MOP_cvt_u32_f32) : + ((isSigned) ? abstract::MOP_cvt_i64_f32 : abstract::MOP_cvt_u64_f32); + break; + default: + CHECK_FATAL(false, "NYI"); } Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp)); - if (toSize == newToSize) { - (void)insn.AddOpndChain(resOpnd).AddOpndChain(tmpFloatOpnd); - } else if (toSize < newToSize) { - RegOperand &tmpIntOpnd = cgFunc->GetOpndBuilder()->CreateVReg(newToSize, kRegTyFloat); - (void)insn.AddOpndChain(tmpIntOpnd).AddOpndChain(tmpFloatOpnd); - SelectIntCvt(resOpnd, tmpIntOpnd, toType, newToType); - } + (void)insn.AddOpndChain(resOpnd).AddOpndChain(regOpnd0); cgFunc->GetCurBB()->AppendInsn(insn); } @@ -1123,23 +1117,22 @@ void MPISel::SelectCvtInt2Float(RegOperand &resOpnd, Operand &opnd0, PrimType to uint32 fromSize = GetPrimTypeBitSize(fromType); bool isSigned = !IsPrimitiveUnsigned(fromType); MOperator mOp = abstract::MOP_undef; - PrimType newFromType = PTY_begin; - if (fromSize == k32BitSize) { - mOp = isSigned ? abstract::MOP_cvt_fr_i32 : abstract::MOP_cvt_fr_u32; - newFromType = PTY_f64; - } else if (fromSize == k64BitSize) { - mOp = isSigned ? abstract::MOP_cvt_fr_i64 : abstract::MOP_cvt_fr_u64; - newFromType = PTY_f64; - } else { - CHECK_FATAL(false, "niy"); + switch (toType) { + case PTY_f64: + mOp = (fromSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_f64_i32 : abstract::MOP_cvt_f64_u32) : + ((isSigned) ? abstract::MOP_cvt_f64_i64 : abstract::MOP_cvt_f64_u64); + break; + case PTY_f32: + mOp = (fromSize <= k32BitSize) ? ((isSigned) ? abstract::MOP_cvt_f32_i32 : abstract::MOP_cvt_f32_u32) : + ((isSigned) ? abstract::MOP_cvt_f32_i64 : abstract::MOP_cvt_f32_u64); + break; + default: + CHECK_FATAL(false, "NYI"); } RegOperand ®Opnd0 = SelectCopy2Reg(opnd0, fromType); - RegOperand &tmpFloatOpnd = - cgFunc->GetOpndBuilder()->CreateVReg(GetPrimTypeBitSize(newFromType), cgFunc->GetRegTyFromPrimTy(newFromType)); Insn &insn = cgFunc->GetInsnBuilder()->BuildInsn(mOp, InsnDesc::GetAbstractId(mOp)); - (void)insn.AddOpndChain(tmpFloatOpnd).AddOpndChain(regOpnd0); + (void)insn.AddOpndChain(resOpnd).AddOpndChain(regOpnd0); cgFunc->GetCurBB()->AppendInsn(insn); - SelectFloatCvt(resOpnd, tmpFloatOpnd, toType, newFromType); } void MPISel::SelectIntCvt(RegOperand &resOpnd, Operand &opnd0, PrimType toType, PrimType fromType) diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/live.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/live.cpp index 4e743f271f0acf99c37817f8dbc9f3ef1d348c5e..dc7413a867f93e4dc4637d97c1fb22019da4c93b 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/live.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/live.cpp @@ -101,11 +101,9 @@ bool LiveAnalysis::GenerateLiveIn(BB &bb) SparseDataInfo *LiveAnalysis::GenerateLiveInByDefUse(SparseDataInfo &liveOut, SparseDataInfo &use, SparseDataInfo &def) { - const uint32 maxRegCount = - cgFunc->GetSSAvRegCount() > cgFunc->GetMaxVReg() ? cgFunc->GetSSAvRegCount() : cgFunc->GetMaxVReg(); - SparseDataInfo *liveIn = memPool->New(maxRegCount, alloc); - liveIn = &use; - SparseDataInfo *tmpLiveOut = memPool->New(liveOut, alloc); + SparseDataInfo *liveIn = &use; + LocalMapleAllocator allocator(cgFunc->GetStackMemPool()); + SparseDataInfo *tmpLiveOut = memPool->New(liveOut, allocator); if (!liveOut.NoneBit()) { tmpLiveOut->Difference(def); liveIn->OrBits(*tmpLiveOut); diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/obj_emit.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/obj_emit.cpp index 67b271dda255402ca60da4cc0c06ef62170386ea..88a74d9a60f3a90c601600b523003d708e8af56f 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/obj_emit.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/obj_emit.cpp @@ -33,12 +33,13 @@ void ObjEmitter::EmitFuncBinaryCode(ObjFuncEmitInfo &objFuncEmitInfo) CGFunc &cgFunc = objFuncEmitInfo.GetCGFunc(); objFuncEmitInfo.SetFuncName(cgFunc.GetName()); - int labelSize = cgFunc.GetLab2BBMap().size() + cgFunc.GetLabelAndValueMap().size() + 1; + int labelSize = static_cast(cgFunc.GetLab2BBMap().size()) + + static_cast(cgFunc.GetLabelAndValueMap().size()) + 1; std::vector label2Offset(labelSize, 0xFFFFFFFFULL); EmitInstructions(objFuncEmitInfo, label2Offset); objFuncEmitInfo.UpdateMethodCodeSize(); - int symbolSize = cgFunc.GetLabelIdx() + 1; + int symbolSize = static_cast(cgFunc.GetLabelIdx() + 1); std::vector symbol2Offset(symbolSize, 0xFFFFFFFFULL); EmitFunctionSymbolTable(objFuncEmitInfo, symbol2Offset); EmitSwitchTable(objFuncEmitInfo, symbol2Offset); @@ -221,6 +222,7 @@ void ObjEmitter::EmitMIRAddrofConstCommon(EmitInfo &emitInfo, uint64 specialOffs { MIRAddrofConst &symAddr = static_cast(emitInfo.elemConst); MIRSymbol *symAddrSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(symAddr.GetSymbolIndex().Idx()); + DEBUG_ASSERT(symAddrSym != nullptr, "null ptr check"); const std::string &symAddrName = symAddrSym->GetName(); LabelFixup labelFixup(symAddrName, emitInfo.offset, kLabelFixupDirect64); if (specialOffset != 0) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp index 1c0a965f2c85f0d456f42d2dd330ab538acb5155..02bcebbd003c74bc6b30047246c5a40a20cf09d2 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/reg_alloc_lsra.cpp @@ -1359,7 +1359,7 @@ uint32 LSRALinearScanRegAllocator::FindAvailablePhyReg(LiveInterval &li) } /* Spill and reload for caller saved registers. */ -void LSRALinearScanRegAllocator::InsertCallerSave(Insn &insn, Operand &opnd, bool isDef) +void LSRALinearScanRegAllocator::InsertCallerSave(Insn &insn, Operand &opnd, bool isDef, uint32 spillIdx) { auto ®Opnd = static_cast(opnd); uint32 vRegNO = regOpnd.GetRegisterNumber(); @@ -1408,8 +1408,8 @@ void LSRALinearScanRegAllocator::InsertCallerSave(Insn &insn, Operand &opnd, boo bool isOutOfRange = false; if (isDef) { Insn *nextInsn = insn.GetNext(); - memOpnd = GetSpillMem(vRegNO, true, insn, static_cast(intSpillRegSet[0] + firstIntReg), isOutOfRange, - regSize); + memOpnd = GetSpillMem(vRegNO, true, insn, static_cast(intSpillRegSet[spillIdx + 1] + firstIntReg), + isOutOfRange, regSize); Insn *stInsn = regInfo->BuildStrInsn(regSize, spType, *phyOpnd, *memOpnd); comment = " SPILL for caller_save " + std::to_string(vRegNO); ++callerSaveSpillCount; @@ -1426,8 +1426,8 @@ void LSRALinearScanRegAllocator::InsertCallerSave(Insn &insn, Operand &opnd, boo insn.GetBB()->InsertInsnAfter(insn, *stInsn); } } else { - memOpnd = GetSpillMem(vRegNO, false, insn, static_cast(intSpillRegSet[0] + firstIntReg), isOutOfRange, - regSize); + memOpnd = GetSpillMem(vRegNO, false, insn, static_cast(intSpillRegSet[spillIdx] + firstIntReg), + isOutOfRange, regSize); Insn *ldInsn = regInfo->BuildLdrInsn(regSize, spType, *phyOpnd, *memOpnd); comment = " RELOAD for caller_save " + std::to_string(vRegNO); ++callerSaveReloadCount; @@ -1804,8 +1804,8 @@ RegOperand *LSRALinearScanRegAllocator::GetReplaceUdOpnd(Insn &insn, Operand &op } if (li->IsShouldSave()) { - InsertCallerSave(insn, opnd, false); - InsertCallerSave(insn, opnd, true); + InsertCallerSave(insn, opnd, false, spillIdx); + InsertCallerSave(insn, opnd, true, spillIdx); } else if (li->GetStackSlot() == kSpilled) { SpillOperand(insn, opnd, false, spillIdx); SpillOperand(insn, opnd, true, spillIdx); @@ -1846,11 +1846,13 @@ RegOperand *LSRALinearScanRegAllocator::GetReplaceOpnd(Insn &insn, Operand &opnd cgFunc->AddtoCalleeSaved(regNO); } - if (li->IsShouldSave()) { - InsertCallerSave(insn, opnd, isDef); - } else if (li->GetStackSlot() == kSpilled) { + if (li->IsShouldSave() || li->GetStackSlot() == kSpilled) { spillIdx = isDef ? 0 : spillIdx; - SpillOperand(insn, opnd, isDef, spillIdx); + if (li->IsShouldSave()) { + InsertCallerSave(insn, opnd, isDef, spillIdx); + } else { + SpillOperand(insn, opnd, isDef, spillIdx); + } if (!isDef) { ++spillIdx; } diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp index 7ae5308768e1be1536c42e93eb5ed6cc7c314387..489d2c48ea8b387e96985ceed6c933618e13d351 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_emitter.cpp @@ -1546,7 +1546,7 @@ void X64Emitter::EmitBBHeaderLabel(CGFunc &cgFunc, LabelIdx labIdx, uint32 freq) bbLabel.append(to_string(funcUniqueId)); bbLabel.append("__"); bbLabel.append(to_string(labIdx)); - int64 labelSymIdx = CalculateLabelSymIdx(funcUniqueId, static_cast(labIdx)); + int64 labelSymIdx = CalculateLabelSymIdx(funcUniqueId, labIdx); assmbler.StoreNameIntoSymMap(labelSymIdx, bbLabel); if (cgFunc.GetCG()->GenerateVerboseCG()) { diff --git a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_standardize.cpp b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_standardize.cpp index 4b3bc53c46df13de8e91c782ef6144a86c61ad2f..c83c765a404eb13d91443baa333c4dd6f706c793 100644 --- a/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_standardize.cpp +++ b/ecmascript/compiler/codegen/maple/maple_be/src/cg/x86_64/x64_standardize.cpp @@ -82,10 +82,10 @@ void X64Standardize::StdzCvtOp(Insn &insn, CGFunc &cgFunc) case abstract::MOP_zext_rr_64_32: destSize = k32BitSize; break; - case abstract::MOP_cvt_fr_u32: + case abstract::MOP_cvt_f32_u32: srcSize = k64BitSize; break; - case abstract::MOP_cvt_rf_u32: + case abstract::MOP_cvt_u32_f32: destSize = k64BitSize; break; default: diff --git a/ecmascript/compiler/codegen/maple/maple_ir/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_ir/BUILD.gn index b179f367f7ea54096d74463e002bea59f37ab50b..3564fddb235b1623688d7166fa5e3eb435000118 100755 --- a/ecmascript/compiler/codegen/maple/maple_ir/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/maple_ir/BUILD.gn @@ -19,7 +19,6 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_util/include", "${MAPLEALL_ROOT}/maple_driver/include", "${MAPLEALL_ROOT}/mempool/include", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", "${MAPLEALL_ROOT}/maple_ipa/include", "${MAPLEALL_ROOT}/maple_ipa/include/old", "${MAPLEALL_ROOT}/maple_me/include", @@ -64,6 +63,7 @@ ohos_static_library("libmplir") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libmplir include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" deps = [ "${MAPLEALL_ROOT}/maple_driver:libdriver_option", diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_module.h b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_module.h index 5fc258f5157201e5a4088a32d5212f750b232350..0cdcb639916b90a37822fa4ec638de177c407cc6 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_module.h +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_module.h @@ -839,7 +839,7 @@ public: { curModulePC = pc; } - + uint32 GetCurModulePC() const { return curModulePC; diff --git a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h index e68ba2ba089ab400a05f44e9d09c784aa3ce246f..0cd1320be5cddf68a53db7a67b0ad54cf6e0e453 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h +++ b/ecmascript/compiler/codegen/maple/maple_ir/include/mir_nodes.h @@ -3046,8 +3046,8 @@ public: auto *node = allocator.GetMemPool()->New(*this); node->SetStmtID(stmtIDNext++); if (fromFreqs.count(GetStmtID()) > 0) { - int64_t oldFreq = fromFreqs[GetStmtID()]; - int64_t newFreq = numer == 0 ? 0 : (denom > 0 ? (oldFreq * numer / denom) : oldFreq); + int64_t oldFreq = static_cast(fromFreqs[GetStmtID()]); + int64_t newFreq = static_cast(numer == 0 ? 0 : (denom > 0 ? (oldFreq * numer / denom) : oldFreq)); toFreqs[node->GetStmtID()] = (newFreq > 0 || numer == 0) ? static_cast(newFreq) : 1; if (updateOp & kUpdateOrigFreq) { int64_t left = (oldFreq - newFreq) > 0 ? (oldFreq - newFreq) : 1; diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_export.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_export.cpp index 7ff851a44f5346f0a2556a0c31480aa2e31e10dc..7773af607f59ce23bc1023e9b6c83c7d0770bade 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_export.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_export.cpp @@ -59,6 +59,7 @@ void BinaryMplExport::OutputBaseNode(const BaseNode *b) void BinaryMplExport::OutputLocalSymbol(MIRSymbol *sym) { + CHECK_FATAL(sym != nullptr, "null ptr"); std::unordered_map::iterator it = localSymMark.find(sym); if (it != localSymMark.end()) { WriteNum(-(it->second)); @@ -70,7 +71,7 @@ void BinaryMplExport::OutputLocalSymbol(MIRSymbol *sym) WriteNum(sym->GetSKind()); WriteNum(sym->GetStorageClass()); size_t mark = localSymMark.size(); - localSymMark[sym] = mark; + localSymMark[sym] = static_cast(mark); OutputTypeAttrs(sym->GetAttrs()); WriteNum(static_cast(sym->GetIsTmp())); if (sym->GetSKind() == kStVar || sym->GetSKind() == kStFunc) { @@ -104,7 +105,7 @@ void BinaryMplExport::OutputPreg(MIRPreg *preg) WriteNum(kBinPreg); Write(static_cast(preg->GetPrimType())); size_t mark = localPregMark.size(); - localPregMark[preg] = mark; + localPregMark[preg] = static_cast(mark); } void BinaryMplExport::OutputLabel(LabelIdx lidx) @@ -117,7 +118,7 @@ void BinaryMplExport::OutputLabel(LabelIdx lidx) WriteNum(kBinLabel); size_t mark = labelMark.size(); - labelMark[lidx] = mark; + labelMark[lidx] = static_cast(mark); } void BinaryMplExport::OutputLocalTypeNameTab(const MIRTypeNameTable *typeNameTab) diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_import.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_import.cpp index 64b1dc9bf1f32819061ec2d775b116d3880eeb03..b9ce2ba83f2d08c1c1ee5be57b4fdb75d31a700d 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_import.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_func_import.cpp @@ -204,6 +204,7 @@ BaseNode *BinaryMplImport::ImportExpression(MIRFunction *func) case OP_addroffunc: { PUIdx puIdx = ImportFuncViaSym(func); MIRFunction *f = GlobalTables::GetFunctionTable().GetFuncTable()[puIdx]; + CHECK_FATAL(f != nullptr, "null ptr"); f->GetFuncSymbol()->SetAppearsInCode(true); AddroffuncNode *addrNode = mod.CurFuncCodeMemPool()->New(typ, puIdx); return addrNode; @@ -568,6 +569,7 @@ BlockNode *BinaryMplImport::ImportBlockNode(MIRFunction *func) CallNode *s = func->GetCodeMemPool()->New(mod, op); s->SetPUIdx(ImportFuncViaSym(func)); MIRFunction *f = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(s->GetPUIdx()); + CHECK_FATAL(f != nullptr, "null ptr"); f->GetFuncSymbol()->SetAppearsInCode(true); numOpr = static_cast(ReadNum()); s->SetNumOpnds(numOpr); @@ -587,6 +589,7 @@ BlockNode *BinaryMplImport::ImportBlockNode(MIRFunction *func) CallNode *s = func->GetCodeMemPool()->New(mod, op); s->SetPUIdx(ImportFuncViaSym(func)); MIRFunction *f = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(s->GetPUIdx()); + CHECK_FATAL(f != nullptr, "null ptr"); f->GetFuncSymbol()->SetAppearsInCode(true); ImportReturnValues(func, &s->GetReturnVec()); numOpr = static_cast(ReadNum()); @@ -606,6 +609,7 @@ BlockNode *BinaryMplImport::ImportBlockNode(MIRFunction *func) CallNode *s = func->GetCodeMemPool()->New(mod, op); s->SetPUIdx(ImportFuncViaSym(func)); MIRFunction *f = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(s->GetPUIdx()); + CHECK_FATAL(f != nullptr, "null ptr"); f->GetFuncSymbol()->SetAppearsInCode(true); s->SetTyIdx(ImportType()); numOpr = static_cast(ReadNum()); @@ -620,6 +624,7 @@ BlockNode *BinaryMplImport::ImportBlockNode(MIRFunction *func) CallNode *s = func->GetCodeMemPool()->New(mod, op); s->SetPUIdx(ImportFuncViaSym(func)); MIRFunction *f = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(s->GetPUIdx()); + CHECK_FATAL(f != nullptr, "null ptr"); f->GetFuncSymbol()->SetAppearsInCode(true); s->SetTyIdx(ImportType()); ImportReturnValues(func, &s->GetReturnVec()); @@ -926,6 +931,7 @@ void BinaryMplImport::ReadFunctionBodyField() for (int64 i = 0; i < size; ++i) { PUIdx puIdx = ImportFunction(); MIRFunction *fn = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(puIdx); + CHECK_FATAL(fn != nullptr, "null ptr"); mod.SetCurFunction(fn); fn->GetFuncSymbol()->SetAppearsInCode(true); localSymTab.clear(); diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_export.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_export.cpp index 57f3e063570b0d29d8177492347a9c26ef4910b0..988ecea1f598d1275c51707493bae29f3f38d49a 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_export.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_export.cpp @@ -475,7 +475,7 @@ void BinaryMplExport::OutputStr(const GStrIdx &gstr) } size_t mark = gStrMark.size(); - gStrMark[gstr] = mark; + gStrMark[gstr] = static_cast(mark); WriteNum(kBinString); DEBUG_ASSERT(GlobalTables::GetStrTable().StringTableSize() != 0, "Container check"); WriteAsciiStr(GlobalTables::GetStrTable().GetStringFromStrIdx(gstr)); @@ -495,7 +495,7 @@ void BinaryMplExport::OutputUsrStr(UStrIdx ustr) } size_t mark = uStrMark.size(); - uStrMark[ustr] = mark; + uStrMark[ustr] = static_cast(mark); WriteNum(kBinUsrString); WriteAsciiStr(GlobalTables::GetUStrTable().GetStringFromStrIdx(ustr)); } @@ -669,7 +669,7 @@ void BinaryMplExport::Init() funcMark[nullptr] = 0; eaNodeMark[nullptr] = 0; curFunc = nullptr; - for (uint32 pti = static_cast(PTY_begin); pti < static_cast(PTY_end); ++pti) { + for (uint32 pti = static_cast(PTY_begin); pti < static_cast(PTY_end); ++pti) { typMark[GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(pti))] = pti; } } @@ -695,7 +695,7 @@ void BinaryMplExport::OutputSymbol(MIRSymbol *sym) WriteNum(sym->GetSKind()); WriteNum(sym->GetStorageClass()); size_t mark = symMark.size(); - symMark[sym] = mark; + symMark[sym] = static_cast(mark); OutputTypeAttrs(sym->GetAttrs()); WriteNum(sym->GetIsTmp() ? 1 : 0); if (sym->GetSKind() == kStPreg) { @@ -733,7 +733,7 @@ void BinaryMplExport::OutputFunction(PUIdx puIdx) return; } size_t mark = funcMark.size(); - funcMark[func] = mark; + funcMark[func] = static_cast(mark); MIRFunction *savedFunc = mod.CurFunction(); mod.SetCurFunction(func); @@ -899,7 +899,7 @@ void BinaryMplExport::OutputCallInfo(CallInfo &callInfo) } WriteNum(kBinCallinfo); size_t mark = callInfoMark.size(); - callInfoMark[callInfo.GetID()] = mark; + callInfoMark[callInfo.GetID()] = static_cast(mark); WriteNum(callInfo.GetCallType()); // call type WriteInt(callInfo.GetLoopDepth()); WriteInt(callInfo.GetID()); @@ -1072,7 +1072,7 @@ void BinaryMplExport::OutEaCgNode(EACGBaseNode &node) return; } size_t mark = eaNodeMark.size(); - eaNodeMark[&node] = mark; + eaNodeMark[&node] = static_cast(mark); WriteNum(kBinEaCgNode); WriteNum(node.kind); OutEaCgBaseNode(node, true); @@ -1192,7 +1192,7 @@ void BinaryMplExport::WriteSymField(uint64 contentIdx) DEBUG_ASSERT(!(s->IsWpoFakeParm() || s->IsWpoFakeRet()) || s->IsDeleted(), "wpofake var not deleted"); MIRStorageClass storageClass = s->GetStorageClass(); MIRSymKind sKind = s->GetSKind(); - if (s->IsDeleted() || storageClass == kScUnused || (s->GetIsImported() && !s->GetAppearsInCode()) || + if (s->IsDeleted() || storageClass == kScUnused || (s->GetIsImported() && !s->GetAppearsInCode()) || (sKind == kStFunc && (storageClass == kScExtern || !s->GetAppearsInCode()))) { continue; } @@ -1366,8 +1366,8 @@ void BinaryMplExport::OutputType(TyIdx tyIdx) } ++BinaryMplExport::typeMarkOffset; } else { - size_t mark = typMark.size() + BinaryMplExport::typeMarkOffset; - typMark[ty] = mark; + size_t mark = typMark.size() + static_cast(BinaryMplExport::typeMarkOffset); + typMark[ty] = static_cast(mark); } auto func = CreateProductFunction(ty->GetKind()); diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_import.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_import.cpp index 6084357e08f1882441b1f1b602c8cd58aeb1690c..4d0b87a822ee4de0fa3f84dda9fb872b40dbc271 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_import.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/bin_mpl_import.cpp @@ -369,7 +369,7 @@ void BinaryMplImport::UpdateMethodSymbols() void BinaryMplImport::ImportFieldsOfStructType(FieldVector &fields, uint32 methodSize) { int64 size = ReadNum(); - int64 initSize = fields.size() + methodSize; + int64 initSize = static_cast(fields.size() + methodSize); for (int64 i = 0; i < size; ++i) { FieldPair fp; ImportFieldPair(fp); @@ -682,7 +682,7 @@ TyIdx BinaryMplImport::ImportType(bool forPointedType) return origType->GetTypeIndex(); } case kBinKindTypeBitField: { - uint8 fieldSize = ReadNum(); + uint8 fieldSize = static_cast(ReadNum()); MIRBitFieldType type(fieldSize, primType, strIdx); type.SetNameIsLocal(nameIsLocal); MIRType *origType = &InsertInTypeTables(type); @@ -839,7 +839,7 @@ TyIdx BinaryMplImport::ImportTypeNonJava() return tyIdxUsed; } case kBinKindTypeBitField: { - uint8 fieldSize = ReadNum(); + uint8 fieldSize = static_cast(ReadNum()); MIRBitFieldType type(fieldSize, primType, strIdx); type.SetNameIsLocal(nameIsLocal); GlobalTables::GetTypeTable().CreateMirTypeNodeAt(type, tyIdxUsed, &mod, false, false); diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/lexer.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/lexer.cpp index 97b19bde66012475baa9682f7a892d37a37c2742..2948d9663caccbeda5f38be070be0bdcc0296f76 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/lexer.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/lexer.cpp @@ -140,7 +140,7 @@ void MIRLexer::GenName() TokenKind MIRLexer::GetConstVal() { bool negative = false; - int valStart = curIdx; + int valStart = static_cast(curIdx); char c = GetCharAtWithUpperCheck(curIdx); if (c == '-') { c = GetNextCurrentCharWithUpperCheck(); @@ -214,7 +214,7 @@ TokenKind MIRLexer::GetHexConst(uint32 valStart, bool negative) tmp = (tmp << k16BitShift) + static_cast(HexCharToDigit(c)); c = GetNextCurrentCharWithUpperCheck(); } - theIntVal = static_cast(static_cast(tmp)); + theIntVal = static_cast(static_cast(tmp)); if (negative) { theIntVal = -theIntVal; } @@ -232,7 +232,7 @@ TokenKind MIRLexer::GetIntConst(uint32 valStart, bool negative) { auto negOrSelf = [negative](uint64 val) { return negative ? ~val + 1 : val; }; - theIntVal = HexCharToDigit(GetCharAtWithUpperCheck(curIdx)); + theIntVal = static_cast(HexCharToDigit(GetCharAtWithUpperCheck(curIdx))); uint64 radix = theIntVal == 0 ? 8 : 10; @@ -315,7 +315,7 @@ TokenKind MIRLexer::GetFloatConst(uint32 valStart, uint32 startIdx, bool negativ if (negative) { theFloatVal = -theFloatVal; } - theIntVal = static_cast(theFloatVal); + theIntVal = static_cast(theFloatVal); theDoubleVal = static_cast(theFloatVal); if (negative && fabs(theFloatVal) <= 1e-6) { theDoubleVal = -theDoubleVal; @@ -329,7 +329,7 @@ TokenKind MIRLexer::GetFloatConst(uint32 valStart, uint32 startIdx, bool negativ if (negative) { theDoubleVal = -theDoubleVal; } - theIntVal = static_cast(theDoubleVal); + theIntVal = static_cast(theDoubleVal); theFloatVal = static_cast(theDoubleVal); if (negative && fabs(theDoubleVal) <= 1e-15) { theFloatVal = -theFloatVal; @@ -359,11 +359,11 @@ TokenKind MIRLexer::GetTokenWithPrefixPercent() // token with prefix '%' char c = GetCharAtWithUpperCheck(curIdx); if (isdigit(c)) { - int valStart = curIdx - 1; - theIntVal = HexCharToDigit(c); + int valStart = static_cast(curIdx) - 1; + theIntVal = static_cast(HexCharToDigit(c)); c = GetNextCurrentCharWithUpperCheck(); while (isdigit(c)) { - theIntVal = (theIntVal * 10) + HexCharToDigit(c); // 10 for decimal + theIntVal = (theIntVal * 10) + static_cast(HexCharToDigit(c)); // 10 for decimal DEBUG_ASSERT(theIntVal >= 0, "int value overflow"); c = GetNextCurrentCharWithUpperCheck(); } diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp index f9c6462b432177e6dca0f1fec012ed12a9f414f1..d20f472d88f371a2cefa948cf2337142f74c32a3 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_builder.cpp @@ -367,6 +367,7 @@ MIRSymbol *MIRBuilder::GetOrCreateDeclInFunc(const std::string &str, const MIRTy DEBUG_ASSERT(symbolTable != nullptr, "symbol_table is null"); bool isCreated = false; MIRSymbol *st = GetOrCreateLocalDecl(str, type.GetTypeIndex(), *symbolTable, isCreated); + DEBUG_ASSERT(st != nullptr, "st is null"); if (isCreated) { st->SetStorageClass(kScAuto); st->SetSKind(kStVar); @@ -922,6 +923,7 @@ CallNode *MIRBuilder::CreateStmtCall(const std::string &callee, const MapleVecto MIRSymbol *st = GlobalTables::GetGsymTable().GetSymbolFromStidx(stIdx.Idx()); DEBUG_ASSERT(st != nullptr, "MIRSymbol st is null"); MIRFunction *func = st->GetFunction(); + DEBUG_ASSERT(func != nullptr, "func st is null"); return CreateStmtCall(func->GetPuidx(), args, OP_call); } diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_const.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_const.cpp index 587fc91a2c372892a8eb1f295cc637d3e26c61f9..9bcd5ccfab037c743f12290e1cfffe87cd50b2f7 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_const.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_const.cpp @@ -62,6 +62,7 @@ void MIRAddrofConst::Dump(const MIRSymbolTable *localSymTab) const : localSymTab->GetSymbolFromStIdx(stIdx.Idx()); DEBUG_ASSERT(stIdx.IsGlobal() || sym->GetStorageClass() == kScPstatic || sym->GetStorageClass() == kScFstatic, "MIRAddrofConst can only point to a global symbol"); + CHECK_FATAL(sym != nullptr, "null ptr"); LogInfo::MapleLogger() << (stIdx.IsGlobal() ? " $" : " %") << sym->GetName(); if (fldID > 0) { LogInfo::MapleLogger() << " " << fldID; @@ -90,6 +91,7 @@ void MIRAddroffuncConst::Dump(const MIRSymbolTable *) const { LogInfo::MapleLogger() << "addroffunc " << GetPrimTypeName(PTY_ptr); MIRFunction *func = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(puIdx); + CHECK_FATAL(func != nullptr, "null ptr"); LogInfo::MapleLogger() << " &" << GlobalTables::GetGsymTable().GetSymbolFromStidx(func->GetStIdx().Idx())->GetName(); } diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_lower.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_lower.cpp index f46a1de206ac977f4bc5c0d02d26571182dfcf0b..d6fa063f52a1dc8699f539fb110a32d863a63b5d 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_lower.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_lower.cpp @@ -714,7 +714,7 @@ BaseNode *MIRLower::LowerFarray(ArrayNode *array) if (constvalNode->GetConstVal()->GetKind() == kConstInt) { const MIRIntConst *pIntConst = static_cast(constvalNode->GetConstVal()); CHECK_FATAL(mirModule.IsJavaModule() || !pIntConst->IsNegative(), "Array index should >= 0."); - int64 eleOffset = pIntConst->GetExtValue() * eSize; + int64 eleOffset = pIntConst->GetExtValue() * static_cast(eSize); BaseNode *baseNode = array->GetBase(); if (eleOffset == 0) { @@ -811,7 +811,7 @@ BaseNode *MIRLower::LowerCArray(ArrayNode *array) uint64 indexVal = 0; if (index->op == OP_constval) { ConstvalNode *constNode = static_cast(index); - indexVal = (static_cast(constNode->GetConstVal()))->GetExtValue(); + indexVal = static_cast((static_cast(constNode->GetConstVal()))->GetExtValue()); isConst = true; MIRIntConst *newConstNode = mirModule.GetMemPool()->New( indexVal * mpyDim, *GlobalTables::GetTypeTable().GetTypeFromTyIdx(TyIdx(array->GetPrimType()))); diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_nodes.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_nodes.cpp index 084a4e4df469bcbc65b24d73f19ddd3328ba5765..51cd890b603b686a560dbab8601c85f990f8e628 100755 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_nodes.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_nodes.cpp @@ -282,7 +282,7 @@ BlockNode *BlockNode::CloneTreeWithFreqs(MapleAllocator &allocator, std::unorder } toFreqs[nnode->GetStmtID()] = (newFreq > 0 || (numer == 0)) ? newFreq : 1; if (updateOp & kUpdateOrigFreq) { // upateOp & 1 : update from - int64_t left = ((oldFreq - newFreq) > 0 || (oldFreq == 0)) ? (oldFreq - newFreq) : 1; + int64_t left = ((oldFreq - newFreq) > 0 || (oldFreq == 0)) ? static_cast(oldFreq - newFreq) : 1; fromFreqs[GetStmtID()] = static_cast(left); } } @@ -317,7 +317,8 @@ BlockNode *BlockNode::CloneTreeWithFreqs(MapleAllocator &allocator, std::unorder toFreqs[newStmt->GetStmtID()] = (newFreq > 0 || oldFreq == 0 || numer == 0) ? static_cast(newFreq) : 1; if (updateOp & kUpdateOrigFreq) { - int64_t left = ((oldFreq - newFreq) > 0 || oldFreq == 0) ? (oldFreq - newFreq) : 1; + int64_t left = ((oldFreq - newFreq) > 0 || oldFreq == 0) ? + static_cast(oldFreq - newFreq) : 1; fromFreqs[stmt.GetStmtID()] = static_cast(left); } } @@ -763,6 +764,7 @@ void AddroffuncNode::Dump(int32) const { LogInfo::MapleLogger() << kOpcodeInfo.GetTableItemAt(GetOpCode()).name << " " << GetPrimTypeName(GetPrimType()); MIRFunction *func = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(puIdx); + CHECK_FATAL(func != nullptr, "null ptr"); LogInfo::MapleLogger() << " &" << GlobalTables::GetGsymTable().GetSymbolFromStidx(func->GetStIdx().Idx())->GetName(); } @@ -1127,6 +1129,7 @@ void DoloopNode::DumpDoVar(const MIRModule &mod) const << " (\n"; } else { const MIRSymbol *st = mod.CurFunction()->GetLocalOrGlobalSymbol(doVarStIdx); + CHECK_FATAL(st != nullptr, "null ptr"); LogInfo::MapleLogger() << " %" << st->GetName() << " (\n"; } } diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_parser.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_parser.cpp index 51a2d7e04249b453037c5305b63e039a6e1d17cc..8723df34ea4ef135e5c339f7eee2fe1dab728918 100755 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_parser.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_parser.cpp @@ -919,6 +919,7 @@ bool MIRParser::ParseStmtCall(StmtNodePtr &stmt) callStmt->SetPUIdx(pIdx); MIRFunction *callee = GlobalTables::GetFunctionTable().GetFuncTable()[pIdx]; + DEBUG_ASSERT(callee != nullptr, "callee is null in MIRParser::ParseStmtCall"); callee->GetFuncSymbol()->SetAppearsInCode(true); if (callee->GetName() == "setjmp") { mod.CurFunction()->SetHasSetjmp(); @@ -2056,7 +2057,7 @@ bool MIRParser::ParseStmtBlockForReg() MIRType *mirType = GlobalTables::GetTypeTable().GetTypeFromTyIdx(tyidx); preg->SetMIRType(mirType); if (lexer.GetTokenKind() == TK_intconst) { - int64 theIntVal = lexer.GetTheIntVal(); + int64 theIntVal = static_cast(lexer.GetTheIntVal()); if (theIntVal != 0 && theIntVal != 1) { Error("parseDeclareReg failed"); return false; @@ -3371,6 +3372,7 @@ bool MIRParser::ParseConstAddrLeafExpr(MIRConstPtr &cexpr) auto *aof = static_cast(expr); MIRFunction *f = GlobalTables::GetFunctionTable().GetFunctionFromPuidx(aof->GetPUIdx()); MIRSymbol *fName = f->GetFuncSymbol(); + DEBUG_ASSERT(fName != nullptr, "null ptr check"); fName->SetAppearsInCode(true); TyIdx ptyIdx = fName->GetTyIdx(); MIRPtrType ptrType(ptyIdx); diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp index 1544ccd97134d4c480409070b83427c171d95617..3ccccccb9faa1871f1ccfd00480f5ba6039ddb61 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/mir_type.cpp @@ -1109,7 +1109,7 @@ bool MIRClassType::IsExceptionType() const FieldID MIRClassType::GetLastFieldID() const { - FieldID fieldID = fields.size(); + FieldID fieldID = static_cast(fields.size()); if (parentTyIdx != 0u) { const auto *parentClassType = static_cast(GlobalTables::GetTypeTable().GetTypeFromTyIdx(parentTyIdx)); @@ -1786,7 +1786,7 @@ int64 MIRArrayType::GetBitOffsetFromArrayAddress(std::vector &indexArray) int64 sum = 0; // element numbers before the specified element uint32 numberOfElemInLowerDim = 1; for (uint32 id = 1; id <= dim; ++id) { - sum += indexArray[dim - id] * numberOfElemInLowerDim; + sum += indexArray[dim - id] * static_cast(numberOfElemInLowerDim); numberOfElemInLowerDim *= sizeArray[dim - id]; } size_t elemsize = GetElemType()->GetSize(); @@ -1795,7 +1795,7 @@ int64 MIRArrayType::GetBitOffsetFromArrayAddress(std::vector &indexArray) } elemsize = RoundUp(elemsize, typeAttrs.GetAlign()); constexpr int64 bitsPerByte = 8; - int64 offset = static_cast(sum) * elemsize * static_cast(bitsPerByte); + int64 offset = static_cast(static_cast(sum) * elemsize * static_cast(bitsPerByte)); if (GetElemType()->GetKind() == kTypeArray && indexArray.size() > dim) { std::vector subIndexArray(indexArray.begin() + dim, indexArray.end()); offset += static_cast(GetElemType())->GetBitOffsetFromArrayAddress(subIndexArray); @@ -2127,7 +2127,7 @@ FieldPair MIRStructType::TraverseToField(FieldID fieldID) const return TraverseToFieldRef(fieldID); } // in parentfields - uint32 parentFieldIdx = -fieldID; + uint32 parentFieldIdx = static_cast(-fieldID); if (parentFields.empty() || parentFieldIdx > parentFields.size()) { return {GStrIdx(0), TyIdxFieldAttrPair(TyIdx(0), FieldAttrs())}; } diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/parser.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/parser.cpp index 5a1fbd03edab08a5eb7b7f1155784ab88c50fcbd..b875501fe0d73b848dcd2c8b3ed95df43e374d06 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/parser.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/parser.cpp @@ -160,7 +160,7 @@ void MIRParser::Error(const std::string &str) { std::stringstream strStream; const std::string &lexName = lexer.GetName(); - int curIdx = lexer.GetCurIdx() - lexName.length() + 1; + int curIdx = static_cast(lexer.GetCurIdx()) - static_cast(lexName.length()) + 1; strStream << "line: " << lexer.GetLineNum() << ":" << curIdx << ":"; message += strStream.str(); message += str; @@ -185,7 +185,7 @@ void MIRParser::Warning(const std::string &str) { std::stringstream strStream; const std::string &lexName = lexer.GetName(); - int curIdx = lexer.GetCurIdx() - lexName.length() + 1; + int curIdx = static_cast(lexer.GetCurIdx()) - static_cast(lexName.length()) + 1; strStream << " >> warning line: " << lexer.GetLineNum() << ":" << curIdx << ":"; warningMessage += strStream.str(); warningMessage += str; @@ -305,7 +305,7 @@ bool MIRParser::ParseArrayType(TyIdx &arrayTyIdx) Error("expect int value parsing array type after [ but get "); return false; } - int64 val = lexer.GetTheIntVal(); + int64 val = static_cast(lexer.GetTheIntVal()); if (val < 0) { Error("expect array value >= 0 "); return false; @@ -435,7 +435,7 @@ bool MIRParser::ParsePragmaElementForArray(MIRPragmaElement &elem) Error("parsing pragma error: expecting int but get "); return false; } - int64 size = lexer.GetTheIntVal(); + int64 size = static_cast(lexer.GetTheIntVal()); tk = lexer.NextToken(); if (tk != TK_coma && size) { Error("parsing pragma error: expecting , but get "); @@ -483,7 +483,7 @@ bool MIRParser::ParsePragmaElementForAnnotation(MIRPragmaElement &elem) Error("parsing pragma error: expecting int but get "); return false; } - int64 size = lexer.GetTheIntVal(); + int64 size = static_cast(lexer.GetTheIntVal()); tk = lexer.NextToken(); if (tk != TK_coma && size) { Error("parsing pragma error: expecting , but get "); @@ -3297,7 +3297,7 @@ bool MIRParser::ParseMPLT(std::ifstream &mpltFile, const std::string &importFile { // save relevant values for the main input file std::ifstream *airFileSave = lexer.GetFile(); - int lineNumSave = lexer.lineNum; + int lineNumSave = static_cast(lexer.lineNum); std::string modFileNameSave = mod.GetFileName(); // set up to read next line from the import file lexer.curIdx = 0; @@ -3340,7 +3340,7 @@ bool MIRParser::ParseMPLT(std::ifstream &mpltFile, const std::string &importFile // restore old values to continue reading from the main input file lexer.curIdx = 0; // to force reading new line lexer.currentLineSize = 0; - lexer.lineNum = lineNumSave; + lexer.lineNum = static_cast(lineNumSave); lexer.SetFile(*airFileSave); mod.SetFileName(modFileNameSave); return true; diff --git a/ecmascript/compiler/codegen/maple/maple_ir/src/printing.cpp b/ecmascript/compiler/codegen/maple/maple_ir/src/printing.cpp index 0f80e1007679af4a9c827f1ec0fd1ab782cf2ebb..8bc74446a1cbfc3648cbbed9875dff30f717eaba 100644 --- a/ecmascript/compiler/codegen/maple/maple_ir/src/printing.cpp +++ b/ecmascript/compiler/codegen/maple/maple_ir/src/printing.cpp @@ -26,7 +26,7 @@ void PrintIndentation(int32 indent) int64 indentAmount = static_cast(indent) * kIndentunit; do { LogInfo::MapleLogger() << kBlankString.substr(0, indentAmount); - indentAmount -= kBlankString.length(); + indentAmount -= static_cast(kBlankString.length()); } while (indentAmount > 0); } diff --git a/ecmascript/compiler/codegen/maple/maple_me/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_me/BUILD.gn index 706a87870b754ed4c67838ba5a9be403a8ff9ed8..1c6635bbd97fde4db3cf4b2054a781fcb937e45e 100755 --- a/ecmascript/compiler/codegen/maple/maple_me/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/maple_me/BUILD.gn @@ -16,7 +16,6 @@ import("//arkcompiler/ets_runtime/js_runtime_config.gni") include_directories = [ "${MAPLEALL_ROOT}/maple_ir/include", "${MAPLEALL_ROOT}/mempool/include", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", "${MAPLEALL_ROOT}/maple_me/include", "${MAPLEALL_ROOT}/maple_ipa/include", "${MAPLEALL_ROOT}/maple_ipa/include/old", @@ -45,6 +44,7 @@ ohos_static_library("libmplme") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libmplme include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" part_name = "ets_runtime" subsystem_name = "arkcompiler" diff --git a/ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn index 1b53744178aa23323668fa2813a1b313561ddd9b..f0abebe43d687e11579ba6ff3323516c4adcc0fa 100644 --- a/ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/maple_pgo/BUILD.gn @@ -26,7 +26,6 @@ include_libmplpgo = [ "${MAPLEALL_ROOT}/maple_be/include/be", "${MAPLEALL_ROOT}/maple_be/include/ad", "${MAPLEALL_ROOT}/maple_be/include/ad/target", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", "${MAPLEALL_ROOT}/maple_driver/include", "${MAPLEALL_ROOT}/maple_phase/include", ] @@ -41,6 +40,7 @@ ohos_static_library("libmplpgo") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libmplpgo include_dirs = include_libmplpgo + external_deps = [ "bounds_checking_function:libsec_static" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" part_name = "ets_runtime" subsystem_name = "arkcompiler" diff --git a/ecmascript/compiler/codegen/maple/maple_phase/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_phase/BUILD.gn index ae7c9a12f8e8b6368d327e622d22520fa5e64209..0a297c085998e82b46646829e09b0c791d2f23ff 100644 --- a/ecmascript/compiler/codegen/maple/maple_phase/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/maple_phase/BUILD.gn @@ -26,7 +26,6 @@ include_libmplphase = [ "${MAPLEALL_ROOT}/maple_be/include/be", "${MAPLEALL_ROOT}/maple_be/include/ad", "${MAPLEALL_ROOT}/maple_be/include/ad/target", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", "${MAPLEALL_ROOT}/maple_driver/include", ] @@ -43,6 +42,7 @@ ohos_static_library("libmplphase") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libmplphase include_dirs = include_libmplphase + external_deps = [ "bounds_checking_function:libsec_static" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" part_name = "ets_runtime" subsystem_name = "arkcompiler" diff --git a/ecmascript/compiler/codegen/maple/maple_util/BUILD.gn b/ecmascript/compiler/codegen/maple/maple_util/BUILD.gn index 162c877e0023b6c91f15d90e995d7d73f1ba5567..f5519fd8d973e0197fe2e03b5d9732e72fcf8d7e 100755 --- a/ecmascript/compiler/codegen/maple/maple_util/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/maple_util/BUILD.gn @@ -40,7 +40,6 @@ include_libmplutil = [ "${MAPLEALL_ROOT}/maple_ir/include", "${MAPLEALL_ROOT}/mempool/include", "${MAPLEALL_ROOT}/maple_driver/include", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", ] include_libcommandline = [ "${MAPLEALL_ROOT}/maple_util/include" ] @@ -50,6 +49,7 @@ ohos_static_library("libmplutil") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libmplutil include_dirs = include_libmplutil + external_deps = [ "bounds_checking_function:libsec_static" ] libs = [ "pthread" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" part_name = "ets_runtime" @@ -61,6 +61,7 @@ ohos_static_library("libcommandline") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libcommandline include_dirs = include_libcommandline + external_deps = [ "bounds_checking_function:libsec_static" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" part_name = "ets_runtime" subsystem_name = "arkcompiler" diff --git a/ecmascript/compiler/codegen/maple/maple_util/include/gcov_profile.h b/ecmascript/compiler/codegen/maple/maple_util/include/gcov_profile.h index a853feac878400e783b862fce266297a676a3e6f..fc3c24bdc52118309b3ef06fe76747579563fdb2 100644 --- a/ecmascript/compiler/codegen/maple/maple_util/include/gcov_profile.h +++ b/ecmascript/compiler/codegen/maple/maple_util/include/gcov_profile.h @@ -72,7 +72,7 @@ public: } void SetStmtFreq(uint32_t stmtID, int64_t freq) { - stmtFreqs[stmtID] = freq; + stmtFreqs[stmtID] = static_cast(freq); } void EraseStmtFreq(uint32_t stmtID) { diff --git a/ecmascript/compiler/codegen/maple/mempool/BUILD.gn b/ecmascript/compiler/codegen/maple/mempool/BUILD.gn index 691a0bb04c07e4b0ed1cd174c634fa7c19957650..e70a420b13ed7a0674f46f653bd586e92192e293 100644 --- a/ecmascript/compiler/codegen/maple/mempool/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/mempool/BUILD.gn @@ -22,7 +22,6 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_ir/include", "${MAPLEALL_ROOT}/maple_util/include", "${MAPLEALL_ROOT}/maple_driver/include", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", ] ohos_static_library("libmempool") { @@ -30,6 +29,7 @@ ohos_static_library("libmempool") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libmempool include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" part_name = "ets_runtime" subsystem_name = "arkcompiler" diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/BUILD.gn b/ecmascript/compiler/codegen/maple/mpl2mpl/BUILD.gn index 35e4763c30a75aea70dbddfb2ca01b04c949aa15..ff9d4a346c7b77e7601544fbb40fb1313f32542b 100755 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/BUILD.gn +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/BUILD.gn @@ -23,7 +23,6 @@ include_directories = [ "${MAPLEALL_ROOT}/maple_driver/include", "${MAPLEALL_ROOT}/mpl2mpl/include", "${MAPLEALL_ROOT}/mempool/include", - "${MAPLEALL_THIRD_PARTY_ROOT}/bounds_checking_function/include", ] src_libmpl2mpl = [ @@ -44,6 +43,7 @@ ohos_static_library("libmpl2mpl") { configs = [ "${MAPLEALL_ROOT}:mapleallcompilecfg" ] sources = src_libmpl2mpl include_dirs = include_directories + external_deps = [ "bounds_checking_function:libsec_static" ] output_dir = "${root_out_dir}/lib/${HOST_ARCH}" part_name = "ets_runtime" subsystem_name = "arkcompiler" diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/src/call_graph.cpp b/ecmascript/compiler/codegen/maple/mpl2mpl/src/call_graph.cpp index 30d21e0cd1aed38233e29e3b26742e12e6933568..9da9a1732003a7c0a3898273c012d98ad1af5f69 100644 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/src/call_graph.cpp +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/src/call_graph.cpp @@ -364,6 +364,7 @@ SCCNode *CallGraph::GetSCCNode(MIRFunction *func) const void CallGraph::UpdateCaleeCandidate(PUIdx callerPuIdx, IcallNode *icall, std::set &candidate) { CGNode *caller = GetCGNode(callerPuIdx); + CHECK_FATAL(caller != nullptr, "caller is null"); for (auto &pair : caller->GetCallee()) { auto *callsite = pair.first; if (callsite->GetCallStmt() == icall) { @@ -381,6 +382,7 @@ void CallGraph::UpdateCaleeCandidate(PUIdx callerPuIdx, IcallNode *icall, std::s void CallGraph::UpdateCaleeCandidate(PUIdx callerPuIdx, IcallNode *icall, PUIdx calleePuidx, CallNode *call) { CGNode *caller = GetCGNode(callerPuIdx); + CHECK_FATAL(caller != nullptr, "caller is null"); for (auto &pair : caller->GetCallee()) { auto *callsite = pair.first; if (callsite->GetCallStmt() == icall) { @@ -656,8 +658,10 @@ void CallGraph::HandleICall(BlockNode &body, CGNode &node, StmtNode *stmt, uint3 if (symbol->GetKonst()->GetKind() == kConstAggConst) { auto *aggConst = static_cast(symbol->GetKonst()); auto *elem = aggConst->GetAggConstElement(dread->GetFieldID()); + CHECK_FATAL(elem != nullptr, "elem is null"); if (elem->GetKind() == kConstAddrofFunc) { auto *addrofFuncConst = static_cast(elem); + CHECK_FATAL(addrofFuncConst != nullptr, "addrofFuncConst is null"); stmt = ReplaceIcallToCall(body, icall, addrofFuncConst->GetValue()); HandleCall(node, stmt, loopDepth); return; @@ -1295,8 +1299,9 @@ void DoDevirtual(const Klass &klass, const KlassHierarchy &klassh) rightSymbol->GetInferredTyIdx() != kNoneTyIdx) { // Devirtual Klass *currKlass = klassh.GetKlassFromTyIdx(rightSymbol->GetInferredTyIdx()); - if (op == OP_interfacecall || op == OP_interfacecallassigned || op == OP_virtualcall || - op == OP_virtualcallassigned) { + CHECK_FATAL(currKlass != nullptr, "null ptr check"); + if ((op == OP_interfacecall || op == OP_interfacecallassigned || op == OP_virtualcall || + op == OP_virtualcallassigned)) { std::vector klassVector; klassVector.push_back(currKlass); bool hasDevirtualed = false; diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/src/class_hierarchy.cpp b/ecmascript/compiler/codegen/maple/mpl2mpl/src/class_hierarchy.cpp index 9d4ebbad04fdd510812062644b863984462d3066..49b4c6c43aaf2398649996384deed0d5be0e09aa 100644 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/src/class_hierarchy.cpp +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/src/class_hierarchy.cpp @@ -630,6 +630,7 @@ void KlassHierarchy::AddKlassRelationAndMethods() // Add method info for (const auto &methodPair : klass->GetMIRStructType()->GetMethods()) { MIRSymbol *funcSym = GlobalTables::GetGsymTable().GetSymbolFromStidx(methodPair.first.Idx()); + DEBUG_ASSERT(funcSym != nullptr, "null ptr check"); MIRFunction *method = funcSym->GetFunction(); klass->AddMethod(method); if (method->GetName().compare(klass->GetKlassName() + namemangler::kClinitSuffix) == 0) { diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/src/constantfold.cpp b/ecmascript/compiler/codegen/maple/mpl2mpl/src/constantfold.cpp index 41866d19362d2f1edccc72cd034652402cdd046b..54350f0a77daa6af5e19d385a3ea157fe2abb7ef 100644 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/src/constantfold.cpp +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/src/constantfold.cpp @@ -1191,7 +1191,7 @@ MIRConst *ConstantFold::FoldRoundMIRConst(const MIRConst &cst, PrimType fromType return GlobalTables::GetFpConstTable().GetOrCreateFloatConst(floatValue); } } else { - uint64 fromValue = constValue.GetExtValue(); + uint64 fromValue = static_cast(constValue.GetExtValue()); float floatValue = round(static_cast(fromValue)); if (static_cast(floatValue) == fromValue) { return GlobalTables::GetFpConstTable().GetOrCreateFloatConst(floatValue); @@ -1206,7 +1206,7 @@ MIRConst *ConstantFold::FoldRoundMIRConst(const MIRConst &cst, PrimType fromType return GlobalTables::GetFpConstTable().GetOrCreateDoubleConst(doubleValue); } } else { - uint64 fromValue = constValue.GetExtValue(); + uint64 fromValue = static_cast(constValue.GetExtValue()); double doubleValue = round(static_cast(fromValue)); if (static_cast(doubleValue) == fromValue) { return GlobalTables::GetFpConstTable().GetOrCreateDoubleConst(doubleValue); @@ -1530,7 +1530,7 @@ std::pair> ConstantFold::FoldTypeCvt(TypeCvtNo MIRConst *ConstantFold::FoldSignExtendMIRConst(Opcode opcode, PrimType resultType, uint8 size, const IntVal &val) const { - uint64 result = opcode == OP_sext ? val.GetSXTValue(size) : val.GetZXTValue(size); + uint64 result = opcode == OP_sext ? static_cast(val.GetSXTValue(size)) : val.GetZXTValue(size); MIRType &type = *GlobalTables::GetTypeTable().GetPrimType(resultType); MIRIntConst *constValue = GlobalTables::GetIntConstTable().GetOrCreateIntConst(result, type); return constValue; @@ -1853,7 +1853,7 @@ std::pair> ConstantFold::FoldBinary(BinaryNode bsize++; ucst >>= 1; } while (ucst != 0); - if (shrAmt + bsize <= GetPrimTypeSize(primType) * kBitSizePerByte) { + if (shrAmt + static_cast(bsize <= GetPrimTypeSize(primType) * kBitSizePerByte)) { fold2extractbits = true; // change to use extractbits result = mirModule->GetMIRBuilder()->CreateExprExtractbits( @@ -2337,7 +2337,7 @@ StmtNode *ConstantFold::SimplifyCondGoto(CondGotoNode *node) ASSERT_NOT_NULL(intConst); if ((node->GetOpCode() == OP_brtrue && !intConst->IsZero()) || (node->GetOpCode() == OP_brfalse && intConst->IsZero())) { - uint32 freq = mirModule->CurFunction()->GetFreqFromLastStmt(node->GetStmtID()); + uint32 freq = static_cast(mirModule->CurFunction()->GetFreqFromLastStmt(node->GetStmtID())); GotoNode *gotoNode = mirModule->CurFuncCodeMemPool()->New(OP_goto); gotoNode->SetOffset(node->GetOffset()); if (Options::profileUse && mirModule->CurFunction()->GetFuncProfData()) { diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/src/ext_constantfold.cpp b/ecmascript/compiler/codegen/maple/mpl2mpl/src/ext_constantfold.cpp index 8adb4371166163e1a54c15e13d9567e1b3b36749..4086d8005bf268d7338fec7ec8d920dd5b1208ed 100644 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/src/ext_constantfold.cpp +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/src/ext_constantfold.cpp @@ -247,13 +247,13 @@ BaseNode *ExtConstantFold::ExtFoldXand(BinaryNode *node) (IsPrimitiveInteger(rnode->Opnd(1)->GetPrimType())) && (lnode->Opnd(0)->Opnd(0)->IsSameContent(rnode->Opnd(0)->Opnd(0)))) { MIRConst *lmConstVal = safe_cast(lnode->Opnd(0)->Opnd(1))->GetConstVal(); - uint64 lmVal = static_cast(lmConstVal)->GetExtValue(); + uint64 lmVal = static_cast(static_cast(lmConstVal)->GetExtValue()); MIRConst *rmConstVal = safe_cast(rnode->Opnd(0)->Opnd(1))->GetConstVal(); - uint64 rmVal = static_cast(rmConstVal)->GetExtValue(); + uint64 rmVal = static_cast(static_cast(rmConstVal)->GetExtValue()); MIRConst *lcConstVal = safe_cast(lnode->Opnd(1))->GetConstVal(); - uint64 lcVal = static_cast(lcConstVal)->GetExtValue(); + uint64 lcVal = static_cast(static_cast(lcConstVal)->GetExtValue()); MIRConst *rcConstVal = safe_cast(rnode->Opnd(1))->GetConstVal(); - uint64 rcVal = static_cast(rcConstVal)->GetExtValue(); + uint64 rcVal = static_cast(static_cast(rcConstVal)->GetExtValue()); bool isWorkable = true; for (uint64 i = 0; i < k64BitSize; i++) { diff --git a/ecmascript/compiler/codegen/maple/mpl2mpl/src/simplify.cpp b/ecmascript/compiler/codegen/maple/mpl2mpl/src/simplify.cpp index cec831158e7beda0872d5d641440a7ab289cc2c3..9f8507f206e57d1286ec469b196982f64471f3a0 100644 --- a/ecmascript/compiler/codegen/maple/mpl2mpl/src/simplify.cpp +++ b/ecmascript/compiler/codegen/maple/mpl2mpl/src/simplify.cpp @@ -289,7 +289,7 @@ static StmtNode *SplitAggCopy(const AssignType *assignNode, MIRStructType *struc newRHS->SetPrimType(fieldType->GetPrimType()); block->InsertAfter(assignNode, newDassign); if (fieldType->IsMIRUnionType()) { - id += fieldType->NumberOfFieldIDs(); + id += static_cast(fieldType->NumberOfFieldIDs()); } } auto newAssign = assignNode->GetNext(); diff --git a/ecmascript/compiler/common_stubs.cpp b/ecmascript/compiler/common_stubs.cpp index b1537dbdd42f401385a732344e0adc448c503f98..e7853b3786f828e696aa1d675224baeabe50846e 100644 --- a/ecmascript/compiler/common_stubs.cpp +++ b/ecmascript/compiler/common_stubs.cpp @@ -18,6 +18,7 @@ #include "ecmascript/base/number_helper.h" #include "ecmascript/compiler/access_object_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_string_stub_builder.h" +#include "ecmascript/compiler/builtins/linked_hashtable_stub_builder.h" #include "ecmascript/compiler/codegen/llvm/llvm_ir_builder.h" #include "ecmascript/compiler/interpreter_stub.h" #include "ecmascript/compiler/new_object_stub_builder.h" @@ -29,6 +30,7 @@ #include "ecmascript/js_map_iterator.h" #include "ecmascript/js_set.h" #include "ecmascript/js_set_iterator.h" +#include "ecmascript/linked_hash_table.h" #include "ecmascript/message_string.h" #include "ecmascript/tagged_hash_table.h" @@ -1140,6 +1142,18 @@ void CreateJSMapIteratorStubBuilder::GenerateCircuit() Return(*result); } +void JSMapGetStubBuilder::GenerateCircuit() +{ + GateRef glue = PtrArgument(0); + GateRef obj = TaggedArgument(1); + GateRef key = TaggedArgument(2U); + + LinkedHashTableStubBuilder linkedHashTableStubBuilder(this, glue); + GateRef linkedTable = linkedHashTableStubBuilder.GetLinked(obj); + GateRef result = linkedHashTableStubBuilder.Get(linkedTable, key); + Return(result); +} + CallSignature CommonStubCSigns::callSigns_[CommonStubCSigns::NUM_OF_STUBS]; void CommonStubCSigns::Initialize() diff --git a/ecmascript/compiler/common_stubs.h b/ecmascript/compiler/common_stubs.h index df54435edaa3a7d1d7c0020dcc6268ae25fbef8a..6a531b67b8372ab444d915278bdca0d50e23682d 100644 --- a/ecmascript/compiler/common_stubs.h +++ b/ecmascript/compiler/common_stubs.h @@ -91,6 +91,7 @@ namespace panda::ecmascript::kungfu { V(Getnextpropname) \ V(CreateJSSetIterator) \ V(CreateJSMapIterator) \ + V(JSMapGet) \ V(GetSingleCharCodeByIndex) \ V(FastStringEqual) \ V(FastStringAdd) \ diff --git a/ecmascript/compiler/compilation_driver.cpp b/ecmascript/compiler/compilation_driver.cpp index 31c76ba51ad3ce297820372416598d4bdb399447..b8d22e333715d8e143a9638564034a46d08d6f49 100644 --- a/ecmascript/compiler/compilation_driver.cpp +++ b/ecmascript/compiler/compilation_driver.cpp @@ -257,10 +257,10 @@ bool CompilationDriver::FilterOption(const std::mapGetJSThread()->GetCurrentEcmaContext()->GetPTManager(); - ptManager->SetCurConstantPool(jsPandaFile_, methodOffset); + ptManager->SetCurCompilationFile(jsPandaFile_); } void CompilationDriver::StoreConstantPoolInfo() const diff --git a/ecmascript/compiler/compilation_driver.h b/ecmascript/compiler/compilation_driver.h index 174a58dd17dcc2a39973cb476e2afea935900eed..df9a3960b17426e8d52bb93efceffdcf9a2d35da 100644 --- a/ecmascript/compiler/compilation_driver.h +++ b/ecmascript/compiler/compilation_driver.h @@ -87,7 +87,6 @@ public: MethodInfo &methodInfo) { Module *module = GetModule(); - SetCurrentConstantPool(methodOffset); cb(bytecodeInfo_.GetRecordName(index), methodName, methodLiteral, methodOffset, methodPcInfo, methodInfo, module); if (methodInfo.IsTypeInferAbort()) { @@ -102,6 +101,7 @@ public: { UpdatePGO(); InitializeCompileQueue(); + SetCurrentCompilationFile(); uint32_t index = 0; auto &methodList = bytecodeInfo_.GetMethodList(); const auto &methodPcInfos = bytecodeInfo_.GetMethodPcInfos(); @@ -353,7 +353,7 @@ protected: bool FilterOption(const std::map> &optionMap, const std::string &recordName, const std::string &methodName) const; - void SetCurrentConstantPool(uint32_t methodOffset) const; + void SetCurrentCompilationFile() const; void StoreConstantPoolInfo() const; diff --git a/ecmascript/compiler/compiler_log.cpp b/ecmascript/compiler/compiler_log.cpp index 0d46d2335207d03222a3bf40b05bb62702a40b10..d6b240034b341a044020f30d8565b32d8dc054e0 100644 --- a/ecmascript/compiler/compiler_log.cpp +++ b/ecmascript/compiler/compiler_log.cpp @@ -256,7 +256,7 @@ void PGOTypeLogList::CollectGateTypeLogInfo(GateRef gate, bool isBinOp) const PGOSampleType *sampleType = acc_.TryGetPGOType(gate).GetPGOSampleType(); if (sampleType->IsString()) { log_ += " [left type: string, right type: string]"; - } else if (sampleType->IsNumber()) { + } else if (sampleType->HasNumber()) { if (sampleType->IsInt()) { log_ += " [left type: int, right type: int]"; } else { diff --git a/ecmascript/compiler/early_elimination.cpp b/ecmascript/compiler/early_elimination.cpp index e2b7e917b8b155050dd5d82610e803769449a6cc..bfa87c31586c54aec2f010446531269b7d45c35c 100644 --- a/ecmascript/compiler/early_elimination.cpp +++ b/ecmascript/compiler/early_elimination.cpp @@ -229,6 +229,9 @@ GateRef EarlyElimination::UpdateDependChain(GateRef gate, DependInfoNode* depend DependInfoNode* EarlyElimination::UpdateWrite(GateRef gate, DependInfoNode* dependInfo) { + if (!enableMemoryAnalysis_) { + return new (chunk_) DependInfoNode(chunk_); + } auto op = acc_.GetOpCode(gate); switch (op) { case OpCode::STORE_PROPERTY: @@ -349,20 +352,14 @@ bool EarlyElimination::CheckReplacement(GateRef lhs, GateRef rhs) break; } case OpCode::TYPED_ARRAY_CHECK: { - if (acc_.GetTypedArrayMetaDateAccessor(lhs).GetType() != - acc_.GetTypedArrayMetaDateAccessor(rhs).GetType()) { + if (acc_.GetTypedArrayMetaDateAccessor(lhs).GetParamType() != + acc_.GetTypedArrayMetaDateAccessor(rhs).GetParamType()) { return false; } break; } case OpCode::TYPE_OF_CHECK: { - if (acc_.GetParamGateType(lhs) != acc_.GetParamGateType(rhs)) { - return false; - } - break; - } - case OpCode::OBJECT_TYPE_CHECK: { - if (acc_.GetObjectTypeAccessor(lhs).GetType() != acc_.GetObjectTypeAccessor(rhs).GetType()) { + if (acc_.GetParamType(lhs) != acc_.GetParamType(rhs)) { return false; } break; diff --git a/ecmascript/compiler/early_elimination.h b/ecmascript/compiler/early_elimination.h index ad152459d678361d6b248f970c64db8d36571523..57414268e79b609c73290636d46ddf110d968081 100644 --- a/ecmascript/compiler/early_elimination.h +++ b/ecmascript/compiler/early_elimination.h @@ -59,8 +59,9 @@ private: class EarlyElimination : public PassVisitor { public: - EarlyElimination(Circuit* circuit, RPOVisitor* visitor, Chunk* chunk) - : PassVisitor(circuit, chunk, visitor), dependChains_(chunk), renames_(chunk) {} + EarlyElimination(Circuit* circuit, RPOVisitor* visitor, Chunk* chunk, bool enableMemoryAnalysis) + : PassVisitor(circuit, chunk, visitor), dependChains_(chunk), renames_(chunk), + enableMemoryAnalysis_(enableMemoryAnalysis) {} ~EarlyElimination() = default; @@ -91,6 +92,7 @@ private: ChunkVector dependChains_; ChunkVector renames_; + bool enableMemoryAnalysis_ {true}; }; } // panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_EARLY_ELIMINATION_H diff --git a/ecmascript/compiler/escape_analysis.cpp b/ecmascript/compiler/escape_analysis.cpp index 2b0fdfa2463ccb6821ac289fd4f79c79ca25a99c..ed9608ab98a22816c17ba35492a1f957c1933be6 100644 --- a/ecmascript/compiler/escape_analysis.cpp +++ b/ecmascript/compiler/escape_analysis.cpp @@ -293,11 +293,11 @@ VirtualObject* EscapeAnalysis::GetOrCreateVirtualObject(size_t numIn, GateInfo* GateRef EscapeAnalysis::VisitCreateObjectWithBuffer(GateRef gate, GateInfo* info) { - constexpr size_t startIn = 5; // 5 : start of props + constexpr size_t startIn = 4; // 4 : start of props constexpr size_t fieldSize = 8; // 8 : bytes per field constexpr size_t stride = 2; // 2: offset and value auto numIn = acc_.GetNumValueIn(gate); - size_t size = acc_.GetConstantValue(acc_.GetValueIn(gate, 1)) / fieldSize; + size_t size = acc_.GetConstantValue(acc_.GetValueIn(gate, 0)) / fieldSize; VirtualObject* vObj = GetOrCreateVirtualObject(size, info); for (size_t i = startIn; i < numIn; i += stride) { diff --git a/ecmascript/compiler/frame_states.cpp b/ecmascript/compiler/frame_states.cpp index f29e66b5130179f181185799e479fe474ff7ad89..ffbd8f1da39a7f1c0fae7bea2642e5ae73f426d8 100644 --- a/ecmascript/compiler/frame_states.cpp +++ b/ecmascript/compiler/frame_states.cpp @@ -12,17 +12,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -#include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/frame_states.h" -#include "ecmascript/ts_types/ts_manager.h" + #include +#include "ecmascript/compiler/bytecode_circuit_builder.h" + namespace panda::ecmascript::kungfu { FrameStateBuilder::FrameStateBuilder(BytecodeCircuitBuilder *builder, Circuit *circuit, const MethodLiteral *literal) : bcBuilder_(builder), - tsManager_(builder->GetTSManager()), - typeRecorder_(builder->GetTypeRecorder()), pgoTypeRecorder_(builder->GetPGOTypeRecorder()), numVregs_(literal->GetNumberVRegs() + FIXED_ARGS), accumulatorIndex_(literal->GetNumberVRegs() + 1), // 1: acc @@ -225,7 +224,11 @@ FrameLiveOut *FrameStateBuilder::GetOrOCreateBBLiveOut(size_t bbIndex) { // As BB0 is empty, its bbBeginStateLiveouts is the same as BB1. if (bbIndex == 0) { - bbIndex = 1; + if (bcBuilder_->IsOSR()) { + bbIndex = GetOsrLoopHeadBBId(); + } else { + bbIndex = 1; + } } auto liveout = bbBeginStateLiveouts_[bbIndex]; if (liveout == nullptr) { @@ -250,11 +253,8 @@ FrameContext *FrameStateBuilder::GetOrOCreateMergedContext(uint32_t bbIndex) return context; } -void FrameStateBuilder::FillBcInputs(const BytecodeInfo &bytecodeInfo, uint32_t bcIndex, GateRef gate) +void FrameStateBuilder::FillBcInputs(const BytecodeInfo &bytecodeInfo, GateRef gate) { - auto type = typeRecorder_->GetType(bcIndex); - acc_.SetGateType(gate, type); - EcmaOpcode opcode = bytecodeInfo.GetOpcode(); auto pgoType = pgoTypeRecorder_->GetPGOType(acc_.TryGetPcOffset(gate)); acc_.TrySetPGOType(gate, pgoType); @@ -276,13 +276,6 @@ void FrameStateBuilder::FillBcInputs(const BytecodeInfo &bytecodeInfo, uint32_t acc_.NewIn(gate, inIdx, defVreg); } else { GateRef defAcc = liveContext_->ValuesAt(accumulatorIndex_); - if (Bytecodes::IsCallOp(opcode)) { - auto oldGt = acc_.GetGateType(defAcc).GetGTRef(); - GateType callTargetType = typeRecorder_->GetCallTargetType(bcIndex); - if (!tsManager_->MethodOffsetIsVaild(oldGt) && !callTargetType.IsAnyType()) { - acc_.SetGateType(defAcc, callTargetType); - } - } acc_.NewIn(gate, inIdx, defAcc); } } @@ -320,7 +313,7 @@ void FrameStateBuilder::UpdateStateDepend(GateRef state, GateRef depend) liveContext_->currentDepend_ = depend; } -void FrameStateBuilder::UpdateMoveValues(const BytecodeInfo &bytecodeInfo, uint32_t bcId) +void FrameStateBuilder::UpdateMoveValues(const BytecodeInfo &bytecodeInfo) { GateRef gate = Circuit::NullGate(); if (bytecodeInfo.AccIn()) { @@ -336,13 +329,6 @@ void FrameStateBuilder::UpdateMoveValues(const BytecodeInfo &bytecodeInfo, uint3 auto vreg = bytecodeInfo.vregOut[0]; liveContext_->SetValuesAt(vreg, gate); } - if (bcBuilder_->HasTypes()) { - GateType type = acc_.GetGateType(gate); - if (type.IsAnyType()) { - type = typeRecorder_->UpdateType(bcId, type); - acc_.SetGateType(gate, type); - } - } } void FrameStateBuilder::UpdateFrameValues(const BytecodeInfo &bytecodeInfo, @@ -355,7 +341,7 @@ void FrameStateBuilder::UpdateFrameValues(const BytecodeInfo &bytecodeInfo, } // jump gate is null if (gate != Circuit::NullGate()) { - FillBcInputs(bytecodeInfo, bcId, gate); + FillBcInputs(bytecodeInfo, gate); } auto liveout = GetFrameLiveoutAfter(bcId); // variable kill @@ -378,6 +364,58 @@ void FrameStateBuilder::UpdateFrameValues(const BytecodeInfo &bytecodeInfo, BindStateSplitAfter(bytecodeInfo, bcId, gate); } +void FrameStateBuilder::SetOsrLoopHeadBB(const BytecodeRegion &osrLoopBodyBB) +{ + auto *loopInfo = GetLoopInfoByLoopBody(osrLoopBodyBB); + if (loopInfo == nullptr) { + loopHeadOfOSR_ = nullptr; + } else { + loopHeadOfOSR_ = &(bcBuilder_->GetBasicBlockById(loopInfo->loopHeadId)); + } + return; +} + +bool FrameStateBuilder::IsOsrLoopExit(const BytecodeRegion &curBB) +{ + if (loopHeadOfOSR_ == nullptr) { + return false; + } + auto *loopInfo = GetLoopInfoByLoopBody(*loopHeadOfOSR_); + if (!loopInfo || !loopInfo->loopExits) { + return false; + } + for (auto *exit : *loopInfo->loopExits) { + if (exit == &curBB) { + return true; + } + } + return false; +} + +bool FrameStateBuilder::OutOfOsrLoop(const BytecodeRegion &curBB) +{ + if (loopHeadOfOSR_ == nullptr) { + return false; + } + const LoopInfo &loopInfoOfOSR = GetLoopInfo(*loopHeadOfOSR_); + const LoopInfo *curLoop = GetLoopInfoByLoopBody(curBB); + while (curLoop != nullptr) { + if (curLoop == &loopInfoOfOSR) { + return false; + } + curLoop = curLoop->parentInfo; + } + return true; +} + +size_t FrameStateBuilder::GetOsrLoopHeadBBId() const +{ + if (loopHeadOfOSR_ == nullptr) { + return -1; + } + return loopHeadOfOSR_->id; +} + void FrameStateBuilder::InitEntryBB(const BytecodeRegion &bb) { auto frameContext = GetOrOCreateMergedContext(bb.id); @@ -406,23 +444,54 @@ void FrameStateBuilder::InitEntryBB(const BytecodeRegion &bb) } } } + + // init live interpreter registers + if (!bcBuilder_->IsOSR()) { + return; + } + auto *liveOut = GetFrameLiveoutBefore(GetOsrLoopHeadBBId()); + for (size_t i = 0; i < envIndex_; i++) { + if (!liveOut->TestBit(i)) { + continue; + } + GateRef init = circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(i), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::TaggedValue()); + frameContext->SetValuesAt(i, init); + } + if (liveOut->TestBit(envIndex_)) { + // -7: env + GateRef env = circuit_->NewGate(circuit_->GetMetaBuilder()->InitVreg(INIT_VRGE_ENV), MachineType::I64, + {circuit_->GetArgRoot()}, GateType::TaggedValue()); + frameContext->SetValuesAt(envIndex_, env); + } } void FrameStateBuilder::NewMerge(const BytecodeRegion &bbNext) { auto frameContext = GetMergedBbContext(bbNext.id); size_t numOfIns = bbNext.numOfStatePreds; - const GateMetaData* metaData = bbNext.loopNumber > 0 ? - circuit_->LoopBegin(numOfIns) : circuit_->Merge(numOfIns); - auto merge = circuit_->NewGate(metaData, - std::vector(numOfIns, Circuit::NullGate())); - auto dependMerge = circuit_->NewGate(circuit_->DependSelector(numOfIns), - std::vector(numOfIns + 1, Circuit::NullGate())); - acc_.NewIn(dependMerge, 0, merge); // 0: is state + if (IsOsrLoopExit(bbNext)) { + // Only the precursor within the OSR loop is required. + numOfIns = 0; + for (const BytecodeRegion *bb : bbNext.preds) { + if (OutOfOsrLoop(*bb)) { + continue; + } + numOfIns++; + } + } + + bool isLoopHead = !(bcBuilder_->IsOSR() && OutOfOsrLoop(bbNext)) && bbNext.loopNumber > 0; + const GateMetaData *metaData = isLoopHead ? circuit_->LoopBegin(numOfIns) : circuit_->Merge(numOfIns); + auto merge = circuit_->NewGate(metaData, std::vector(numOfIns, Circuit::NullGate())); + auto dependMerge = + circuit_->NewGate(circuit_->DependSelector(numOfIns), std::vector(numOfIns + 1, Circuit::NullGate())); + acc_.NewIn(dependMerge, 0, merge); // 0: is state // reset current state and depend frameContext->currentState_ = merge; frameContext->currentDepend_ = dependMerge; - if (bbNext.loopNumber > 0) { + + if (isLoopHead) { ChunkVector& headerGates = bcBuilder_->GetLoopHeaderGates(); auto& loopInfo = GetLoopInfo(bbNext); headerGates[loopInfo.sortIndx] = merge; @@ -446,7 +515,9 @@ void FrameStateBuilder::MergeStateDepend(const BytecodeRegion &bb, const Bytecod NewMerge(bbNext); } if (IsLoopBackEdge(bb, bbNext)) { - ASSERT(index != 0); + if (!(bcBuilder_->IsOSR() && IsOsrLoopExit(bbNext))) { + ASSERT(index != 0); + } entryState = circuit_->NewGate(circuit_->LoopBack(), { entryState }); } acc_.NewIn(mergedContext->currentState_, index, entryState); @@ -454,6 +525,21 @@ void FrameStateBuilder::MergeStateDepend(const BytecodeRegion &bb, const Bytecod mergedContext->needStateSplit_ = true; } +size_t FrameStateBuilder::GetNumOfStatePreds(const BytecodeRegion &bb) +{ + size_t numOfIns = bb.numOfStatePreds; + if (bcBuilder_->IsOSR() && IsOsrLoopExit(bb)) { + numOfIns = 0; + for (const BytecodeRegion *b : bb.preds) { + if (OutOfOsrLoop(*b)) { + continue; + } + numOfIns++; + } + } + return numOfIns; +} + GateRef FrameStateBuilder::MergeValue(const BytecodeRegion &bb, GateRef stateMerge, GateRef currentValue, GateRef nextValue, size_t index) { @@ -465,9 +551,10 @@ GateRef FrameStateBuilder::MergeValue(const BytecodeRegion &bb, acc_.NewIn(nextValue, index + 1, currentValue); currentValue = nextValue; } else if (currentValue != nextValue) { - auto inList = std::vector(1 + bb.numOfStatePreds, Circuit::NullGate()); // 1: state - auto phi = circuit_->NewGate(circuit_->ValueSelector(bb.numOfStatePreds), - MachineType::I64, inList.size(), inList.data(), GateType::AnyType()); + size_t numOfIns = GetNumOfStatePreds(bb); + auto inList = std::vector(1 + numOfIns, Circuit::NullGate()); // 1: state + auto phi = circuit_->NewGate(circuit_->ValueSelector(numOfIns), MachineType::I64, inList.size(), inList.data(), + GateType::AnyType()); acc_.NewIn(phi, 0, stateMerge); if (nextValue != Circuit::NullGate()) { for (size_t i = 0; i < index; i++) { @@ -588,7 +675,10 @@ void FrameStateBuilder::NewLoopExit(const BytecodeRegion &bbNext, BitSet *loopAs void FrameStateBuilder::TryInsertLoopExit(const BytecodeRegion &bb, const BytecodeRegion &bbNext) { - if (!bcBuilder_->EnableLoopOptimization()) { + if (!bcBuilder_->EnableLoopOptimization() && !bcBuilder_->IsOSR()) { + return; + } + if (bcBuilder_->IsOSR() && bcBuilder_->IsCacheBBOfOSRLoop(bbNext)) { return; } auto currentLoop = GetLoopInfoByLoopBody(bb); @@ -613,14 +703,14 @@ void FrameStateBuilder::TryInsertLoopExit(const BytecodeRegion &bb, const Byteco } } -void FrameStateBuilder::AdvanceToNextBB(const BytecodeRegion &bb) +void FrameStateBuilder::AdvanceToNextBB(const BytecodeRegion &bb, bool isOsrLoopExit) { liveContext_ = GetMergedBbContext(bb.id); ASSERT(liveContext_ != nullptr); if (bb.loopNumber > 0) { // use bb as merged values SaveCurrentContext(bb); - } else { + } else if (!isOsrLoopExit) { // all input merged ASSERT(liveContext_->currentIndex_ == bb.numOfStatePreds); } @@ -672,7 +762,9 @@ void FrameStateBuilder::MergeIntoSuccessor(const BytecodeRegion &bb, const Bytec bool FrameStateBuilder::IsLoopBackEdge(const BytecodeRegion &bb, const BytecodeRegion &bbNext) { - if (bbNext.loopNumber > 0) { + if (bcBuilder_->IsOSR() && OutOfOsrLoop(bbNext)) { + return false; + } else if (bbNext.loopNumber > 0) { auto& loopInfo = GetLoopInfo(bbNext); return loopInfo.loopBodys->TestBit(bb.id); } @@ -872,9 +964,11 @@ public: CountLoopBody(loopInfo, info.fromId); PropagateLoopBody(loopInfo); } - if (!bcBuilder_->EnableLoopOptimization()) { + + if (!bcBuilder_->EnableLoopOptimization() && !bcBuilder_->IsOSR()) { return; } + auto size = bcBuilder_->GetBasicBlockCount(); dfsStack_.resize(size, DFSState(0, 0)); ComputeLoopTree(); @@ -968,7 +1062,9 @@ public: while (currentDepth > 0) { auto &curState = dfsStack_[currentDepth - 1]; // -1: for current auto const &bb = bcBuilder_->GetBasicBlockById(curState.bbId); - ASSERT(bb.catches.empty()); + if (!bcBuilder_->IsOSR()) { + ASSERT(bb.catches.empty()); + } auto index = curState.index; BytecodeRegion* bbNext = nullptr; if (index >= bb.succs.size()) { diff --git a/ecmascript/compiler/frame_states.h b/ecmascript/compiler/frame_states.h index 657c305e50cea85548de79044f6d08180957a4d8..74da363523f329779dd053f9dd396a4afd5a7512 100644 --- a/ecmascript/compiler/frame_states.h +++ b/ecmascript/compiler/frame_states.h @@ -16,7 +16,6 @@ #ifndef ECMASCRIPT_COMPILER_FRAME_STATE_H #define ECMASCRIPT_COMPILER_FRAME_STATE_H -#include "ecmascript/compiler/argument_accessor.h" #include "ecmascript/compiler/base/bit_set.h" #include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/gate.h" @@ -115,7 +114,7 @@ public: void AdvanceToNextBc(const BytecodeInfo &bytecodeInfo, FrameLiveOut* liveout, uint32_t bcId); void UpdateFrameValues(const BytecodeInfo &bytecodeInfo, uint32_t bcId, GateRef gate); - void UpdateMoveValues(const BytecodeInfo &bytecodeInfo, uint32_t bcId); + void UpdateMoveValues(const BytecodeInfo &bytecodeInfo); void UpdateStateDepend(GateRef state, GateRef depend); FrameLiveOut *GetOrOCreateBCEndLiveOut(uint32_t bcIndex); FrameLiveOut *GetOrOCreateBBLiveOut(size_t bbIndex); @@ -129,7 +128,7 @@ public: return liveContext_->currentDepend_; } void MergeIntoSuccessor(const BytecodeRegion &bb, const BytecodeRegion &bbNext); - void AdvanceToNextBB(const BytecodeRegion &bb); + void AdvanceToNextBB(const BytecodeRegion &bb, bool isOsrLoopExit = false); void InitEntryBB(const BytecodeRegion &bb); const ChunkDeque& GetRpoList() const @@ -146,6 +145,20 @@ public: UpdateVirtualRegister(accumulatorIndex_, gate); } + void SetOsrLoopHeadBB(const BytecodeRegion &loopHeadOfOSR); + + bool IsOsrLoopExit(const BytecodeRegion &curBB); + + bool OutOfOsrLoop(const BytecodeRegion &curBB); + + size_t GetOsrLoopHeadBBId() const; + + bool IsContextExists(uint32_t bbIndex) const + { + ASSERT(bbIndex < bbFrameContext_.size()); + return bbFrameContext_[bbIndex] != nullptr; + } + private: static constexpr size_t FIXED_ARGS = 2; // ac & env struct LoopInfo { @@ -208,8 +221,9 @@ private: } FrameContext *GetOrOCreateMergedContext(uint32_t bbIndex); - void FillBcInputs(const BytecodeInfo &bytecodeInfo, uint32_t bcIndex, GateRef gate); + void FillBcInputs(const BytecodeInfo &bytecodeInfo, GateRef gate); void DumpLiveState(); + size_t GetNumOfStatePreds(const BytecodeRegion &bb); GateRef MergeValue(const BytecodeRegion &bb, GateRef stateMerge, GateRef currentValue, GateRef nextValue, size_t index); void NewMerge(const BytecodeRegion &bbNext); @@ -239,8 +253,6 @@ private: FrameContext *GetCachedContext(); BytecodeCircuitBuilder *bcBuilder_ {nullptr}; - TSManager *tsManager_ {nullptr}; - const TypeRecorder *typeRecorder_ {nullptr}; const PGOTypeRecorder *pgoTypeRecorder_ {nullptr}; FrameLiveOut *liveOutResult_ {nullptr}; FrameLiveOut *currentBBliveOut_ {nullptr}; @@ -261,6 +273,7 @@ private: ChunkVector loops_; ChunkDeque rpoList_; ChunkVector postOrderList_; + const BytecodeRegion *loopHeadOfOSR_ {nullptr}; friend class BlockLoopAnalysis; friend class SubContextScope; diff --git a/ecmascript/compiler/gate.cpp b/ecmascript/compiler/gate.cpp index 3030adebaf47108e33a32317353a25487d5f1c37..0b8d0591a4ac0f052391421778c40bcc098b9ac6 100644 --- a/ecmascript/compiler/gate.cpp +++ b/ecmascript/compiler/gate.cpp @@ -242,42 +242,93 @@ void Gate::CheckFrameStateInput() const } } -void Gate::CheckStateOutput() const +std::string Gate::GetValueInAndOut(bool inListPreview, size_t highlightIdx) const { - if (GetMetaData()->IsState()) { - size_t cnt = 0; - const Gate *curGate = this; - if (!curGate->IsFirstOutNull()) { - const Out *curOut = curGate->GetFirstOutConst(); - auto meta = curOut->GetGateConst()->GetMetaData(); - if (curOut->IsStateEdge() && meta->IsState()) { - cnt++; - } + auto opcode = GetOpCode(); + if (opcode != OpCode::NOP && opcode != OpCode::DEAD) { + std::string log("{\"id\":" + std::to_string(id_) + ", \"op\":\"" + GateMetaData::Str(opcode) + "\", "); + log += "\",\"in\":["; + size_t idx = 0; + auto stateSize = GetStateCount(); + auto dependSize = GetDependCount(); + auto valueSize = GetInValueCount(); + auto frameStateSize = GetInFrameStateCount(); + auto rootSize = GetRootCount(); + size_t start = 0; + size_t end = stateSize; + idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); + end += dependSize; + start += stateSize; + idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); + end += valueSize; + start += dependSize; + idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); + end += frameStateSize; + start += valueSize; + idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log); + end += rootSize; + start += frameStateSize; + idx = PrintInGate(end, idx, start, inListPreview, highlightIdx, log, true); + + log += "], \"out\":["; + + if (!IsFirstOutNull()) { + const Out *curOut = GetFirstOutConst(); + opcode = curOut->GetGateConst()->GetOpCode(); + log += std::to_string(curOut->GetGateConst()->GetId()) + + (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) : std::string("")); + while (!curOut->IsNextOutNull()) { curOut = curOut->GetNextOutConst(); - meta = curOut->GetGateConst()->GetMetaData(); - if (curOut->IsStateEdge() && meta->IsState()) { - cnt++; - } + log += ", " + std::to_string(curOut->GetGateConst()->GetId()) + + (inListPreview ? std::string(":" + GateMetaData::Str(opcode)) + : std::string("")); } } - size_t expected = 0; - bool needCheck = true; - if (GetMetaData()->IsTerminalState()) { - expected = 0; - } else if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::JS_BYTECODE) { - expected = 2; // 2: expected number of state out branches - } else if (GetOpCode() == OpCode::SWITCH_BRANCH) { - needCheck = false; - } else { - expected = 1; + log += "]},"; + return log; + } + return ""; +} + +void Gate::CheckStateOutput(const std::string& methodName) const +{ + if (!GetMetaData()->IsState()) { + return; + } + size_t cnt = 0; + const Gate *curGate = this; + if (!curGate->IsFirstOutNull()) { + const Out *curOut = curGate->GetFirstOutConst(); + auto meta = curOut->GetGateConst()->GetMetaData(); + if (curOut->IsStateEdge() && meta->IsState()) { + cnt++; } - if (needCheck && cnt != expected) { - curGate->Print(); - CheckFailed("Number of state out branches is not valid (expected:" + std::to_string(expected) + - " actual:" + std::to_string(cnt) + ")", -1); + while (!curOut->IsNextOutNull()) { + curOut = curOut->GetNextOutConst(); + meta = curOut->GetGateConst()->GetMetaData(); + if (curOut->IsStateEdge() && meta->IsState()) { + cnt++; + } } } + size_t expected = 0; + bool needCheck = true; + if (GetMetaData()->IsTerminalState()) { + expected = 0; + } else if (GetOpCode() == OpCode::IF_BRANCH || GetOpCode() == OpCode::JS_BYTECODE) { + expected = 2; // 2: expected number of state out branches + } else if (GetOpCode() == OpCode::SWITCH_BRANCH) { + needCheck = false; + } else { + expected = 1; + } + if (needCheck && cnt != expected) { + curGate->Print(); + std::string log = curGate->GetValueInAndOut(true); + CheckFailed("Number of state out branches is not valid (expected:" + std::to_string(expected) + + " actual:" + std::to_string(cnt) + ") methodName:" + methodName + " gateValue:" + log, -1); + } } void Gate::CheckBranchOutput() const @@ -367,7 +418,7 @@ void Gate::CheckRelay() const } } -void Gate::Verify(bool isArch64) const +void Gate::Verify(bool isArch64, const std::string& methodName) const { CheckNullInput(); CheckStateInput(); @@ -375,7 +426,7 @@ void Gate::Verify(bool isArch64) const CheckDependInput(); CheckFrameStateInput(); CheckRootInput(); - CheckStateOutput(); + CheckStateOutput(methodName); CheckBranchOutput(); CheckNOP(); CheckSelector(); @@ -731,11 +782,8 @@ std::string Gate::GateTypeStr(GateType gateType) const if (strMap.count(gateType) > 0) { name = strMap.at(gateType); } - GlobalTSTypeRef r = gateType.GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return name + std::string("-GT(M=") + std::to_string(m) + - std::string(", L=") + std::to_string(l) + std::string(")"); + uint32_t r = gateType.GetType(); + return name + std::string("-gateType(") + std::to_string(r) + std::string(")"); } void Gate::Print(std::string additionOp, bool inListPreview, size_t highlightIdx) const @@ -883,7 +931,8 @@ void Gate::PrintWithBytecode() const break; } case OpCode::TYPED_BINARY_OP: { - bytecodeStr = GetTypedBinaryMetaData()->Str(); + auto typedOp = TypedBinaryAccessor(GetOneParameterMetaData()->GetValue()).GetTypedBinOp(); + bytecodeStr = GateMetaData::Str(typedOp); break; } case OpCode::TYPED_UNARY_OP: { @@ -907,7 +956,8 @@ void Gate::PrintWithBytecode() const break; } case OpCode::TYPED_CALLTARGETCHECK_OP: { - auto typedOp = GetTypedCallTargetCheckMetaData()->GetTypedCallTargetCheckOp(); + TypedCallTargetCheckAccessor accessor(GetOneParameterMetaData()->GetValue()); + auto typedOp = accessor.GetCallTargetCheckOp(); bytecodeStr = GateMetaData::Str(typedOp); break; } diff --git a/ecmascript/compiler/gate.h b/ecmascript/compiler/gate.h index feb6377268894696e38f4bd719acafe413569db0..9c78e0d71a57f538ae1403fb5f9257ad0274fe7f 100644 --- a/ecmascript/compiler/gate.h +++ b/ecmascript/compiler/gate.h @@ -192,12 +192,13 @@ public: void CheckDependInput() const; void CheckRootInput() const; void CheckFrameStateInput() const; - void CheckStateOutput() const; + void CheckStateOutput(const std::string& methodName) const; + std::string GetValueInAndOut(bool inListPreview = false, size_t highlightIdx = -1) const; void CheckBranchOutput() const; void CheckNOP() const; void CheckSelector() const; void CheckRelay() const; - void Verify(bool isArch64) const; + void Verify(bool isArch64, const std::string& methodName) const; [[nodiscard]] MarkCode GetMark(TimeStamp stamp) const; void SetMark(MarkCode mark, TimeStamp stamp); MachineType GetMachineType() const @@ -226,16 +227,6 @@ public: return OneParameterMetaData::Cast(meta_); } - const TypedBinaryMetaData* GetTypedBinaryMetaData() const - { - return TypedBinaryMetaData::Cast(meta_); - } - - const TypedCallTargetCheckMetaData* GetTypedCallTargetCheckMetaData() const - { - return TypedCallTargetCheckMetaData::Cast(meta_); - } - const StringMetaData* GetStringMetaData() const { ASSERT(meta_->IsStringType()); diff --git a/ecmascript/compiler/gate_accessor.cpp b/ecmascript/compiler/gate_accessor.cpp index aaaf9f438e6688363c6422a5db13e4ed1b6dfc46..85e7ed13e7e11b330901637e2f6b4f690310e25c 100644 --- a/ecmascript/compiler/gate_accessor.cpp +++ b/ecmascript/compiler/gate_accessor.cpp @@ -108,6 +108,13 @@ size_t GateAccessor::GetOffset(GateRef gate) const return accessor.GetOffset(); } +size_t GateAccessor::GetInitOffset(GateRef gate) const +{ + ASSERT(GetOpCode(gate) == OpCode::INITVREG); + Gate *gatePtr = circuit_->LoadGatePtr(gate); + return gatePtr->GetOneParameterMetaData()->GetValue(); +} + uint32_t GateAccessor::GetTrueWeight(GateRef gate) const { ASSERT(GetOpCode(gate) == OpCode::IF_BRANCH); @@ -331,21 +338,6 @@ bool GateAccessor::TypedOpIsTypedArray(GateRef gate, TypedOpKind kind) const } } -GateType GateAccessor::GetReceiverType([[maybe_unused]]GateRef gate) const -{ - return GateType::Empty(); -} - -GateType GateAccessor::GetHolderType([[maybe_unused]]GateRef gate) const -{ - return GateType::Empty(); -} - -GateType GateAccessor::GetNewHolderType([[maybe_unused]]GateRef gate) const -{ - return GateType::Empty(); -} - TypedLoadOp GateAccessor::GetTypedLoadOp(GateRef gate) const { ASSERT(GetOpCode(gate) == OpCode::LOAD_ELEMENT); @@ -363,8 +355,8 @@ TypedStoreOp GateAccessor::GetTypedStoreOp(GateRef gate) const TypedCallTargetCheckOp GateAccessor::GetTypedCallTargetCheckOp(GateRef gate) const { ASSERT(GetOpCode(gate) == OpCode::TYPED_CALLTARGETCHECK_OP); - Gate *gatePtr = circuit_->LoadGatePtr(gate); - return gatePtr->GetTypedCallTargetCheckMetaData()->GetTypedCallTargetCheckOp(); + TypedCallTargetCheckAccessor accessor(TryGetValue(gate)); + return accessor.GetCallTargetCheckOp(); } MemoryType GateAccessor::GetMemoryType(GateRef gate) const @@ -385,52 +377,26 @@ uint32_t GateAccessor::GetHClassIndex(GateRef gate) const TypedBinOp GateAccessor::GetTypedBinaryOp(GateRef gate) const { ASSERT(GetOpCode(gate) == OpCode::TYPED_BINARY_OP); - Gate *gatePtr = circuit_->LoadGatePtr(gate); - return gatePtr->GetTypedBinaryMetaData()->GetTypedBinaryOp(); -} - -PGOTypeRef GateAccessor::GetTypedBinaryType(GateRef gate) const -{ - ASSERT(GetOpCode(gate) == OpCode::TYPED_BINARY_OP); - Gate *gatePtr = circuit_->LoadGatePtr(gate); - return gatePtr->GetTypedBinaryMetaData()->GetType(); + TypedBinaryAccessor accessor(TryGetValue(gate)); + return accessor.GetTypedBinOp(); } bool GateAccessor::HasNumberType(GateRef gate) const { - auto sampleType = GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - return true; - } - if (sampleType->IsNone()) { - GateType leftType = GetLeftType(gate); - GateType rightType = GetRightType(gate); - if (leftType.IsNumberType() && rightType.IsNumberType()) { - return true; - } + OpCode op = GetOpCode(gate); + if (op == OpCode::TYPED_BINARY_OP) { + TypedBinaryAccessor accessor(TryGetValue(gate)); + return accessor.GetParamType().HasNumberType(); } return false; } bool GateAccessor::HasStringType(GateRef gate) const { - const PGOSampleType *sampleType = TryGetPGOType(gate).GetPGOSampleType(); - return sampleType->IsString(); -} - -// Include number, undefined, null and boolean type. -bool GateAccessor::HasPrimitiveNumberType(GateRef gate) const -{ - auto sampleType = GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - return true; - } - if (sampleType->IsNone()) { - GateType leftType = GetLeftType(gate); - GateType rightType = GetRightType(gate); - if (leftType.IsPrimitiveNumberType() && rightType.IsPrimitiveNumberType()) { - return true; - } + OpCode op = GetOpCode(gate); + if (op == OpCode::TYPED_BINARY_OP) { + TypedBinaryAccessor accessor(TryGetValue(gate)); + return accessor.GetParamType().IsStringType(); } return false; } @@ -445,17 +411,21 @@ GlobalTSTypeRef GateAccessor::GetFuncGT(GateRef gate) const GateType GateAccessor::GetParamGateType(GateRef gate) const { - ASSERT(GetOpCode(gate) == OpCode::PRIMITIVE_TYPE_CHECK || - GetOpCode(gate) == OpCode::INDEX_CHECK || - GetOpCode(gate) == OpCode::TYPED_CALLTARGETCHECK_OP || - GetOpCode(gate) == OpCode::CREATE_ARRAY_WITH_BUFFER || - GetOpCode(gate) == OpCode::TYPE_OF_CHECK || - GetOpCode(gate) == OpCode::TYPE_OF); + // NOTICE-PGO: consider to delete this function in Part3, only primitive_type_check use, + // which is generate in the retype pass + ASSERT(GetOpCode(gate) == OpCode::PRIMITIVE_TYPE_CHECK); Gate *gatePtr = circuit_->LoadGatePtr(gate); GateTypeAccessor accessor(gatePtr->GetOneParameterMetaData()->GetValue()); return accessor.GetGateType(); } +ParamType GateAccessor::GetParamType(GateRef gate) const +{ + Gate *gatePtr = circuit_->LoadGatePtr(gate); + GateTypeAccessor accessor(gatePtr->GetOneParameterMetaData()->GetValue()); + return accessor.GetParamType(); +} + bool GateAccessor::IsConvertSupport(GateRef gate) const { ASSERT(GetOpCode(gate) == OpCode::CONVERT || @@ -483,25 +453,6 @@ ValueType GateAccessor::GetDstType(GateRef gate) const return accessor.GetDstType(); } -GateType GateAccessor::GetLeftType(GateRef gate) const -{ - ASSERT(GetOpCode(gate) == OpCode::TYPED_UNARY_OP || - GetOpCode(gate) == OpCode::TYPED_BINARY_OP || - GetOpCode(gate) == OpCode::TYPE_CONVERT); - Gate *gatePtr = circuit_->LoadGatePtr(gate); - GatePairTypeAccessor accessor(gatePtr->GetOneParameterMetaData()->GetValue()); - return accessor.GetLeftType(); -} - -GateType GateAccessor::GetRightType(GateRef gate) const -{ - ASSERT(GetOpCode(gate) == OpCode::TYPED_BINARY_OP || - GetOpCode(gate) == OpCode::TYPE_CONVERT); - Gate *gatePtr = circuit_->LoadGatePtr(gate); - GatePairTypeAccessor accessor(gatePtr->GetOneParameterMetaData()->GetValue()); - return accessor.GetRightType(); -} - uint32_t GateAccessor::GetFirstValue(GateRef gate) const { ASSERT(GetOpCode(gate) == OpCode::RANGE_GUARD); @@ -664,9 +615,6 @@ PGOTypeRef GateAccessor::TryGetPGOType(GateRef gate) const if (op == OpCode::JS_BYTECODE) { return gatePtr->GetJSBytecodeMetaData()->GetType(); } - if (op == OpCode::TYPED_BINARY_OP) { - return GetTypedBinaryType(gate); - } return PGOTypeRef::NoneType(); } @@ -1991,4 +1939,46 @@ uint32_t GateAccessor::GetConstpoolId(GateRef gate) const Gate *gatePtr = circuit_->LoadGatePtr(gate); return gatePtr->GetOneParameterMetaData()->GetValue(); } + +TypedBinOp GateAccessor::GetRevCompareOpForTypedBinOp(TypedBinOp op) +{ + switch (op) { + case TypedBinOp::TYPED_LESS: + return TypedBinOp::TYPED_GREATEREQ; + case TypedBinOp::TYPED_LESSEQ: + return TypedBinOp::TYPED_GREATER; + case TypedBinOp::TYPED_GREATER: + return TypedBinOp::TYPED_LESSEQ; + case TypedBinOp::TYPED_GREATEREQ: + return TypedBinOp::TYPED_LESS; + case TypedBinOp::TYPED_EQ: + return TypedBinOp::TYPED_NOTEQ; + case TypedBinOp::TYPED_NOTEQ: + return TypedBinOp::TYPED_EQ; + default: + UNREACHABLE(); + return op; + } +} + +TypedBinOp GateAccessor::GetSwapCompareOpForTypedBinOp(TypedBinOp op) +{ + switch (op) { + case TypedBinOp::TYPED_LESS: + return TypedBinOp::TYPED_GREATER; + case TypedBinOp::TYPED_LESSEQ: + return TypedBinOp::TYPED_GREATEREQ; + case TypedBinOp::TYPED_GREATER: + return TypedBinOp::TYPED_LESS; + case TypedBinOp::TYPED_GREATEREQ: + return TypedBinOp::TYPED_LESSEQ; + case TypedBinOp::TYPED_EQ: + return TypedBinOp::TYPED_EQ; + case TypedBinOp::TYPED_NOTEQ: + return TypedBinOp::TYPED_NOTEQ; + default: + UNREACHABLE(); + return op; + } +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/gate_accessor.h b/ecmascript/compiler/gate_accessor.h index 756a8bd4e0592f632cfd602444ed2a62d85075d9..2f21750fe44d1303593a1c1035563f6c274389cf 100644 --- a/ecmascript/compiler/gate_accessor.h +++ b/ecmascript/compiler/gate_accessor.h @@ -383,6 +383,7 @@ public: ICmpCondition GetICmpCondition(GateRef gate) const; FCmpCondition GetFCmpCondition(GateRef gate) const; size_t GetOffset(GateRef gate) const; + size_t GetInitOffset(GateRef gate) const; uint32_t GetTrueWeight(GateRef gate) const; uint32_t GetFalseWeight(GateRef gate) const; bool HasBranchWeight(GateRef gate) const; @@ -397,21 +398,17 @@ public: void SetElementsKind(GateRef gate, ElementsKind kind); size_t GetVirtualRegisterIndex(GateRef gate) const; bool TypedOpIsTypedArray(GateRef gate, TypedOpKind kind) const; - GateType GetReceiverType(GateRef gate) const; - GateType GetHolderType(GateRef gate) const; - GateType GetNewHolderType(GateRef gate) const; TypedLoadOp GetTypedLoadOp(GateRef gate) const; TypedStoreOp GetTypedStoreOp(GateRef gate) const; MemoryType GetMemoryType(GateRef gate) const; uint32_t GetHClassIndex(GateRef gate) const; TypedBinOp GetTypedBinaryOp(GateRef gate) const; TypedCallTargetCheckOp GetTypedCallTargetCheckOp(GateRef gate) const; - PGOTypeRef GetTypedBinaryType(GateRef gate) const; - bool HasPrimitiveNumberType(GateRef gate) const; bool HasNumberType(GateRef gate) const; bool HasStringType(GateRef gate) const; GlobalTSTypeRef GetFuncGT(GateRef gate) const; GateType GetParamGateType(GateRef gate) const; + ParamType GetParamType(GateRef gate) const; TypedUnaryAccessor GetTypedUnAccessor(GateRef gate) const; TypedBinaryAccessor GetTypedBinaryAccessor(GateRef gate) const; TypedJumpAccessor GetTypedJumpAccessor(GateRef gate) const; @@ -542,8 +539,6 @@ public: void ReplaceGate(GateRef gate, GateRef state, GateRef depend, GateRef value); void ReplaceGate(GateRef gate, StateDepend stateDepend, GateRef replacement); void ReplaceGate(GateRef gate, GateRef replacement); - GateType GetLeftType(GateRef gate) const; - GateType GetRightType(GateRef gate) const; uint32_t GetFirstValue(GateRef gate) const; uint32_t GetSecondValue(GateRef gate) const; GateRef GetGlueFromArgList() const; @@ -616,6 +611,9 @@ public: void SetStoreNoBarrier(GateRef gate, bool isNoBarrier); bool IsNoBarrier(GateRef gate) const; + TypedBinOp GetRevCompareOpForTypedBinOp(TypedBinOp op); + TypedBinOp GetSwapCompareOpForTypedBinOp(TypedBinOp op); + private: const GateMetaData *GetMetaData(GateRef gate) const; UseIterator ReplaceHirIfSuccess(const UseIterator &useIt, GateRef state); diff --git a/ecmascript/compiler/gate_meta_data_builder.h b/ecmascript/compiler/gate_meta_data_builder.h index b39af546b5ce0667de34e8a803b498a37ab56ed0..68d333f2e5b07731ad0a5fb93a0f21954997e60b 100644 --- a/ecmascript/compiler/gate_meta_data_builder.h +++ b/ecmascript/compiler/gate_meta_data_builder.h @@ -146,16 +146,6 @@ public: return new (chunk_) JSBytecodeMetaData(valuesIn, methodId, opcode, pcOffset, bcIndex, flags); } - const GateMetaData* TypedBinaryOp(uint64_t value, TypedBinOp binOp, PGOTypeRef type) - { - return new (chunk_) TypedBinaryMetaData(value, binOp, type); - } - - const GateMetaData* TypedCallTargetCheckOp(uint32_t numIns, uint64_t value, TypedCallTargetCheckOp checkOp) - { - return new (chunk_) TypedCallTargetCheckMetaData(numIns, value, checkOp); - } - const GateMetaData* Nop() { return &cachedNop_; diff --git a/ecmascript/compiler/graph_editor.cpp b/ecmascript/compiler/graph_editor.cpp index d6d45dd01d85f73fd3d6ef4e051864cc53af72fd..74a38930b214e54bd2818abe7ba057729d28c98f 100644 --- a/ecmascript/compiler/graph_editor.cpp +++ b/ecmascript/compiler/graph_editor.cpp @@ -122,6 +122,30 @@ void GraphEditor::PropagateMerge(const Edge& edge) } } +bool GraphEditor::HasOsrDeoptUse(GateRef gate) +{ + std::vector valueOuts; + acc_.GetValueUses(gate, valueOuts); + for (auto out : valueOuts) { + if (acc_.GetOpCode(out) != OpCode::FRAME_STATE) { + continue; + } + std::vector outs; + acc_.GetValueUses(out, outs); + for (auto use : outs) { + if (acc_.GetOpCode(use) != OpCode::DEOPT_CHECK) { + continue; + } + GateRef deoptType = acc_.GetValueIn(use, 2); // 2: deopt type + uint64_t v = acc_.GetConstantValue(deoptType); + if (v == static_cast(DeoptType::OSRLOOPEXIT)) { + return true; + } + } + } + return false; +} + void GraphEditor::EliminatePhi() { circuit_->AdvanceTime(); @@ -139,7 +163,7 @@ void GraphEditor::EliminatePhi() phis.emplace_back(gate); continue; } - if (acc_.IsFrameValues(gate)) { + if (acc_.IsFrameValues(gate) && !HasOsrDeoptUse(gate)) { continue; } // get used phi diff --git a/ecmascript/compiler/graph_editor.h b/ecmascript/compiler/graph_editor.h index 1ffa90cb77f05cb5cf28465336d1f0b484230e27..7484941c7276344f738403d9a04f8e6a3b702855 100644 --- a/ecmascript/compiler/graph_editor.h +++ b/ecmascript/compiler/graph_editor.h @@ -38,6 +38,7 @@ private: void PropagateGate(const Edge& edge); void PropagateMerge(const Edge& edge); void EliminatePhi(); + bool HasOsrDeoptUse(GateRef gate); Circuit *circuit_ {nullptr}; GateAccessor acc_; diff --git a/ecmascript/compiler/graph_linearizer.h b/ecmascript/compiler/graph_linearizer.h index 97d4ed317b5e750f95170d81ce6f99ec9d2982eb..15674af1c2623ced6420e02c1114e216e45d8a1b 100644 --- a/ecmascript/compiler/graph_linearizer.h +++ b/ecmascript/compiler/graph_linearizer.h @@ -474,6 +474,7 @@ private: friend class ImmediateDominatorsGenerator; friend class LoopInfoBuilder; friend class StateSplitLinearizer; + friend class InductionVariableAnalysis; }; }; // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/hash_stub_builder.cpp b/ecmascript/compiler/hash_stub_builder.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6fbd49f032e8bda5d558cf50a181d322b92b2cfa --- /dev/null +++ b/ecmascript/compiler/hash_stub_builder.cpp @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2022 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. + */ + +#include "ecmascript/compiler/hash_stub_builder.h" + +namespace panda::ecmascript::kungfu { + +GateRef HashStubBuilder::GetHash(GateRef key) +{ + auto env = GetEnvironment(); + Label entryLabel(env); + Label exit(env); + env->SubCfgEntry(&entryLabel); + DEFVARIABLE(res, VariableType::INT32(), Int32(0)); + + Label slowGetHash(env); + Label symbolKey(env); + Label stringCheck(env); + BRANCH(TaggedIsSymbol(key), &symbolKey, &stringCheck); + + Bind(&symbolKey); + res = Load(VariableType::INT32(), key, IntPtr(JSSymbol::HASHFIELD_OFFSET)); + Jump(&exit); + + Bind(&stringCheck); + Label stringKey(env); + Label objectCheck(env); + BRANCH(TaggedIsString(key), &stringKey, &objectCheck); + Bind(&stringKey); + res = GetHashcodeFromString(glue_, key); + Jump(&exit); + + Bind(&objectCheck); + Label heapObjectKey(env); + Label numberCheck(env); + BRANCH(TaggedIsHeapObject(key), &heapObjectKey, &numberCheck); + + Bind(&heapObjectKey); + Label ecmaObjectKey(env); + BRANCH(TaggedObjectIsEcmaObject(key), &ecmaObjectKey, &slowGetHash); + Bind(&ecmaObjectKey); + CalcHashcodeForObject(glue_, key, &res, &exit); + + Bind(&numberCheck); + Label numberKey(env); + BRANCH(TaggedIsNumber(key), &numberKey, &slowGetHash); + + Bind(&numberKey); + CalcHashcodeForNumber(key, &res, &exit); + + Bind(&slowGetHash); + res = GetInt32OfTInt(CallRuntime(glue_, RTSTUB_ID(GetLinkedHash), { key })); + Jump(&exit); + + Bind(&exit); + auto ret = *res; + env->SubCfgExit(); + return ret; +} + +void HashStubBuilder::CalcHashcodeForNumber(GateRef key, Variable *res, Label *exit) +{ + auto env = GetEnvironment(); + Label doubleKey(env); + Label intKey(env); + BRANCH(TaggedIsDouble(key), &doubleKey, &intKey); + Bind(&doubleKey); + { + CalcHashcodeForDouble(key, res, exit); + } + Bind(&intKey); + { + *res = CalcHashcodeForInt(key); + Jump(exit); + } +} +} // namespace panda::ecmascript::kungfu diff --git a/test/typeinfer/bitwise_op/bitwise_op.ts b/ecmascript/compiler/hash_stub_builder.h similarity index 40% rename from test/typeinfer/bitwise_op/bitwise_op.ts rename to ecmascript/compiler/hash_stub_builder.h index 9f2c729a69a7ba465f0575ecc4201a91c0323a37..db4d17deee1ff4c146cb85366b8ed1f5c17de8a1 100644 --- a/test/typeinfer/bitwise_op/bitwise_op.ts +++ b/ecmascript/compiler/hash_stub_builder.h @@ -1,40 +1,41 @@ -/* - * Copyright (c) 2022 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. - */ - -declare function AssertType(value:any, type:string):void; -{ - let x:number = 123; - let y:number = 2; - let andRes = x & y; - AssertType(andRes, "int"); - - let orRes = x | y; - AssertType(orRes, "int"); - - let xorRes = x ^ y; - AssertType(xorRes, "int"); - - let shlRes = x << y; - AssertType(shlRes, "int"); - - let ashrRes = x >> y; - AssertType(ashrRes, "int"); - - let shrRes = x >>> y; - AssertType(shrRes, "int"); - - let notRes = ~x; - AssertType(notRes, "int"); -} +/* + * Copyright (c) 2022 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. + */ + +#ifndef ECMASCRIPT_COMPILER_HASH_STUB_BUILDER_H +#define ECMASCRIPT_COMPILER_HASH_STUB_BUILDER_H + +#include "ecmascript/compiler/builtins/builtins_string_stub_builder.h" +#include "ecmascript/compiler/profiler_operation.h" +#include "ecmascript/compiler/stub_builder.h" + +namespace panda::ecmascript::kungfu { +class HashStubBuilder : public StubBuilder { +public: + explicit HashStubBuilder(StubBuilder *parent, GateRef glue) + : StubBuilder(parent), glue_(glue) {} + ~HashStubBuilder() override = default; + NO_MOVE_SEMANTIC(HashStubBuilder); + NO_COPY_SEMANTIC(HashStubBuilder); + void GenerateCircuit() override {} + + GateRef GetHash(GateRef key); + +private: + void CalcHashcodeForNumber(GateRef key, Variable *res, Label *exit); + + GateRef glue_; +}; +} // namespace panda::ecmascript::kungfu +#endif // ECMASCRIPT_COMPILER_HASH_STUB_BUILDER_H diff --git a/ecmascript/compiler/ic_stub_builder.cpp b/ecmascript/compiler/ic_stub_builder.cpp index f3b78ae9682ae9ffd7ee47f6a02e4b6e8e7fc36b..04d56fd7b4d0785a66def44383192c6431fac9f9 100644 --- a/ecmascript/compiler/ic_stub_builder.cpp +++ b/ecmascript/compiler/ic_stub_builder.cpp @@ -13,8 +13,9 @@ * limitations under the License. */ #include "ecmascript/compiler/ic_stub_builder.h" + +#include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h" #include "ecmascript/compiler/stub_builder-inl.h" -#include "ecmascript/compiler/typed_array_stub_builder.h" namespace panda::ecmascript::kungfu { void ICStubBuilder::NamedICAccessor(Variable* cachedHandler, Label *tryICHandler) @@ -198,7 +199,7 @@ void ICStubBuilder::LoadICByValue( ValuedICAccessor(&cachedHandler, &loadWithHandler, &loadElement); Bind(&loadElement); { - GateRef handlerInfo = NumberGetInt(glue_, *cachedHandler); + GateRef handlerInfo = GetInt64OfTInt(*cachedHandler); BRANCH(IsElement(handlerInfo), &handlerInfoIsElement, &handlerInfoNotElement); Bind(&handlerInfoIsElement); { @@ -220,7 +221,7 @@ void ICStubBuilder::LoadICByValue( { GateRef hclass = LoadHClass(receiver_); GateRef jsType = GetObjectType(hclass); - TypedArrayStubBuilder typedArrayBuilder(reinterpret_cast(this)); + BuiltinsTypedArrayStubBuilder typedArrayBuilder(reinterpret_cast(this)); ret = typedArrayBuilder.LoadTypedArrayElement(glue_, receiver_, propKey_, jsType); Jump(&exit); } diff --git a/ecmascript/compiler/induction_variable_analysis.cpp b/ecmascript/compiler/induction_variable_analysis.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b05f62e87bd7fa6d114c5126415fddf7c975ab62 --- /dev/null +++ b/ecmascript/compiler/induction_variable_analysis.cpp @@ -0,0 +1,245 @@ +/* + * 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. + */ + +#include "ecmascript/compiler/induction_variable_analysis.h" + +namespace panda::ecmascript::kungfu { + +bool InductionVariableAnalysis::IsIntConstant(GateRef gate) const +{ + if (acc_.GetOpCode(gate) != OpCode::CONSTANT) { + return false; + } + JSTaggedValue value(acc_.GetConstantValue(gate)); + return value.IsInt(); +} + +bool InductionVariableAnalysis::IsInductionVariable(GateRef gate) const +{ + if (acc_.GetOpCode(gate) != OpCode::VALUE_SELECTOR) { + return false; + } + size_t numValueIn = acc_.GetNumValueIn(gate); + GateRef startGate = acc_.GetValueIn(gate, 0); + GateRef valueGate = acc_.GetValueIn(gate, 1); + if (!IsIntConstant(startGate)) { + return false; + } + if (acc_.GetOpCode(valueGate) != OpCode::TYPED_BINARY_OP) { + return false; + } + TypedBinOp binOp = acc_.GetTypedBinaryOp(valueGate); + if (binOp != TypedBinOp::TYPED_ADD && binOp != TypedBinOp::TYPED_SUB) { + return false; + } + TypedBinaryAccessor accessor(acc_.TryGetValue(valueGate)); + const ParamType paramType = accessor.GetParamType(); + if (!paramType.IsIntType()) { + return false; + } + + for (size_t i = 2; i < numValueIn; i++) { // 2: skip startGate and valueGate + if (acc_.GetValueIn(gate, i) != valueGate) { + return false; + } + } + + // check if value satisfies a = a + x + if (acc_.GetValueIn(valueGate, 0) != gate && acc_.GetValueIn(valueGate, 1) != gate) { + return false; + } + GateRef stride = acc_.GetValueIn(valueGate, 1); + if (acc_.GetValueIn(valueGate, 0) != gate) { + stride = acc_.GetValueIn(valueGate, 0); + } + if (!IsIntConstant(stride)) { + return false; + } + return true; +} + +std::pair InductionVariableAnalysis::GetStartAndStride(GateRef gate) const +{ + ASSERT(acc_.GetOpCode(gate) == OpCode::VALUE_SELECTOR); + GateRef startGate = acc_.GetValueIn(gate, 0); + ASSERT(IsIntConstant(startGate)); + auto start = GetIntFromTaggedConstant(startGate); + + GateRef valueGate = acc_.GetValueIn(gate, 1); + ASSERT(acc_.GetOpCode(valueGate) == OpCode::TYPED_BINARY_OP); + [[maybe_unused]]TypedBinOp binOp = acc_.GetTypedBinaryOp(valueGate); + ASSERT(binOp == TypedBinOp::TYPED_ADD || binOp == TypedBinOp::TYPED_SUB); + TypedBinaryAccessor accessor(acc_.TryGetValue(valueGate)); + [[maybe_unused]]const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.IsIntType()); + + GateRef strideGate = acc_.GetValueIn(valueGate, 1); + if (acc_.GetValueIn(valueGate, 0) != gate) { + strideGate = acc_.GetValueIn(valueGate, 0); + } + ASSERT(IsIntConstant(strideGate)); + auto stride = GetIntFromTaggedConstant(strideGate); + + // a - xb < c -> a + (-x)b < c + if (acc_.GetTypedBinaryOp(valueGate) == TypedBinOp::TYPED_SUB) { + stride = -stride; + } + + return std::make_pair(start, stride); +} + +int32_t InductionVariableAnalysis::GetIntFromTaggedConstant(GateRef gate) const +{ + ASSERT(acc_.GetOpCode(gate) == OpCode::CONSTANT); + JSTaggedValue value(acc_.GetConstantValue(gate)); + return value.GetInt(); +} + +bool InductionVariableAnalysis::IsLessOrGreaterCmp(GateRef gate) const +{ + return acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_GREATEREQ || + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_GREATER || + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_LESSEQ || + acc_.GetTypedBinaryOp(gate) == TypedBinOp::TYPED_LESS; +} + +bool InductionVariableAnalysis::TryGetLoopTimes(const GraphLinearizer::LoopInfo& loop, int32_t& loopTimes) const +{ + if (loop.loopExits->size() > 1) { + return false; + } + ASSERT(loop.loopExits->size() == 1); + GateRef loopExit = loop.loopExits->at(0)->GetState(); + ASSERT(acc_.GetOpCode(loopExit) == OpCode::IF_TRUE || acc_.GetOpCode(loopExit) == OpCode::IF_FALSE); + GateRef conditionJump = acc_.GetState(loopExit); + GateRef cmp = acc_.GetValueIn(conditionJump); + if (acc_.GetOpCode(cmp) != OpCode::TYPED_BINARY_OP || !IsLessOrGreaterCmp(cmp)) { + return false; + } + GateRef limitGate = acc_.GetValueIn(cmp, 1); + if (!IsIntConstant(limitGate)) { + return false; + } + int32_t limit = GetIntFromTaggedConstant(limitGate); + + GateRef selector = acc_.GetValueIn(cmp, 0); + if (!IsInductionVariable(selector)) { + return false; + } + + auto [start, stride] = GetStartAndStride(selector); + + bool cmpFlag = (acc_.GetOpCode(loopExit) == OpCode::IF_TRUE) ^ + (acc_.GetTypedJumpAccessor(conditionJump).GetTypedJumpOp() == TypedJumpOp::TYPED_JEQZ) ^ + (acc_.GetTypedBinaryOp(cmp) == TypedBinOp::TYPED_LESSEQ || + acc_.GetTypedBinaryOp(cmp) == TypedBinOp::TYPED_LESS); + bool equalFlag = (acc_.GetOpCode(loopExit) == OpCode::IF_TRUE) ^ + (acc_.GetTypedJumpAccessor(conditionJump).GetTypedJumpOp() == TypedJumpOp::TYPED_JEQZ) ^ + (acc_.GetTypedBinaryOp(cmp) == TypedBinOp::TYPED_GREATEREQ || + acc_.GetTypedBinaryOp(cmp) == TypedBinOp::TYPED_LESSEQ); + + // a + xb >= c -> c - xb <= a + if (!cmpFlag) { + std::swap(start, limit); + stride = -stride; + } + // a + xb < c -> a + xb <= c - 1 + if (!equalFlag) { + limit--; + } + if (start > limit) { + loopTimes = 0; + return true; + } + loopTimes = (limit - start) / stride + 1; + if (IsLogEnabled() && IsTraced()) { + LOG_COMPILER(INFO) << "loopTimes: "<< loopTimes << " start: " << start + << " stride: " << stride << " limit: " << limit; + } + return true; +} + +void InductionVariableAnalysis::CollectInductionSelector() +{ + for (const auto &loop : graphLinearizer_.loops_) { + int32_t loopTimes = 0; + + if (TryGetLoopTimes(loop, loopTimes)) { + ReplaceInductionVariable(loop, loopTimes); + } + } +} + +void InductionVariableAnalysis::ReplaceInductionVariable(const GraphLinearizer::LoopInfo& loop, + const int32_t loopTimes) +{ + GateRef loopBegin = loop.loopHead->GetState(); + auto uses = acc_.Uses(loopBegin); + for (auto it = uses.begin(); it != uses.end(); it++) { + if (acc_.GetOpCode(*it) == OpCode::VALUE_SELECTOR) { + ASSERT(acc_.GetState(*it) == loopBegin); + if (!IsInductionVariable(*it)) { + continue; + } + auto [start, stride] = GetStartAndStride(*it); + int64_t result = start + static_cast(stride) * loopTimes; + if (result > static_cast(INT_MAX) || result < static_cast(INT_MIN)) { + return; + } + if (IsLogEnabled() && IsTraced()) { + LOG_COMPILER(INFO) << "result = " << start << " + " << stride << " * " + << loopTimes << " = " << result; + } + TryReplaceOutOfLoopUses(*it, loop, static_cast(result)); + } + } +} + +void InductionVariableAnalysis::TryReplaceOutOfLoopUses(GateRef gate, + const GraphLinearizer::LoopInfo& loop, + const int32_t result) +{ + ASSERT(IsInductionVariable(gate)); + auto uses = acc_.Uses(gate); + for (auto it = uses.begin(); it != uses.end();) { + auto region = graphLinearizer_.GateToRegion(*it); + if (!loop.loopBodys->TestBit(region->GetId()) && loop.loopHead != region) { + GateRef constantValue = builder_.Int32(result); + it = acc_.ReplaceIn(it, constantValue); + } else { + it++; + } + } +} + +void InductionVariableAnalysis::Run() +{ + graphLinearizer_.SetScheduleJSOpcode(); + graphLinearizer_.LinearizeGraph(); + CollectInductionSelector(); + if (IsLogEnabled()) { + LOG_COMPILER(INFO) << ""; + LOG_COMPILER(INFO) << "\033[34m" + << "====================" + << " After Induction Variable Analysis " + << "[" << GetMethodName() << "]" + << "====================" + << "\033[0m"; + circuit_->PrintAllGatesWithBytecode(); + LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m"; + } +} + +} \ No newline at end of file diff --git a/ecmascript/compiler/induction_variable_analysis.h b/ecmascript/compiler/induction_variable_analysis.h new file mode 100644 index 0000000000000000000000000000000000000000..5c2077b3198d010d265c14b80bcbb2c318fea368 --- /dev/null +++ b/ecmascript/compiler/induction_variable_analysis.h @@ -0,0 +1,67 @@ +/* + * 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. + */ + +#ifndef ECMASCRIPT_COMPILER_INDUCTION_VARIABLE_ANALYSIS_H +#define ECMASCRIPT_COMPILER_INDUCTION_VARIABLE_ANALYSIS_H + +#include "ecmascript/compiler/circuit_builder.h" +#include "ecmascript/compiler/graph_linearizer.h" +#include "ecmascript/compiler/pass_manager.h" + +namespace panda::ecmascript::kungfu { +class InductionVariableAnalysis { +public: + InductionVariableAnalysis(Circuit* circuit, PassContext* ctx, bool enableLog, + const std::string& name, Chunk* chunk, bool isTraced) + : enableLog_(enableLog), methodName_(name), circuit_(circuit), + builder_(circuit, ctx->GetCompilerConfig()), acc_(circuit), + graphLinearizer_(circuit, enableLog, name, chunk, false, true), isTraced_(isTraced) {} + + void Run(); +private: + bool IsLogEnabled() const + { + return enableLog_; + } + + bool IsTraced() const + { + return isTraced_; + } + + const std::string& GetMethodName() const + { + return methodName_; + } + bool IsIntConstant(GateRef gate) const; + bool IsInductionVariable(GateRef gate) const; + bool IsLessOrGreaterCmp(GateRef gate) const; + std::pair GetStartAndStride(GateRef gate) const; + bool TryGetLoopTimes(const GraphLinearizer::LoopInfo& loop, int32_t& loopTimes) const; + int32_t GetIntFromTaggedConstant(GateRef gate) const; + void CollectInductionSelector(); + void TryReplaceOutOfLoopUses(GateRef gate, const GraphLinearizer::LoopInfo& loop, const int32_t result); + void ReplaceInductionVariable(const GraphLinearizer::LoopInfo& loop, const int32_t loopTimes); + bool enableLog_ {false}; + std::string methodName_; + Circuit* circuit_ {nullptr}; + CircuitBuilder builder_; + GateAccessor acc_; + GraphLinearizer graphLinearizer_; + bool isTraced_; +}; + +} +#endif \ No newline at end of file diff --git a/ecmascript/compiler/interpreter_stub.cpp b/ecmascript/compiler/interpreter_stub.cpp index 1cf48e5f855f36f0ecc55b9f4e3887ae224dbdb3..48b1d87b811101336bfdb42d82a00be717620802 100644 --- a/ecmascript/compiler/interpreter_stub.cpp +++ b/ecmascript/compiler/interpreter_stub.cpp @@ -221,6 +221,127 @@ void name##StubBuilder::GenerateCircuitImpl(GateRef glue, GateRef sp, GateRef pc } \ Bind(&NeedCallRuntimeFalse) +#define TRY_OSR() \ + DEFVARIABLE(varOsrCache, VariableType::NATIVE_POINTER(), Undefined()); \ + DEFVARIABLE(varMachineCodeOffset, VariableType::JS_ANY(), Undefined()); \ + DEFVARIABLE(varMachineCode, VariableType::NATIVE_POINTER(), Undefined()); \ + Label getOsrCache(env); \ + Label getMachineCode(env); \ + Label checkDeOptFlag(env); \ + Label checkExecCount(env); \ + Label clearMachineCode(env); \ + Label executeBCByAOT(env); \ + Label executeBCByInterpreter(env); \ + GateRef curFrame = GetFrame(sp); \ + GateRef curFunction = GetFunctionFromFrame(curFrame); \ + GateRef curMethod = Load(VariableType::JS_ANY(), curFunction, IntPtr(JSFunctionBase::METHOD_OFFSET)); \ + Branch(TaggedIsUndefined(profileTypeInfo), &executeBCByInterpreter, &getOsrCache); \ + Bind(&getOsrCache); \ + { \ + GateRef profileTypeInfoLength = GetLengthOfTaggedArray(profileTypeInfo); \ + GateRef typeInfoNum = Int32Sub(profileTypeInfoLength, Int32(ProfileTypeInfo::EXTRA_CACHE_SLOT_INDEX)); \ + GateRef relativeOffset = PtrMul(ZExtInt32ToPtr(typeInfoNum), IntPtr(JSTaggedValue::TaggedTypeSize())); \ + GateRef osrCacheOffset = PtrAdd(relativeOffset, IntPtr(TaggedArray::DATA_OFFSET)); \ + varOsrCache = Load(VariableType::NATIVE_POINTER(), profileTypeInfo, osrCacheOffset); \ + Branch(TaggedIsUndefinedOrNull(*varOsrCache), &executeBCByInterpreter, &getMachineCode); \ + } \ + Bind(&getMachineCode); \ + { \ + DEFVARIABLE(varIndex, VariableType::INT32(), Int32(0)); \ + Label traverseOsrCache(env); \ + Label compareOffset(env); \ + Label addIndex(env); \ + Label traverseOsrCacheAgain(env); \ + GateRef fistPC = Load(VariableType::NATIVE_POINTER(), curMethod, \ + IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET)); \ + GateRef jmpOffsetInFunc = TruncPtrToInt32(PtrSub(pc, fistPC)); \ + GateRef length = GetLengthOfTaggedArray(*varOsrCache); \ + Branch(Int32LessThan(*varIndex, length), &traverseOsrCache, &executeBCByInterpreter); \ + LoopBegin(&traverseOsrCache); \ + { \ + GateRef relativeOffset = PtrMul(ZExtInt32ToPtr(*varIndex), IntPtr(JSTaggedValue::TaggedTypeSize())); \ + varMachineCodeOffset = PtrAdd(relativeOffset, IntPtr(TaggedArray::DATA_OFFSET)); \ + varMachineCode = Load(VariableType::NATIVE_POINTER(), *varOsrCache, *varMachineCodeOffset); \ + Branch(TaggedIsUndefinedOrNull(*varMachineCode), &addIndex, &compareOffset); \ + Bind(&compareOffset); \ + { \ + GateRef offsetField = Load(VariableType::INT32(), *varMachineCode, \ + IntPtr(MachineCode::INS_SIZE_OFFSET)); \ + Branch(Int32Equal(jmpOffsetInFunc, offsetField), &checkExecCount, &addIndex); \ + } \ + Bind(&addIndex); \ + { \ + varIndex = Int32Add(*varIndex, Int32(1)); \ + varMachineCode = NullPtr(); \ + Branch(Int32LessThan(*varIndex, length), &traverseOsrCacheAgain, &executeBCByInterpreter); \ + } \ + Bind(&traverseOsrCacheAgain); \ + } \ + LoopEnd(&traverseOsrCache); \ + } \ + Bind(&checkExecCount); \ + { \ + GateRef execCnt = Load(VariableType::INT16(), *varMachineCode, IntPtr(MachineCode::OSR_EXECUTE_CNT_OFFSET)); \ + Branch(Int32LessThan(ZExtInt16ToInt32(execCnt), Int32(5)), &checkDeOptFlag, &dispatch); \ + } \ + Bind(&checkDeOptFlag); \ + { \ + GateRef deOptField = Load(VariableType::INT16(), *varMachineCode, IntPtr(MachineCode::OSRMASK_OFFSET)); \ + Branch(Equal(deOptField, Int16(MachineCode::OSR_DEOPT_FLAG)), &clearMachineCode, &executeBCByAOT); \ + } \ + Bind(&clearMachineCode); \ + { \ + Store(VariableType::NATIVE_POINTER(), glue, *varOsrCache, *varMachineCodeOffset, NullPtr()); \ + Jump(&executeBCByInterpreter); \ + } \ + Bind(&executeBCByAOT); \ + { \ + DEFVARIABLE(varRetVal, VariableType::JS_ANY(), Undefined()); \ + Label fastCallOptimized(env); \ + Label callOptimized(env); \ + Label handleReturn(env); \ + Label resumeRspAndReturn(env); \ + Label resumeRspAndDispatch(env); \ + Store(VariableType::NATIVE_POINTER(), glue, curFunction, IntPtr(JSFunction::MACHINECODE_OFFSET), \ + *varMachineCode); \ + GateRef execCnt = Load(VariableType::INT16(), *varMachineCode, IntPtr(MachineCode::OSR_EXECUTE_CNT_OFFSET)); \ + GateRef newExecCnt = Int16Add(execCnt, Int16(1)); \ + Store(VariableType::INT16(), glue, *varMachineCode, IntPtr(MachineCode::OSR_EXECUTE_CNT_OFFSET), \ + newExecCnt); \ + GateRef codeAddr = Load(VariableType::NATIVE_POINTER(), *varMachineCode, \ + IntPtr(MachineCode::FUNCADDR_OFFSET)); \ + varRetVal = FastCallOptimized(glue, codeAddr, { glue, sp }); \ + Jump(&handleReturn); \ + Bind(&handleReturn); \ + { \ + GateRef prevSp = Load(VariableType::NATIVE_POINTER(), curFrame, \ + IntPtr(AsmInterpretedFrame::GetBaseOffset(env->IsArch32Bit()))); \ + GateRef prevFrame = GetFrame(prevSp); \ + GateRef prevPc = GetPcFromFrame(prevFrame); \ + Branch(IntPtrEqual(prevPc, IntPtr(0)), &resumeRspAndReturn, &resumeRspAndDispatch); \ + Bind(&resumeRspAndReturn); \ + { \ + CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndReturn), { *varRetVal, prevSp, sp}); \ + Return(); \ + } \ + Bind(&resumeRspAndDispatch); \ + { \ + GateRef prevFunction = GetFunctionFromFrame(prevFrame); \ + GateRef prevMethod = Load(VariableType::JS_ANY(), prevFunction, \ + IntPtr(JSFunctionBase::METHOD_OFFSET)); \ + GateRef prevConstpool = GetConstpoolFromMethod(prevMethod); \ + GateRef prevProfileTypeInfo = GetProfileTypeInfoFromFunction(prevFunction); \ + GateRef prevHotnessCounter = GetHotnessCounterFromMethod(prevMethod); \ + GateRef jumpSize = GetCallSizeFromFrame(prevFrame); \ + CallNGCRuntime(glue, RTSTUB_ID(ResumeRspAndDispatch), \ + {glue, sp, prevPc, prevConstpool, prevProfileTypeInfo, *varRetVal, \ + prevHotnessCounter, jumpSize}); \ + Return(); \ + } \ + } \ + } \ + Bind(&executeBCByInterpreter) + template void InterpreterStubBuilder::DebugPrintInstruction() { @@ -752,6 +873,8 @@ DECLARE_ASM_HANDLER(HandleJmpImm8) Label dispatch(env); Label slowPath(env); + TRY_OSR(); + UPDATE_HOTNESS(sp, callback); DISPATCH_BAK(JUMP, SExtInt32ToPtr(offset)); } @@ -766,6 +889,8 @@ DECLARE_ASM_HANDLER(HandleJmpImm16) Label dispatch(env); Label slowPath(env); + TRY_OSR(); + UPDATE_HOTNESS(sp, callback); DISPATCH_BAK(JUMP, SExtInt32ToPtr(offset)); } @@ -779,6 +904,9 @@ DECLARE_ASM_HANDLER(HandleJmpImm32) GateRef offset = ReadInstSigned32_0(pc); Label dispatch(env); Label slowPath(env); + + TRY_OSR(); + UPDATE_HOTNESS(sp, callback); DISPATCH_BAK(JUMP, SExtInt32ToPtr(offset)); } @@ -4999,10 +5127,13 @@ DECLARE_ASM_HANDLER(HandleDefineFieldByNameImm8Id16V8) Label icPath(env); Label slowPath(env); Label exit(env); + Label isEcmaObj(env); // hclass hit -> ic path Label tryGetHclass(env); Label firstValueHeapObject(env); Label hclassNotHit(env); + BRANCH(IsEcmaObject(receiver), &isEcmaObj, &slowPath); + Bind(&isEcmaObj); BRANCH(TaggedIsUndefined(profileTypeInfo), &hclassNotHit, &tryGetHclass); Bind(&tryGetHclass); { diff --git a/ecmascript/compiler/ir_builder.h b/ecmascript/compiler/ir_builder.h index f6e712cfc8e7867c9ec43bb0c97d115c2b23f1ea..584a7dca93d131dc95323b315aeb679e2a296ebf 100644 --- a/ecmascript/compiler/ir_builder.h +++ b/ecmascript/compiler/ir_builder.h @@ -102,10 +102,19 @@ enum class CallExceptionKind : bool { V(MulWithOverflow, (GateRef gate, GateRef e1, GateRef e2)) \ V(ExtractValue, (GateRef gate, GateRef e1, GateRef e2)) \ V(Sqrt, (GateRef gate, GateRef e1)) \ + V(Exp, (GateRef gate, GateRef e1, GateRef e2)) \ + V(Abs, (GateRef gate, GateRef e1)) \ + V(Min, (GateRef gate, GateRef e1, GateRef e2)) \ + V(Max, (GateRef gate, GateRef e1, GateRef e2)) \ + V(Clz32, (GateRef gate, GateRef e1)) \ + V(DoubleTrunc, (GateRef gate, GateRef e1)) \ + V(Ceil, (GateRef gate, GateRef e1)) \ + V(Floor, (GateRef gate, GateRef e1)) \ V(ReadSp, (GateRef gate)) \ + V(InitVreg, (GateRef gate)) \ V(FinishAllocate, (GateRef gate, GateRef e1)) bool IsAddIntergerType(MachineType machineType); bool IsMulIntergerType(MachineType machineType); } // namespace panda::ecmascript::kungfu -#endif // ECMASCRIPT_COMPILER_IR_BUILDER_H \ No newline at end of file +#endif // ECMASCRIPT_COMPILER_IR_BUILDER_H diff --git a/ecmascript/compiler/jit_compiler.cpp b/ecmascript/compiler/jit_compiler.cpp index ca56ede8dd7d1253d287ffa109e902329c86f0d4..b2497dc9371cf40d31ae2bfa4020c7864bfc0149 100644 --- a/ecmascript/compiler/jit_compiler.cpp +++ b/ecmascript/compiler/jit_compiler.cpp @@ -25,15 +25,14 @@ #include "ecmascript/platform/file.h" namespace panda::ecmascript::kungfu { -JitCompiler *JitCompiler::GetInstance(EcmaVM *vm) +JitCompiler *JitCompiler::GetInstance(JSRuntimeOptions *options) { - static JitCompiler instance(vm); + static JitCompiler instance(options); return &instance; } -JitCompilationOptions::JitCompilationOptions(EcmaVM *vm) +JitCompilationOptions::JitCompilationOptions(JSRuntimeOptions runtimeOptions) { - JSRuntimeOptions &runtimeOptions = vm->GetJSOptions(); #if defined(PANDA_TARGET_AMD64) triple_ = TARGET_X64; #elif defined(PANDA_TARGET_ARM64) @@ -47,6 +46,7 @@ JitCompilationOptions::JitCompilationOptions(EcmaVM *vm) logOption_ = runtimeOptions.GetCompilerLogOption(); logMethodsList_ = runtimeOptions.GetMethodsListForLog(); compilerLogTime_ = runtimeOptions.IsEnableCompilerLogTime(); + deviceIsScreenOff_ = runtimeOptions.GetDeviceState(); hotnessThreshold_ = runtimeOptions.GetPGOHotnessThreshold(); profilerIn_ = std::string(runtimeOptions.GetPGOProfilerPath()); isEnableArrayBoundsCheckElimination_ = runtimeOptions.IsEnableArrayBoundsCheckElimination(); @@ -57,7 +57,7 @@ JitCompilationOptions::JitCompilationOptions(EcmaVM *vm) isEnableOptInlining_ = runtimeOptions.IsEnableOptInlining(); isEnableOptString_ = runtimeOptions.IsEnableOptString(); isEnableTypeInfer_ = - isEnableTypeLowering_ || vm->GetJSThread()->GetCurrentEcmaContext()->GetTSManager()->AssertTypes(); + isEnableTypeLowering_ || runtimeOptions.AssertTypes(); isEnableOptPGOType_ = runtimeOptions.IsEnableOptPGOType(); isEnableOptTrackField_ = runtimeOptions.IsEnableOptTrackField(); isEnableOptLoopPeeling_ = runtimeOptions.IsEnableOptLoopPeeling(); @@ -70,13 +70,14 @@ JitCompilationOptions::JitCompilationOptions(EcmaVM *vm) isEnableLoweringBuiltin_ = runtimeOptions.IsEnableLoweringBuiltin(); } -void JitCompiler::Init(EcmaVM *vm) +void JitCompiler::Init(JSRuntimeOptions runtimeOptions) { BytecodeStubCSigns::Initialize(); CommonStubCSigns::Initialize(); + BuiltinsStubCSigns::Initialize(); RuntimeStubCSigns::Initialize(); - JitCompilationOptions jitOptions(vm); + JitCompilationOptions jitOptions(runtimeOptions); jitOptions_ = jitOptions; PassOptions::Builder optionsBuilder; passOptions_ = @@ -134,7 +135,7 @@ bool JitCompilerTask::Compile() return false; } jitCodeGenerator_.reset(aotFileGenerator); - return passManager_->Compile(jsFunction_, *jitCodeGenerator_); + return passManager_->Compile(jsFunction_, *jitCodeGenerator_, offset_); } bool JitCompilerTask::Finalize(JitTask *jitTask) @@ -148,13 +149,10 @@ bool JitCompilerTask::Finalize(JitTask *jitTask) return true; } -void InitJitCompiler(EcmaVM *vm) +void InitJitCompiler(JSRuntimeOptions options) { - if (vm == nullptr) { - return; - } - JitCompiler *jitCompiler = JitCompiler::GetInstance(vm); - jitCompiler->Init(vm); + JitCompiler *jitCompiler = JitCompiler::GetInstance(&options); + jitCompiler->Init(options); } void *CreateJitCompilerTask(JitTask *jitTask) diff --git a/ecmascript/compiler/jit_compiler.h b/ecmascript/compiler/jit_compiler.h index 31948eaea360bd29c5589115bcaaad1b274dc59e..4a29a1722ba6347d0d3ccd883e62bb211906765d 100644 --- a/ecmascript/compiler/jit_compiler.h +++ b/ecmascript/compiler/jit_compiler.h @@ -22,7 +22,7 @@ namespace panda::ecmascript::kungfu { extern "C" { -PUBLIC_API void InitJitCompiler(EcmaVM *vm); +PUBLIC_API void InitJitCompiler(JSRuntimeOptions options); PUBLIC_API void *CreateJitCompilerTask(JitTask *jitTask); PUBLIC_API bool JitCompile(void *compiler, JitTask *jitTask); PUBLIC_API bool JitFinalize(void *compiler, JitTask *jitTask); @@ -30,7 +30,7 @@ PUBLIC_API void DeleteJitCompile(void *handle); }; struct JitCompilationOptions { - JitCompilationOptions(EcmaVM *vm); + JitCompilationOptions(JSRuntimeOptions options); JitCompilationOptions() = default; std::string triple_; @@ -40,6 +40,7 @@ struct JitCompilationOptions { std::string logOption_; std::string logMethodsList_; bool compilerLogTime_; + bool deviceIsScreenOff_; size_t maxAotMethodSize_; size_t maxMethodsInModule_; uint32_t hotnessThreshold_; @@ -67,7 +68,7 @@ struct JitCompilationOptions { class JitCompilerTask final { public: JitCompilerTask(JitTask *jitTask) : vm_(jitTask->GetVM()), jsFunction_(jitTask->GetJsFunction()), - passManager_(nullptr), jitCodeGenerator_(nullptr) { }; + offset_(jitTask->GetOffset()), passManager_(nullptr), jitCodeGenerator_(nullptr) { }; static JitCompilerTask *CreateJitCompilerTask(JitTask *jitTask); @@ -77,6 +78,7 @@ public: private: EcmaVM *vm_; JSHandle jsFunction_; + int32_t offset_; std::unique_ptr passManager_; // need refact AOTFileGenerator to JitCodeGenerator std::unique_ptr jitCodeGenerator_; @@ -84,14 +86,14 @@ private: class JitCompiler final { public: - explicit JitCompiler(EcmaVM *vm) : jitOptions_(vm), + explicit JitCompiler(JSRuntimeOptions *options) : jitOptions_(*options), log_(jitOptions_.logOption_), logList_(jitOptions_.logMethodsList_), profilerDecoder_(jitOptions_.profilerIn_, jitOptions_.hotnessThreshold_) { } ~JitCompiler() = default; - void Init(EcmaVM *vm); + void Init(JSRuntimeOptions options); - static JitCompiler *GetInstance(EcmaVM *vm = nullptr); + static JitCompiler *GetInstance(JSRuntimeOptions *options = nullptr); JitCompilationOptions &GetJitOptions() { return jitOptions_; diff --git a/ecmascript/compiler/lcr_circuit_builder.h b/ecmascript/compiler/lcr_circuit_builder.h index 11ea91fa0c9735b3bbf07665fe6be322ff46ef67..fec452ac1ab5d5b0713a896fc08f91dceb14ec39 100644 --- a/ecmascript/compiler/lcr_circuit_builder.h +++ b/ecmascript/compiler/lcr_circuit_builder.h @@ -16,7 +16,9 @@ #ifndef ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H #define ECMASCRIPT_COMPILER_LCR_CIRCUIT_BUILDER_H +#include "ecmascript/compiler/circuit_builder.h" #include "ecmascript/compiler/circuit_builder_helper.h" +#include "ecmascript/compiler/share_gate_meta_data.h" #include "ecmascript/mem/region.h" #include "ecmascript/method.h" @@ -74,6 +76,51 @@ GateRef CircuitBuilder::IntPtrLSL(GateRef x, GateRef y) return BinaryArithmetic(circuit_->Lsl(), ptrSize, x, y); } +GateRef CircuitBuilder::Int16ToBigEndianInt16(GateRef x) +{ + GateRef int16toint32 = ZExtInt16ToInt32(x); + GateRef high8bits = Int32LSL(Int32And(int16toint32, Int32(0x00FF)), Int32(8)); + GateRef low8bits = Int32LSR(Int32And(int16toint32, Int32(0xFF00)), Int32(8)); + return TruncInt32ToInt16(Int32Add(high8bits, low8bits)); +} + +GateRef CircuitBuilder::Int32ToBigEndianInt32(GateRef x) +{ + GateRef first8bits = Int32LSL(Int32And(x, Int32(0x000000FF)), Int32(24)); + GateRef second8bits = Int32LSL(Int32And(x, Int32(0x0000FF00)), Int32(8)); + GateRef third8bits = Int32LSR(Int32And(x, Int32(0x00FF0000)), Int32(8)); + GateRef fourth8bits = Int32LSR(Int32And(x, Int32(0xFF000000)), Int32(24)); + GateRef firstHalf = Int32Add(first8bits, second8bits); + GateRef secondHalf = Int32Add(third8bits, fourth8bits); + return Int32Add(firstHalf, secondHalf); +} + +GateRef CircuitBuilder::Int64ToBigEndianInt64(GateRef x) +{ + GateRef first8bits = Int64LSL(Int64And(x, Int64(0x00000000000000FF)), Int64(56)); + GateRef second8bits = Int64LSL(Int64And(x, Int64(0x000000000000FF00)), Int64(40)); + // 0-16bits + GateRef first16bits = Int64Add(first8bits, second8bits); + GateRef third8bits = Int64LSL(Int64And(x, Int64(0x0000000000FF0000)), Int64(24)); + GateRef fourth8bits = Int64LSL(Int64And(x, Int64(0x00000000FF000000)), Int64(8)); + // 16-32bits + GateRef second16bits = Int64Add(third8bits, fourth8bits); + // 0-32bits + GateRef firstHalf = Int64Add(first16bits, second16bits); + GateRef fifth8bits = Int64LSR(Int64And(x, Int64(0x000000FF00000000)), Int64(8)); + GateRef sixth8bits = Int64LSR(Int64And(x, Int64(0x0000FF0000000000)), Int64(24)); + //32-48bits + GateRef third16bits = Int64Add(fifth8bits, sixth8bits); + GateRef seventh8bits = Int64LSR(Int64And(x, Int64(0x00FF000000000000)), Int64(40)); + GateRef eighth8bits = Int64LSR(Int64And(x, Int64(0xFF00000000000000)), Int64(56)); + //48-64bits + GateRef fourth16bits = Int64Add(seventh8bits, eighth8bits); + //32-64bits + GateRef secondHalf = Int64Add(third16bits, fourth16bits); + //0-64bits + return Int64Add(firstHalf, secondHalf); +} + GateRef CircuitBuilder::IntPtrOr(GateRef x, GateRef y) { auto ptrsize = env_->Is32Bit() ? MachineType::I32 : MachineType::I64; @@ -208,6 +255,73 @@ GateRef CircuitBuilder::DoubleToInt(GateRef glue, GateRef x, size_t typeBits) return ret; } +GateRef CircuitBuilder::DoubleCheckINFInRangeInt32(GateRef x) +{ + Label entry(env_); + env_->SubCfgEntry(&entry); + Label exit(env_); + Label isInfinity(env_); + Label positiveInf(env_); + Label negativeInf(env_); + + DEFVALUE(result, env_, VariableType::INT32(), DoubleInRangeInt32(x)); + GateRef Max = Double(INT32_MAX); + GateRef Min = Double(INT32_MIN); + GateRef pInfinity = Double(base::POSITIVE_INFINITY); + Branch(DoubleIsINF(x), &isInfinity, &exit); + Bind(&isInfinity); + { + Branch(DoubleEqual(x, pInfinity), &positiveInf, &negativeInf); + Bind(&positiveInf); + { + result = ChangeFloat64ToInt32(Max); + Jump(&exit); + } + Bind(&negativeInf); + { + result = ChangeFloat64ToInt32(Min); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env_->SubCfgExit(); + return ret; +} + +GateRef CircuitBuilder::DoubleInRangeInt32(GateRef x) +{ + Label entry(env_); + env_->SubCfgEntry(&entry); + Label exit(env_); + Label overflow(env_); + Label checkUnderflow(env_); + Label underflow(env_); + + DEFVALUE(result, env_, VariableType::INT32(), ChangeFloat64ToInt32(x)); + GateRef Max = Double(INT32_MAX); + GateRef Min = Double(INT32_MIN); + Branch(DoubleGreaterThan(x, Max), &overflow, &checkUnderflow); + Bind(&overflow); + { + result = ChangeFloat64ToInt32(Max); + Jump(&exit); + } + Bind(&checkUnderflow); + { + Branch(DoubleLessThan(x, Min), &underflow, &exit); + Bind(&underflow); + { + result = ChangeFloat64ToInt32(Min); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env_->SubCfgExit(); + return ret; +} + GateRef CircuitBuilder::Int32ToTaggedInt(GateRef x) { GateRef val = SExtInt32ToInt64(x); diff --git a/ecmascript/compiler/lcr_opcodes.h b/ecmascript/compiler/lcr_opcodes.h index bec26557a5a91317b3e807491243a7dbdfebb8c4..520388ded6892a52b7936d6abbfe0a744434a1e2 100644 --- a/ecmascript/compiler/lcr_opcodes.h +++ b/ecmascript/compiler/lcr_opcodes.h @@ -36,14 +36,17 @@ namespace panda::ecmascript::kungfu { V(Lsr, LSR, GateFlags::NONE_FLAG, 0, 0, 2) \ V(Asr, ASR, GateFlags::NONE_FLAG, 0, 0, 2) \ V(Sqrt, SQRT, GateFlags::NO_WRITE, 0, 0, 1) \ + V(Min, MIN, GateFlags::NO_WRITE, 0, 0, 2) \ + V(Max, MAX, GateFlags::NO_WRITE, 0, 0, 2) \ V(AddWithOverflow, ADD_WITH_OVERFLOW, GateFlags::NONE_FLAG, 0, 0, 2) \ V(SubWithOverflow, SUB_WITH_OVERFLOW, GateFlags::NONE_FLAG, 0, 0, 2) \ V(MulWithOverflow, MUL_WITH_OVERFLOW, GateFlags::NONE_FLAG, 0, 0, 2) \ V(ExtractValue, EXTRACT_VALUE, GateFlags::NONE_FLAG, 0, 0, 2) - + #define LCR_UNARY_GATE_META_DATA_CACHE_LIST(V) \ V(Zext, ZEXT, GateFlags::NONE_FLAG, 0, 0, 1) \ V(Sext, SEXT, GateFlags::NONE_FLAG, 0, 0, 1) \ + V(DoubleTrunc, DOUBLE_TRUNC, GateFlags::NO_WRITE, 0, 0, 1) \ V(Trunc, TRUNC, GateFlags::NONE_FLAG, 0, 0, 1) \ V(Fext, FEXT, GateFlags::NONE_FLAG, 0, 0, 1) \ V(Ftrunc, FTRUNC, GateFlags::NONE_FLAG, 0, 0, 1) \ @@ -56,7 +59,11 @@ namespace panda::ecmascript::kungfu { V(UnsignedFloatToInt, UNSIGNED_FLOAT_TO_INT, GateFlags::NONE_FLAG, 0, 0, 1) \ V(TruncFloatToInt64, TRUNC_FLOAT_TO_INT64, GateFlags::NONE_FLAG, 0, 0, 1) \ V(TruncFloatToInt32, TRUNC_FLOAT_TO_INT32, GateFlags::NONE_FLAG, 0, 0, 1) \ - V(Bitcast, BITCAST, GateFlags::NONE_FLAG, 0, 0, 1) + V(Bitcast, BITCAST, GateFlags::NONE_FLAG, 0, 0, 1) \ + V(Abs, ABS, GateFlags::NO_WRITE, 0, 0, 1) \ + V(Clz32, CLZ32, GateFlags::NONE_FLAG, 0, 0, 1) \ + V(Ceil, CEIL, GateFlags::NO_WRITE, 0, 0, 1) \ + V(Floor, FLOOR, GateFlags::NO_WRITE, 0, 0, 1) #define LCR_IMMUTABLE_META_DATA_CACHE_LIST(V) \ V(ReadSp, READSP, GateFlags::NONE_FLAG, 0, 0, 0) \ diff --git a/ecmascript/compiler/loop_analysis.cpp b/ecmascript/compiler/loop_analysis.cpp index 81b1a63f8cad0ee3176fc91734df2f83b09bf9f7..b0b8accfaa4ce1526e0875694ba371ee516ab178 100644 --- a/ecmascript/compiler/loop_analysis.cpp +++ b/ecmascript/compiler/loop_analysis.cpp @@ -44,6 +44,9 @@ void LoopAnalysis::Run() ChunkVector& headerGates = bcBuilder_->GetLoopHeaderGates(); for (auto it = headerGates.rbegin(); it != headerGates.rend(); ++it) { auto gate = *it; + if (gate == Circuit::NullGate()) { + continue; + } auto loopInfo = chunk_->New(chunk_, gate); loopInfos_.emplace_back(loopInfo); } @@ -214,4 +217,4 @@ void LoopAnalysis::LoopExitElimination() } } } -} // namespace panda::ecmascript::kungfu \ No newline at end of file +} // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/mcr_circuit_builder.cpp b/ecmascript/compiler/mcr_circuit_builder.cpp index 9d66a4f877c7e1a05fdede12ddcc053ee61595f8..a1f70fdbb9253e7dbc80ae2add67fadb543cd71a 100644 --- a/ecmascript/compiler/mcr_circuit_builder.cpp +++ b/ecmascript/compiler/mcr_circuit_builder.cpp @@ -13,7 +13,12 @@ * limitations under the License. */ +#include "libpandabase/utils/hash.h" + #include "ecmascript/compiler/mcr_circuit_builder.h" + +#include "ecmascript/compiler/circuit_builder.h" +#include "ecmascript/compiler/share_gate_meta_data.h" #include "ecmascript/message_string.h" #include "ecmascript/stubs/runtime_stubs-inl.h" #include "ecmascript/stubs/runtime_stubs.h" @@ -25,7 +30,7 @@ namespace panda::ecmascript::kungfu { -GateRef CircuitBuilder::ObjectTypeCheck(GateType type, bool isHeapObject, GateRef gate, GateRef hclassIndex, +GateRef CircuitBuilder::ObjectTypeCheck(bool isHeapObject, GateRef gate, GateRef hclassIndex, GateRef frameState) { auto currentLabel = env_->GetCurrentLabel(); @@ -34,7 +39,7 @@ GateRef CircuitBuilder::ObjectTypeCheck(GateType type, bool isHeapObject, GateRe if (frameState == Circuit::NullGate()) { frameState = acc_.FindNearestFrameState(currentDepend); } - ObjectTypeAccessor accessor(type, isHeapObject); + ObjectTypeAccessor accessor(isHeapObject); GateRef ret = GetCircuit()->NewGate(circuit_->ObjectTypeCheck(accessor.ToValue()), MachineType::I1, {currentControl, currentDepend, gate, hclassIndex, frameState}, GateType::NJSValue()); currentLabel->SetControl(ret); @@ -177,28 +182,29 @@ GateRef CircuitBuilder::ArrayGuardianCheck(GateRef frameState) return ret; } -GateRef CircuitBuilder::TypedArrayCheck(GateRef gate, GateType type, TypedArrayMetaDateAccessor::Mode mode, +GateRef CircuitBuilder::TypedArrayCheck(GateRef gate, ParamType type, TypedArrayMetaDateAccessor::Mode mode, OnHeapMode onHeap) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.FindNearestFrameState(currentDepend); - TypedArrayMetaDateAccessor accessor(type, mode, onHeap); - GateRef ret = GetCircuit()->NewGate(circuit_->TypedArrayCheck(accessor.ToValue()), MachineType::I1, + uint64_t value = TypedArrayMetaDateAccessor::ToValue(type, mode, onHeap); + GateRef ret = GetCircuit()->NewGate(circuit_->TypedArrayCheck(value), MachineType::I1, {currentControl, currentDepend, gate, frameState}, GateType::NJSValue()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); return ret; } -GateRef CircuitBuilder::LoadTypedArrayLength(GateRef gate, GateType type, OnHeapMode onHeap) +GateRef CircuitBuilder::LoadTypedArrayLength(GateRef gate, ParamType paramType, OnHeapMode onHeap) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); - TypedArrayMetaDateAccessor accessor(type, TypedArrayMetaDateAccessor::Mode::LOAD_LENGTH, onHeap); - GateRef ret = GetCircuit()->NewGate(circuit_->LoadTypedArrayLength(accessor.ToValue()), MachineType::I64, + uint64_t value = TypedArrayMetaDateAccessor::ToValue(paramType, + TypedArrayMetaDateAccessor::Mode::LOAD_LENGTH, onHeap); + GateRef ret = GetCircuit()->NewGate(circuit_->LoadTypedArrayLength(value), MachineType::I64, {currentControl, currentDepend, gate}, GateType::IntType()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); @@ -271,25 +277,25 @@ GateRef CircuitBuilder::IndexCheck(GateRef gate, GateRef index) return ret; } -GateRef CircuitBuilder::TypeOfCheck(GateRef gate, GateType type) +GateRef CircuitBuilder::TypeOfCheck(GateRef gate, ParamType paramType) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.FindNearestFrameState(currentDepend); - GateRef ret = GetCircuit()->NewGate(circuit_->TypeOfCheck(static_cast(type.Value())), + GateRef ret = GetCircuit()->NewGate(circuit_->TypeOfCheck(static_cast(paramType.Value())), MachineType::I64, {currentControl, currentDepend, gate, frameState}, GateType::IntType()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); return ret; } -GateRef CircuitBuilder::TypedTypeOf(GateType type) +GateRef CircuitBuilder::TypedTypeOf(ParamType paramType) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); - GateRef ret = GetCircuit()->NewGate(circuit_->TypeOf(static_cast(type.Value())), + GateRef ret = GetCircuit()->NewGate(circuit_->TypeOf(static_cast(paramType.Value())), MachineType::I64, {currentControl, currentDepend}, GateType::AnyType()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); @@ -579,15 +585,15 @@ GateRef CircuitBuilder::CallTargetCheck(GateRef gate, GateRef function, GateRef return ret; } -GateRef CircuitBuilder::JSCallTargetFromDefineFuncCheck(GateType type, GateRef func, GateRef gate) +GateRef CircuitBuilder::JSCallTargetFromDefineFuncCheck(GateRef func, GateRef gate) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.GetFrameState(gate); - GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(1, static_cast(type.Value()), - TypedCallTargetCheckOp::JSCALL_IMMEDIATE_AFTER_FUNC_DEF), - MachineType::I1, {currentControl, currentDepend, func, frameState}, GateType::NJSValue()); + uint64_t value = TypedCallTargetCheckAccessor::ToValue(TypedCallTargetCheckOp::JSCALL_IMMEDIATE_AFTER_FUNC_DEF); + GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(value), MachineType::I1, + {currentControl, currentDepend, func, IntPtr(INVALID_INDEX), frameState}, GateType::NJSValue()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); return ret; @@ -712,6 +718,51 @@ GateRef CircuitBuilder::IsNotUndefinedOrHoleCheck(GateRef value) return ret; } +GateRef CircuitBuilder::IsEcmaObjectCheck(GateRef gate) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + auto frameState = acc_.FindNearestFrameState(currentDepend); + GateRef ret = GetCircuit()->NewGate(circuit_->IsEcmaObjectCheck(), + MachineType::I1, + {currentControl, currentDepend, gate, frameState}, + GateType::NJSValue()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::IsDataViewCheck(GateRef gate) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + auto frameState = acc_.FindNearestFrameState(currentDepend); + GateRef ret = GetCircuit()->NewGate(circuit_->IsDataViewCheck(), + MachineType::I1, + {currentControl, currentDepend, gate, frameState}, + GateType::NJSValue()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::IsTaggedBooleanCheck(GateRef value) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + auto frameState = acc_.FindNearestFrameState(currentDepend); + GateRef ret = GetCircuit()->NewGate(circuit_->IsTaggedBooleanCheck(), + MachineType::I1, + {currentControl, currentDepend, value, frameState}, + GateType::NJSValue()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + GateRef CircuitBuilder::ValueCheckNegOverflow(GateRef value) { auto currentLabel = env_->GetCurrentLabel(); @@ -765,18 +816,18 @@ GateRef CircuitBuilder::Int32DivWithCheck(GateRef left, GateRef right) } GateRef CircuitBuilder::TypedConditionJump(MachineType type, TypedJumpOp jumpOp, uint32_t weight, - GateType typeVal, const std::vector& inList) + ParamType paramType, const std::vector& inList) { - uint64_t value = TypedJumpAccessor::ToValue(typeVal, jumpOp, weight); + uint64_t value = TypedJumpAccessor::ToValue(paramType, jumpOp, weight); return GetCircuit()->NewGate(circuit_->TypedConditionJump(value), type, inList.size(), inList.data(), GateType::Empty()); } -GateRef CircuitBuilder::TypeConvert(MachineType type, GateType typeFrom, GateType typeTo, +GateRef CircuitBuilder::TypeConvert(MachineType type, ParamType typeFrom, GateType typeTo, const std::vector& inList) { // merge types of valueIns before and after convertion - uint64_t operandTypes = GatePairTypeAccessor::ToValue(typeFrom, typeTo); + uint64_t operandTypes = TypeConvertAccessor::ToValue(typeFrom, typeTo); return GetCircuit()->NewGate(circuit_->TypedConvert(operandTypes), type, inList.size(), inList.data(), GateType::AnyType()); } @@ -1015,17 +1066,16 @@ GateType CircuitBuilder::GetGateTypeOfValueType(ValueType type) } } -GateRef CircuitBuilder::InsertTypedBinaryop(GateRef left, GateRef right, GateType leftType, GateType rightType, - GateType gateType, PGOTypeRef pgoType, TypedBinOp op) +GateRef CircuitBuilder::InsertTypedBinaryop(GateRef left, GateRef right, TypedBinOp op) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); - uint64_t operandTypes = GatePairTypeAccessor::ToValue(leftType, rightType); - auto ret = GetCircuit()->NewGate(circuit_->TypedBinaryOp(operandTypes, op, pgoType), + uint64_t value = TypedBinaryAccessor::ToValue(ParamType::NumberType(), op); + auto ret = GetCircuit()->NewGate(circuit_->TypedBinaryOp(value), MachineType::I64, {currentControl, currentDepend, left, right}, - gateType); + GateType::AnyType()); acc_.ReplaceInAfterInsert(currentControl, currentDepend, ret); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); @@ -1038,8 +1088,8 @@ GateRef CircuitBuilder::InsertRangeCheckPredicate(GateRef left, TypedBinOp cond, auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.FindNearestFrameState(currentDepend); - TypedBinaryAccessor accessor(GateType::IntType(), cond); - auto ret = GetCircuit()->NewGate(circuit_->RangeCheckPredicate(accessor.ToValue()), + uint64_t value = TypedBinaryAccessor::ToValue(ParamType::IntType(), cond); + auto ret = GetCircuit()->NewGate(circuit_->RangeCheckPredicate(value), MachineType::I32, {currentControl, currentDepend, left, right, frameState}, GateType::IntType()); @@ -1166,6 +1216,43 @@ GateRef CircuitBuilder::GetLengthFromString(GateRef value) return Int32LSR(len, Int32(EcmaString::STRING_LENGTH_SHIFT_COUNT)); } +GateRef CircuitBuilder::Rotl(GateRef word, uint32_t shift) +{ + static constexpr uint32_t MAX_BITS = 32; + return Int32Or(Int32LSL(word, Int32(shift)), Int32LSR(word, Int32(MAX_BITS - shift))); +} + +GateRef CircuitBuilder::CalcHashcodeForInt(GateRef value) +{ + GateRef rawVal = ChangeTaggedPointerToInt64(value); + GateRef low = TruncInt64ToInt32(rawVal); + GateRef k1 = Int32Mul(low, Int32(MurmurHash32Const::C1)); + GateRef k2 = Rotl(k1, MurmurHash32Const::MAIN_FIRST_SHIFT); + GateRef k3 = Int32Mul(k2, Int32(MurmurHash32Const::C2)); + GateRef hash1 = Int32Xor(Int32(DEFAULT_SEED), k3); + GateRef hash2 = Rotl(hash1, MurmurHash32Const::MAIN_SECOND_SHIFT); + GateRef hash3 = Int32Add(Int32Mul(hash2, Int32(MurmurHash32Const::MAIN_MULTIPLICATOR)), + Int32(MurmurHash32Const::MAIN_CONSTANT)); + + GateRef high = TruncInt64ToInt32(Int64LSR(rawVal, Int64(32U))); + GateRef k4 = Int32Mul(high, Int32(MurmurHash32Const::C1)); + GateRef k5 = Rotl(k4, MurmurHash32Const::MAIN_FIRST_SHIFT); + GateRef k6 = Int32Mul(k5, Int32(MurmurHash32Const::C2)); + GateRef hash4 = Int32Xor(hash3, k6); + GateRef hash5 = Rotl(hash4, MurmurHash32Const::MAIN_SECOND_SHIFT); + GateRef hash6 = Int32Add(Int32Mul(hash5, Int32(MurmurHash32Const::MAIN_MULTIPLICATOR)), + Int32(MurmurHash32Const::MAIN_CONSTANT)); + + GateRef hash7 = Int32Xor(hash6, Int32(8U)); + // Finalize + GateRef hash8 = Int32Xor(hash7, Int32LSR(hash7, Int32(MurmurHash32Const::FINALIZE_FIRST_SHIFT))); + GateRef hash9 = Int32Mul(hash8, Int32(MurmurHash32Const::FINALIZE_FIRST_MULTIPLICATOR)); + GateRef hash10 = Int32Xor(hash9, Int32LSR(hash9, Int32(MurmurHash32Const::FINALIZE_SECOND_SHIFT))); + GateRef hash11 = Int32Mul(hash10, Int32(MurmurHash32Const::FINALIZE_SECOND_MULTIPLICATOR)); + GateRef hash12 = Int32Xor(hash11, Int32LSR(hash11, Int32(MurmurHash32Const::FINALIZE_THIRD_SHIFT))); + return hash12; +} + GateRef CircuitBuilder::GetHashcodeFromString(GateRef glue, GateRef value) { ASSERT(!GetCircuit()->IsOptimizedJSFunctionFrame()); @@ -1571,7 +1658,7 @@ GateRef CircuitBuilder::ToNumber(GateRef gate, GateRef value, GateRef glue) return ret; } -GateRef CircuitBuilder::BuildMathBuiltinOp(const GateMetaData* op, std::vector args) +GateRef CircuitBuilder::BuildControlDependOp(const GateMetaData* op, std::vector args) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); @@ -1597,6 +1684,102 @@ GateRef CircuitBuilder::StringFromSingleCharCode(GateRef gate) return ret; } +GateRef CircuitBuilder::ArrayBufferIsView(GateRef gate) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + GateRef ret = GetCircuit()->NewGate( + circuit_->ArrayBufferIsView(), MachineType::I64, {currentControl, currentDepend, gate}, GateType::AnyType()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::DataViewGet( + GateRef thisobj, GateRef index, GateRef dataViewCallID, GateRef isLittleEndian, GateRef frameState) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + GateRef ret = GetCircuit()->NewGate( + circuit_->DataViewGet(), + MachineType::I64, + {currentControl, currentDepend, thisobj, index, dataViewCallID, isLittleEndian, frameState}, + GateType::AnyType()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::DataViewSet( + GateRef thisobj, GateRef index, GateRef value, GateRef dataViewCallID, GateRef isLittleEndian, GateRef frameState) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + GateRef ret = GetCircuit()->NewGate( + circuit_->DataViewSet(), + MachineType::I64, + {currentControl, currentDepend, thisobj, index, value, dataViewCallID, isLittleEndian, frameState}, + GateType::TaggedValue()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::NumberIsFinite(GateRef gate) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + GateRef ret = + GetCircuit()->NewGate(circuit_->NumberIsFinite(), MachineType::I64, + { currentControl, currentDepend, gate }, GateType::AnyType()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::NumberIsInteger(GateRef gate) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + GateRef ret = + GetCircuit()->NewGate(circuit_->NumberIsInteger(), MachineType::I64, + { currentControl, currentDepend, gate }, GateType::AnyType()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::NumberIsNaN(GateRef gate) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + GateRef ret = + GetCircuit()->NewGate(circuit_->NumberIsNaN(), MachineType::I64, + { currentControl, currentDepend, gate }, GateType::AnyType()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + +GateRef CircuitBuilder::NumberIsSafeInteger(GateRef gate) +{ + auto currentLabel = env_->GetCurrentLabel(); + auto currentControl = currentLabel->GetControl(); + auto currentDepend = currentLabel->GetDepend(); + GateRef ret = + GetCircuit()->NewGate(circuit_->NumberIsSafeInteger(), MachineType::I64, + { currentControl, currentDepend, gate }, GateType::AnyType()); + currentLabel->SetControl(ret); + currentLabel->SetDepend(ret); + return ret; +} + GateRef CircuitBuilder::IsASCIICharacter(GateRef gate) { return Int32UnsignedLessThan(Int32Sub(gate, Int32(1)), Int32(base::utf_helper::UTF8_1B_MAX)); diff --git a/ecmascript/compiler/mcr_circuit_builder.h b/ecmascript/compiler/mcr_circuit_builder.h index 1d941309f2e136a33f62eeaea7bbfaec32c1ae22..cc2c440d18bf4a69de5661c7bb26410b401a3ef8 100644 --- a/ecmascript/compiler/mcr_circuit_builder.h +++ b/ecmascript/compiler/mcr_circuit_builder.h @@ -68,9 +68,11 @@ GateRef CircuitBuilder::TaggedObjectIsString(GateRef obj) GateRef CircuitBuilder::TaggedObjectIsShared(GateRef obj) { - GateRef objectType = GetObjectType(LoadHClass(obj)); - return BoolOr(Int32Equal(objectType, Int32(static_cast(JSType::JS_SHARED_OBJECT))), - Int32Equal(objectType, Int32(static_cast(JSType::JS_SHARED_FUNCTION)))); + GateRef bitfield = Load(VariableType::INT32(), LoadHClass(obj), IntPtr(JSHClass::BIT_FIELD_OFFSET)); + return Int32NotEqual( + Int32And(Int32LSR(bitfield, Int32(JSHClass::IsJSSharedBit::START_BIT)), + Int32((1LU << JSHClass::IsJSSharedBit::SIZE) - 1)), + Int32(0)); } GateRef CircuitBuilder::TaggedObjectBothAreString(GateRef x, GateRef y) @@ -86,6 +88,18 @@ GateRef CircuitBuilder::TaggedObjectIsEcmaObject(GateRef obj) Int32GreaterThanOrEqual(objectType, Int32(static_cast(JSType::ECMA_OBJECT_FIRST)))); } +GateRef CircuitBuilder::TaggedObjectIsByteArray(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return Int32Equal(objectType, Int32(static_cast(JSType::BYTE_ARRAY))); +} + +GateRef CircuitBuilder::TaggedObjectIsDataView(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return Int32Equal(objectType, Int32(static_cast(JSType::JS_DATA_VIEW))); +} + GateRef CircuitBuilder::IsSpecialSlicedString(GateRef obj) { GateRef objectType = GetObjectType(LoadHClass(obj)); @@ -167,7 +181,7 @@ GateRef CircuitBuilder::TaggedIsStringIterator(GateRef obj) return ret; } -GateRef CircuitBuilder::TaggedIsShared(GateRef obj) +GateRef CircuitBuilder::TaggedIsSharedObj(GateRef obj) { Label entry(env_); SubCfgEntry(&entry); @@ -569,29 +583,28 @@ inline GateRef CircuitBuilder::TypedCallBuiltin(GateRef hirGate, const std::vect } template -GateRef CircuitBuilder::TypedBinaryOp(GateRef x, GateRef y, GateType xType, GateType yType, GateType gateType, - PGOTypeRef pgoType) +GateRef CircuitBuilder::TypedBinaryOp(GateRef x, GateRef y, ParamType paramType) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); - uint64_t operandTypes = GatePairTypeAccessor::ToValue(xType, yType); - auto numberBinaryOp = GetCircuit()->NewGate(circuit_->TypedBinaryOp(operandTypes, Op, pgoType), - MachineType::I64, {currentControl, currentDepend, x, y}, gateType); + uint64_t value = TypedBinaryAccessor::ToValue(paramType, Op); + auto numberBinaryOp = GetCircuit()->NewGate(circuit_->TypedBinaryOp(value), + MachineType::I64, {currentControl, currentDepend, x, y}, GateType::AnyType()); currentLabel->SetControl(numberBinaryOp); currentLabel->SetDepend(numberBinaryOp); return numberBinaryOp; } template -GateRef CircuitBuilder::JSNoGCCallThisTargetTypeCheck(GateType type, GateRef func, GateRef methodId, GateRef gate) +GateRef CircuitBuilder::JSNoGCCallThisTargetTypeCheck(GateRef func, GateRef methodId, GateRef gate) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.GetFrameState(gate); - GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(CircuitBuilder::GATE_TWO_VALUESIN, - static_cast(type.Value()), Op), MachineType::I1, + uint64_t value = TypedCallTargetCheckAccessor::ToValue(Op); + GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(value), MachineType::I1, {currentControl, currentDepend, func, methodId, frameState}, GateType::NJSValue()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); @@ -599,14 +612,14 @@ GateRef CircuitBuilder::JSNoGCCallThisTargetTypeCheck(GateType type, GateRef fun } template -GateRef CircuitBuilder::JSCallTargetTypeCheck(GateType type, GateRef func, GateRef methodIndex, GateRef gate) +GateRef CircuitBuilder::JSCallTargetTypeCheck(GateRef func, GateRef methodIndex, GateRef gate) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.GetFrameState(gate); - GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(CircuitBuilder::GATE_TWO_VALUESIN, - static_cast(type.Value()), Op), MachineType::I1, + uint64_t value = TypedCallTargetCheckAccessor::ToValue(Op); + GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(value), MachineType::I1, {currentControl, currentDepend, func, methodIndex, frameState}, GateType::NJSValue()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); @@ -614,41 +627,42 @@ GateRef CircuitBuilder::JSCallTargetTypeCheck(GateType type, GateRef func, GateR } template -GateRef CircuitBuilder::JSCallThisTargetTypeCheck(GateType type, GateRef func, GateRef gate) +GateRef CircuitBuilder::JSCallThisTargetTypeCheck(GateRef func, GateRef gate) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto frameState = acc_.GetFrameState(gate); - GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(1, static_cast(type.Value()), Op), - MachineType::I1, {currentControl, currentDepend, func, frameState}, GateType::NJSValue()); + uint64_t value = TypedCallTargetCheckAccessor::ToValue(Op); + GateRef ret = GetCircuit()->NewGate(circuit_->TypedCallTargetCheckOp(value), MachineType::I1, + {currentControl, currentDepend, func, IntPtr(INVALID_INDEX), frameState}, GateType::NJSValue()); currentLabel->SetControl(ret); currentLabel->SetDepend(ret); return ret; } template -GateRef CircuitBuilder::TypedUnaryOp(GateRef x, GateType xType, GateType gateType) +GateRef CircuitBuilder::TypedUnaryOp(GateRef x, ParamType paramType) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); - uint64_t value = TypedUnaryAccessor::ToValue(xType, Op); + uint64_t value = TypedUnaryAccessor::ToValue(paramType, Op); auto numberUnaryOp = GetCircuit()->NewGate(circuit_->TypedUnaryOp(value), - MachineType::I64, {currentControl, currentDepend, x}, gateType); + MachineType::I64, {currentControl, currentDepend, x}, GateType::AnyType()); currentLabel->SetControl(numberUnaryOp); currentLabel->SetDepend(numberUnaryOp); return numberUnaryOp; } template -GateRef CircuitBuilder::TypedConditionJump(GateRef x, GateType xType, uint32_t weight) +GateRef CircuitBuilder::TypedConditionJump(GateRef x, ParamType paramType, uint32_t weight) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); auto machineType = MachineType::NOVALUE; - auto jumpOp = TypedConditionJump(machineType, Op, weight, xType, {currentControl, currentDepend, x}); + auto jumpOp = TypedConditionJump(machineType, Op, weight, paramType, {currentControl, currentDepend, x}); currentLabel->SetControl(jumpOp); currentLabel->SetDepend(jumpOp); return jumpOp; @@ -682,12 +696,13 @@ GateRef CircuitBuilder::StoreElement(GateRef receiver, GateRef index, GateRef va return ret; } -GateRef CircuitBuilder::PrimitiveToNumber(GateRef x, VariableType type) +GateRef CircuitBuilder::PrimitiveToNumber(GateRef x, ParamType paramType) { auto currentLabel = env_->GetCurrentLabel(); auto currentControl = currentLabel->GetControl(); auto currentDepend = currentLabel->GetDepend(); - auto numberconvert = TypeConvert(MachineType::I64, type.GetGateType(), GateType::NumberType(), + + auto numberconvert = TypeConvert(MachineType::I64, paramType, GateType::NumberType(), {currentControl, currentDepend, x}); currentLabel->SetControl(numberconvert); currentLabel->SetDepend(numberconvert); diff --git a/ecmascript/compiler/mcr_gate_meta_data.cpp b/ecmascript/compiler/mcr_gate_meta_data.cpp index b4ee551e859aaa19374ef4e01eac0652b079a2a4..3294cc5a1ee77ec8aea24bad430e2568726a0686 100644 --- a/ecmascript/compiler/mcr_gate_meta_data.cpp +++ b/ecmascript/compiler/mcr_gate_meta_data.cpp @@ -18,49 +18,6 @@ #include "ecmascript/compiler/gate_meta_data_builder.h" namespace panda::ecmascript::kungfu { - -TypedBinOp TypedBinaryMetaData::GetRevCompareOp(TypedBinOp op) -{ - switch (op) { - case TypedBinOp::TYPED_LESS: - return TypedBinOp::TYPED_GREATEREQ; - case TypedBinOp::TYPED_LESSEQ: - return TypedBinOp::TYPED_GREATER; - case TypedBinOp::TYPED_GREATER: - return TypedBinOp::TYPED_LESSEQ; - case TypedBinOp::TYPED_GREATEREQ: - return TypedBinOp::TYPED_LESS; - case TypedBinOp::TYPED_EQ: - return TypedBinOp::TYPED_NOTEQ; - case TypedBinOp::TYPED_NOTEQ: - return TypedBinOp::TYPED_EQ; - default: - UNREACHABLE(); - return op; - } -} - -TypedBinOp TypedBinaryMetaData::GetSwapCompareOp(TypedBinOp op) -{ - switch (op) { - case TypedBinOp::TYPED_LESS: - return TypedBinOp::TYPED_GREATER; - case TypedBinOp::TYPED_LESSEQ: - return TypedBinOp::TYPED_GREATEREQ; - case TypedBinOp::TYPED_GREATER: - return TypedBinOp::TYPED_LESS; - case TypedBinOp::TYPED_GREATEREQ: - return TypedBinOp::TYPED_LESSEQ; - case TypedBinOp::TYPED_EQ: - return TypedBinOp::TYPED_EQ; - case TypedBinOp::TYPED_NOTEQ: - return TypedBinOp::TYPED_NOTEQ; - default: - UNREACHABLE(); - return op; - } -} - bool GateMetaData::IsTypedOperator() const { return (opcode_ == OpCode::TYPED_BINARY_OP) || (opcode_ == OpCode::TYPE_CONVERT) || @@ -172,4 +129,4 @@ std::string GateMetaData::Str(ValueType type) } return "UNKNOW"; } -} \ No newline at end of file +} diff --git a/ecmascript/compiler/mcr_gate_meta_data.h b/ecmascript/compiler/mcr_gate_meta_data.h index 01edc75ac8631107d5f6c7e299f36fb5e6c4e2bb..4e043159914870912e2c49d255c446096541b470 100644 --- a/ecmascript/compiler/mcr_gate_meta_data.h +++ b/ecmascript/compiler/mcr_gate_meta_data.h @@ -204,100 +204,15 @@ private: bool noGC_; }; -class TypedCallTargetCheckMetaData : public OneParameterMetaData { -public: - TypedCallTargetCheckMetaData(uint32_t valuesIn, uint64_t value, TypedCallTargetCheckOp checkOp) - : OneParameterMetaData(OpCode::TYPED_CALLTARGETCHECK_OP, GateFlags::CHECKABLE, 1, 1, valuesIn, value), - checkOp_(checkOp) - { - SetKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP); - } - - bool equal(const GateMetaData &other) const override - { - if (!OneParameterMetaData::equal(other)) { - return false; - } - auto cast_other = - static_cast(&other); - if (checkOp_ == cast_other->checkOp_) { - return true; - } - return false; - } - - static const TypedCallTargetCheckMetaData* Cast(const GateMetaData* meta) - { - meta->AssertKind(GateMetaData::Kind::TYPED_CALLTARGETCHECK_OP); - return static_cast(meta); - } - - TypedCallTargetCheckOp GetTypedCallTargetCheckOp() const - { - return checkOp_; - } -private: - TypedCallTargetCheckOp checkOp_; -}; - -class TypedBinaryMetaData : public OneParameterMetaData { -public: - TypedBinaryMetaData(uint64_t value, TypedBinOp binOp, PGOTypeRef type) - : OneParameterMetaData(OpCode::TYPED_BINARY_OP, GateFlags::NO_WRITE, 1, 1, 2, value), // 2: valuesIn - binOp_(binOp), type_(type) - { - SetKind(GateMetaData::Kind::TYPED_BINARY_OP); - } - - bool equal(const GateMetaData &other) const override - { - if (!OneParameterMetaData::equal(other)) { - return false; - } - auto cast_other = static_cast(&other); - if (binOp_ == cast_other->binOp_ && type_ == cast_other->type_) { - return true; - } - return false; - } - - static const TypedBinaryMetaData* Cast(const GateMetaData* meta) - { - meta->AssertKind(GateMetaData::Kind::TYPED_BINARY_OP); - return static_cast(meta); - } - - TypedBinOp GetTypedBinaryOp() const - { - return binOp_; - } - - PGOTypeRef GetType() const - { - return type_; - } - - std::string Str() const - { - return GateMetaData::Str(binOp_); - } - - static TypedBinOp GetRevCompareOp(TypedBinOp op); - static TypedBinOp GetSwapCompareOp(TypedBinOp op); -private: - TypedBinOp binOp_; - PGOTypeRef type_; -}; - class TypedUnaryAccessor { public: // type bits shift static constexpr int OPRAND_TYPE_BITS = 32; explicit TypedUnaryAccessor(uint64_t value) : bitField_(value) {} - GateType GetTypeValue() const + ParamType GetParamType() const { - return GateType(TypedValueBits::Get(bitField_)); + return ParamType(TypedValueBits::Get(bitField_)); } TypedUnOp GetTypedUnOp() const @@ -305,10 +220,9 @@ public: return TypedUnOpBits::Get(bitField_); } - static uint64_t ToValue(GateType typeValue, TypedUnOp unaryOp) + static uint64_t ToValue(ParamType paramType, TypedUnOp unaryOp) { - return TypedValueBits::Encode(typeValue.Value()) - | TypedUnOpBits::Encode(unaryOp); + return TypedValueBits::Encode(paramType.Value()) | TypedUnOpBits::Encode(unaryOp); } private: @@ -323,14 +237,10 @@ public: // type bits shift static constexpr int OPRAND_TYPE_BITS = 32; explicit TypedBinaryAccessor(uint64_t value) : bitField_(value) {} - explicit TypedBinaryAccessor(GateType gate, TypedBinOp binOp) - { - bitField_ = TypedValueBits::Encode(gate.Value()) | TypedBinOpBits::Encode(binOp); - } - GateType GetTypeValue() const + ParamType GetParamType() const { - return GateType(TypedValueBits::Get(bitField_)); + return ParamType(TypedValueBits::Get(bitField_)); } TypedBinOp GetTypedBinOp() const @@ -338,9 +248,9 @@ public: return TypedBinOpBits::Get(bitField_); } - uint64_t ToValue() const + static uint64_t ToValue(ParamType operandType, TypedBinOp binOp) { - return bitField_; + return TypedValueBits::Encode(operandType.Value()) | TypedBinOpBits::Encode(binOp); } private: @@ -350,6 +260,28 @@ private: uint64_t bitField_; }; +class TypedCallTargetCheckAccessor { +public: + // type bits shift + static constexpr int CALLTARGETCHECK_OP_BITS = 32; + explicit TypedCallTargetCheckAccessor(uint64_t value) : bitField_(value) {} + + TypedCallTargetCheckOp GetCallTargetCheckOp() const + { + return CallTargetCheckOpBits::Get(bitField_); + } + + static uint64_t ToValue(TypedCallTargetCheckOp op) + { + return CallTargetCheckOpBits::Encode(op); + } + +private: + using CallTargetCheckOpBits = panda::BitField; + + uint64_t bitField_; +}; + class BranchAccessor { public: // type bits shift @@ -510,9 +442,9 @@ public: static constexpr int JUMP_OP_BITS = 8; explicit TypedJumpAccessor(uint64_t value) : bitField_(value) {} - GateType GetTypeValue() const + ParamType GetParamType() const { - return GateType(TypedValueBits::Get(bitField_)); + return ParamType(TypedValueBits::Get(bitField_)); } TypedJumpOp GetTypedJumpOp() const @@ -530,9 +462,9 @@ public: return FalseWeightBits::Get(bitField_); } - static uint64_t ToValue(GateType typeValue, TypedJumpOp jumpOp, uint32_t weight) + static uint64_t ToValue(ParamType paramType, TypedJumpOp jumpOp, uint32_t weight) { - return TypedValueBits::Encode(typeValue.Value()) + return TypedValueBits::Encode(paramType.Value()) | TypedJumpOpBits::Encode(jumpOp) | WeightBits::Encode(weight); } diff --git a/ecmascript/compiler/mcr_lowering.cpp b/ecmascript/compiler/mcr_lowering.cpp index 351d671bb48ce57870f8ee16d24482ee522e4ce3..3cd9e5b57b826a9ac7102c2974a9a34effe80369 100644 --- a/ecmascript/compiler/mcr_lowering.cpp +++ b/ecmascript/compiler/mcr_lowering.cpp @@ -13,14 +13,16 @@ * limitations under the License. */ #include "ecmascript/compiler/mcr_lowering.h" +#include "ecmascript/compiler/argument_accessor.h" #include "ecmascript/compiler/bytecodes.h" #include "ecmascript/compiler/share_gate_meta_data.h" +#include "ecmascript/compiler/share_opcodes.h" #include "ecmascript/global_env.h" -#include "ecmascript/jspandafile/program_object.h" -#include "ecmascript/js_thread.h" #include "ecmascript/js_function.h" +#include "ecmascript/js_hclass.h" +#include "ecmascript/js_thread.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/message_string.h" -#include "ecmascript/compiler/argument_accessor.h" namespace panda::ecmascript::kungfu { @@ -103,6 +105,15 @@ GateRef MCRLowering::VisitGate(GateRef gate) case OpCode::IS_NOT_UNDEFINED_OR_HOLE_CHECK: LowerIsNotUndefinedOrHoleCheck(gate); break; + case OpCode::IS_ECMA_OBJECT_CHECK: + LowerIsEcmaObjectCheck(gate); + break; + case OpCode::IS_TAGGED_BOOLEAN_CHECK: + LowerIsTaggedBooleanCheck(gate); + break; + case OpCode::IS_DATA_VIEW_CHECK: + LowerIsDataViewCheck(gate); + break; case OpCode::STORE_MEMORY: LowerStoreMemory(gate); break; @@ -914,6 +925,36 @@ void MCRLowering::LowerIsNotUndefinedOrHoleCheck(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } +void MCRLowering::LowerIsEcmaObjectCheck(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef frameState = acc_.GetFrameState(gate); + GateRef obj = acc_.GetValueIn(gate, 0); + GateRef isEcmaObject = builder_.IsEcmaObject(obj); + builder_.DeoptCheck(isEcmaObject, frameState, DeoptType::ISNOTECMAOBJECT); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); +} + +void MCRLowering::LowerIsDataViewCheck(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef frameState = acc_.GetFrameState(gate); + GateRef obj = acc_.GetValueIn(gate, 0); + GateRef isDataView = builder_.CheckJSType(obj, JSType::JS_DATA_VIEW); + builder_.DeoptCheck(isDataView, frameState, DeoptType::ISNOTDATAVIEW); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); +} + +void MCRLowering::LowerIsTaggedBooleanCheck(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef frameState = acc_.GetFrameState(gate); + GateRef value = acc_.GetValueIn(gate, 0); + GateRef taggedIsBoolean = builder_.TaggedIsBoolean(value); + builder_.DeoptCheck(taggedIsBoolean, frameState, DeoptType::ISNOTTAGGEDBOOLEAN); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); +} + void MCRLowering::LowerValueCheckNegOverflow(GateRef gate) { Environment env(gate, circuit_, &builder_); diff --git a/ecmascript/compiler/mcr_lowering.h b/ecmascript/compiler/mcr_lowering.h index 2cfff1dd7304f5b250597b728ba0961b04d165e1..bed06aa0ffdb76776adcba68418072067744f8f2 100644 --- a/ecmascript/compiler/mcr_lowering.h +++ b/ecmascript/compiler/mcr_lowering.h @@ -73,6 +73,9 @@ private: void LowerLexVarIsHoleCheck(GateRef gate); void LowerIsUndefinedOrHoleCheck(GateRef gate); void LowerIsNotUndefinedOrHoleCheck(GateRef gate); + void LowerIsEcmaObjectCheck(GateRef gate); + void LowerIsDataViewCheck(GateRef gate); + void LowerIsTaggedBooleanCheck(GateRef gate); void LowerStoreMemory(GateRef gate); void LowerCheckNullAndConvert(GateRef gate, GateRef frameState); void LowerUndefinedAndConvert(GateRef gate, GateRef frameState); diff --git a/ecmascript/compiler/mcr_opcodes.h b/ecmascript/compiler/mcr_opcodes.h index e329b5a34653d3f893c8bf8ca0142d130a20fb66..0b3de642fbe928a8a0d54680750cdc7410fa7851 100644 --- a/ecmascript/compiler/mcr_opcodes.h +++ b/ecmascript/compiler/mcr_opcodes.h @@ -29,6 +29,9 @@ namespace panda::ecmascript::kungfu { V(LexVarIsHoleCheck, LEX_VAR_IS_HOLE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ V(IsUndefinedOrHoleCheck, IS_UNDEFINED_OR_HOLE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ V(IsNotUndefinedOrHoleCheck, IS_NOT_UNDEFINED_OR_HOLE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ + V(IsEcmaObjectCheck, IS_ECMA_OBJECT_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ + V(IsDataViewCheck, IS_DATA_VIEW_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ + V(IsTaggedBooleanCheck, IS_TAGGED_BOOLEAN_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ V(TaggedIsHeapObject, TAGGED_IS_HEAP_OBJECT, GateFlags::NO_WRITE, 1, 1, 1) \ V(IsMarkerCellValid, IS_MARKER_CELL_VALID, GateFlags::NO_WRITE, 1, 1, 1) \ V(StringEqual, STRING_EQUAL, GateFlags::NO_WRITE, 1, 1, 2) @@ -61,6 +64,10 @@ namespace panda::ecmascript::kungfu { V(MigrateFromHeapValueToRawValue, MIGRATE_FROM_HEAPVALUE_TO_RAWVALUE, GateFlags::NONE_FLAG, 1, 1, 3) \ V(MigrateFromHoleIntToHoleNumber, MIGRATE_FROM_HOLEINT_TO_HOLENUMBER, GateFlags::NONE_FLAG, 1, 1, 1) \ V(MigrateFromHoleNumberToHoleInt, MIGRATE_FROM_HOLENUMBER_TO_HOLEINT, GateFlags::NONE_FLAG, 1, 1, 1) \ + V(NumberIsFinite, NUMBER_IS_FINITE, GateFlags::NO_WRITE, 1, 1, 1) \ + V(NumberIsInteger, NUMBER_IS_INTEGER, GateFlags::NO_WRITE, 1, 1, 1) \ + V(NumberIsNaN, NUMBER_IS_NAN, GateFlags::NO_WRITE, 1, 1, 1) \ + V(NumberIsSafeInteger, NUMBER_IS_SAFEINTEGER, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathAcos, MATH_ACOS, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathAcosh, MATH_ACOSH, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathAsin, MATH_ASIN, GateFlags::NO_WRITE, 1, 1, 1) \ @@ -70,16 +77,46 @@ namespace panda::ecmascript::kungfu { V(MathAtanh, MATH_ATANH, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathCos, MATH_COS, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathCosh, MATH_COSH, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathSign, MATH_SIGN, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathSignTagged, MATH_SIGN_TAGGED, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathSin, MATH_SIN, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathSinh, MATH_SINH, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathSqrt, MATH_SQRT, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathTan, MATH_TAN, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathTanh, MATH_TANH, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathTrunc, MATH_TRUNC, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathLog, MATH_LOG, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathLog2, MATH_LOG2, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathLog10, MATH_LOG10, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathLog1p, MATH_LOG1P, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathExp, MATH_EXP, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathExpm1, MATH_EXPM1, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathClz32, MATH_CLZ32, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathClz32Double, MATH_CLZ32_DOUBLE, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathClz32Int32, MATH_CLZ32_INT32, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathAbs, MATH_ABS, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathAbsInt32, MATH_ABS_INT32, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathAbsDouble, MATH_ABS_DOUBLE, GateFlags::NO_WRITE, 1, 1, 1) \ V(MathPow, MATH_POW, GateFlags::NO_WRITE, 1, 1, 2) \ + V(MathCbrt, MATH_CBRT, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathMin, MATH_MIN, GateFlags::NO_WRITE, 1, 1, 2) \ + V(MathMinInt32, MATH_MIN_INT32, GateFlags::NO_WRITE, 1, 1, 2) \ + V(MathMinDouble, MATH_MIN_DOUBLE, GateFlags::NO_WRITE, 1, 1, 2) \ + V(MathMax, MATH_MAX, GateFlags::NO_WRITE, 1, 1, 2) \ + V(MathMaxInt32, MATH_MAX_INT32, GateFlags::NO_WRITE, 1, 1, 2) \ + V(MathMaxDouble, MATH_MAX_DOUBLE, GateFlags::NO_WRITE, 1, 1, 2) \ + V(MathRound, MATH_ROUND, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathRoundDouble, MATH_ROUND_DOUBLE, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathFRound, MATH_FROUND, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathCeil, MATH_CEIL, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathFloor, MATH_FLOOR, GateFlags::NO_WRITE, 1, 1, 1) \ + V(MathImul, MATH_IMUL, GateFlags::NO_WRITE, 1, 1, 2) \ + V(GlobalIsFinite, GLOBAL_IS_FINITE, GateFlags::NO_WRITE, 1, 1, 1) \ + V(GlobalIsNan, GLOBAL_IS_NAN, GateFlags::NO_WRITE, 1, 1, 1) \ + V(ArrayBufferIsView, ARRAY_BUFFER_IS_VIEW, GateFlags::NO_WRITE, 1, 1, 1) \ + V(DataViewGet, DATA_VIEW_GET, GateFlags::NO_WRITE, 1, 1, 5) \ + V(DataViewSet, DATA_VIEW_SET, GateFlags::NO_WRITE, 1, 1, 6) \ + V(MapGet, MAP_GET, GateFlags::NO_WRITE, 1, 1, 2) \ MCR_BINARY_GATE_META_DATA_CACHE_LIST(V) #define MCR_GATE_META_DATA_LIST_WITH_PC_OFFSET(V) \ @@ -123,6 +160,7 @@ namespace panda::ecmascript::kungfu { V(PrimitiveTypeCheck, PRIMITIVE_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ V(TypedArrayCheck, TYPED_ARRAY_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ V(LoadTypedArrayLength, LOAD_TYPED_ARRAY_LENGTH, GateFlags::NO_WRITE, 1, 1, 1) \ + V(TypedBinaryOp, TYPED_BINARY_OP, GateFlags::NO_WRITE, 1, 1, 2) \ V(TypedUnaryOp, TYPED_UNARY_OP, GateFlags::NO_WRITE, 1, 1, 1) \ V(TypedConditionJump, TYPED_CONDITION_JUMP, GateFlags::NO_WRITE, 1, 1, 1) \ V(TypedConvert, TYPE_CONVERT, GateFlags::NO_WRITE, 1, 1, 1) \ @@ -130,22 +168,21 @@ namespace panda::ecmascript::kungfu { V(Convert, CONVERT, GateFlags::NONE_FLAG, 0, 0, 1) \ V(JSInlineTargetTypeCheck, JSINLINETARGET_TYPE_CHECK, GateFlags::CHECKABLE, 1, 1, 2) \ V(TypeOfCheck, TYPE_OF_CHECK, GateFlags::CHECKABLE, 1, 1, 1) \ - V(TypeOf, TYPE_OF, GateFlags::NO_WRITE, 1, 1, 0) + V(TypeOf, TYPE_OF, GateFlags::NO_WRITE, 1, 1, 0) \ + V(TypedCallTargetCheckOp, TYPED_CALLTARGETCHECK_OP, GateFlags::CHECKABLE, 1, 1, 2 ) + +// NOTICE-PGO: wx typedcalltargetcheckop can adopt different number of valueIn #define MCR_GATE_META_DATA_LIST_WITH_ONE_PARAMETER(V) \ MCR_GATE_META_DATA_LIST_WITH_VALUE(V) \ MCR_GATE_META_DATA_LIST_WITH_GATE_TYPE(V) -#define MCR_GATE_OPCODE_LIST(V) \ - V(TYPED_BINARY_OP) \ - V(TYPED_CALLTARGETCHECK_OP) - -} - #define MCR_GATE_META_DATA_LIST_WITH_VALUE_IN(V) \ V(TypedCreateObjWithBuffer, TYPED_CREATE_OBJ_WITH_BUFFER, GateFlags::CHECKABLE, 1, 1, value) \ - V(TypedCallCheck, TYPED_CALL_CHECK, GateFlags::CHECKABLE, 1, 1, value) + V(TypedCallCheck, TYPED_CALL_CHECK, GateFlags::CHECKABLE, 1, 1, value) #define MCR_GATE_META_DATA_LIST_WITH_SIZE(V) \ MCR_GATE_META_DATA_LIST_WITH_VALUE_IN(V) +} + #endif // ECMASCRIPT_COMPILER_MCR_OPCODE_H diff --git a/ecmascript/compiler/native_inline_lowering.cpp b/ecmascript/compiler/native_inline_lowering.cpp index 2b6c78a588f888b52fe8bc17dc651d7613dc0ef9..0d2d18ce607b41b95a90a194758099b1826d7264 100644 --- a/ecmascript/compiler/native_inline_lowering.cpp +++ b/ecmascript/compiler/native_inline_lowering.cpp @@ -13,29 +13,45 @@ * limitations under the License. */ #include "ecmascript/compiler/native_inline_lowering.h" +#include "ecmascript/builtins/builtins_number.h" +#include "ecmascript/base/number_helper.h" +#include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/circuit_builder_helper.h" -#include "ecmascript/compiler/circuit.h" +#include "ecmascript/compiler/share_gate_meta_data.h" +#include "ecmascript/js_dataview.h" #include "ecmascript/js_thread.h" #include "ecmascript/message_string.h" namespace panda::ecmascript::kungfu { -std::optional NativeInlineLowering::GetArgc(GateRef gate) +std::optional> NativeInlineLowering::GetCallInfo(GateRef gate) { EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate); switch (ecmaOpcode) { + case EcmaOpcode::CALLARG0_IMM8: + return {{0U, false}}; case EcmaOpcode::CALLTHIS0_IMM8_V8: - return 0U; + return {{0U, true}}; + case EcmaOpcode::CALLARG1_IMM8_V8: + return {{1U, false}}; case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: - return 1U; + return {{1U, true}}; + case EcmaOpcode::CALLARGS2_IMM8_V8_V8: + return {{2U, false}}; case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: - return 2U; + return {{2U, true}}; + case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: + return {{3U, false}}; case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: - return 3U; + return {{3U, true}}; + case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: { + CallRangeTypeInfoAccessor tia(thread_, circuit_, gate); + return {{tia.GetArgc(), false}}; + } case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: { CallThisRangeTypeInfoAccessor tia(thread_, circuit_, gate); - return tia.GetArgc(); + return {{tia.GetArgc(), true}}; } default: return std::nullopt; @@ -51,73 +67,159 @@ void NativeInlineLowering::RunNativeInlineLowering() if (op != OpCode::JS_BYTECODE) { continue; } - std::optional opt_argc = GetArgc(gate); - if (!opt_argc) { + auto optCallInfo = GetCallInfo(gate); + if (!optCallInfo) { continue; } - size_t argc = opt_argc.value(); + auto [argc, skipThis] = optCallInfo.value(); CallTypeInfoAccessor ctia(thread_, circuit_, gate); - BuiltinsStubCSigns::ID id = ctia.TryGetPGOBuiltinId(); + BuiltinsStubCSigns::ID id = ctia.TryGetPGOBuiltinMethodId(); switch (id) { case BuiltinsStubCSigns::ID::StringFromCharCode: - TryInlineStringFromCharCode(gate, argc); + TryInlineStringFromCharCode(gate, argc, skipThis); + break; + case BuiltinsStubCSigns::ID::NumberIsFinite: + TryInlineNumberIsFinite(gate, argc, skipThis); + break; + case BuiltinsStubCSigns::ID::NumberIsInteger: + TryInlineNumberIsInteger(gate, argc, skipThis); + break; + case BuiltinsStubCSigns::ID::NumberIsNaN: + TryInlineNumberIsNaN(gate, argc, skipThis); + break; + case BuiltinsStubCSigns::ID::NumberIsSafeInteger: + TryInlineNumberIsSafeInteger(gate, argc, skipThis); break; case BuiltinsStubCSigns::ID::MathAcos: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAcos()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAcos(), skipThis); break; case BuiltinsStubCSigns::ID::MathAcosh: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAcosh()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAcosh(), skipThis); break; case BuiltinsStubCSigns::ID::MathAsin: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAsin()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAsin(), skipThis); break; case BuiltinsStubCSigns::ID::MathAsinh: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAsinh()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAsinh(), skipThis); break; case BuiltinsStubCSigns::ID::MathAtan: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAtan()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAtan(), skipThis); break; case BuiltinsStubCSigns::ID::MathAtan2: - TryInlineMathBinaryBuiltin(gate, argc, id, circuit_->MathAtan2()); + TryInlineMathBinaryBuiltin(gate, argc, id, circuit_->MathAtan2(), skipThis); break; case BuiltinsStubCSigns::ID::MathAtanh: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAtanh()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAtanh(), skipThis); break; case BuiltinsStubCSigns::ID::MathCos: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathCos()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathCos(), skipThis); break; case BuiltinsStubCSigns::ID::MathCosh: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathCosh()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathCosh(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathSign: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathSign(), skipThis); break; case BuiltinsStubCSigns::ID::MathSin: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathSin()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathSin(), skipThis); break; case BuiltinsStubCSigns::ID::MathSinh: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathSinh()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathSinh(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathSqrt: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathSqrt(), skipThis); break; case BuiltinsStubCSigns::ID::MathTan: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathTan()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathTan(), skipThis); break; case BuiltinsStubCSigns::ID::MathTanh: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathTanh()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathTanh(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathTrunc: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathTrunc(), skipThis); break; case BuiltinsStubCSigns::ID::MathAbs: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAbs()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathAbs(), skipThis); break; case BuiltinsStubCSigns::ID::MathLog: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog(), skipThis); break; case BuiltinsStubCSigns::ID::MathLog2: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog2()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog2(), skipThis); break; case BuiltinsStubCSigns::ID::MathLog10: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog10()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog10(), skipThis); break; case BuiltinsStubCSigns::ID::MathLog1p: - TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog1p()); + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathLog1p(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathExp: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathExp(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathExpm1: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathExpm1(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathClz32: + TryInlineMathClz32Builtin(gate, argc, skipThis); break; case BuiltinsStubCSigns::ID::MathPow: - TryInlineMathBinaryBuiltin(gate, argc, id, circuit_->MathPow()); + TryInlineMathBinaryBuiltin(gate, argc, id, circuit_->MathPow(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathCbrt: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathCbrt(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathImul: + TryInlineMathImulBuiltin(gate, argc, id, circuit_->MathImul(), skipThis); + break; + case BuiltinsStubCSigns::ID::GlobalIsFinite: + TryInlineGlobalFiniteBuiltin(gate, argc, id, circuit_->GlobalIsFinite(), skipThis); + break; + case BuiltinsStubCSigns::ID::GlobalIsNan: + TryInlineGlobalNanBuiltin(gate, argc, id, circuit_->GlobalIsNan(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathMin: + TryInlineMathMinMaxBuiltin(gate, argc, id, circuit_->MathMin(), base::POSITIVE_INFINITY, skipThis); + break; + case BuiltinsStubCSigns::ID::MathMax: + TryInlineMathMinMaxBuiltin(gate, argc, id, circuit_->MathMax(), -base::POSITIVE_INFINITY, skipThis); + break; + case BuiltinsStubCSigns::ID::MathRound: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathRound(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathFRound: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathFRound(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathCeil: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathCeil(), skipThis); + break; + case BuiltinsStubCSigns::ID::MathFloor: + TryInlineMathUnaryBuiltin(gate, argc, id, circuit_->MathFloor(), skipThis); + break; + case BuiltinsStubCSigns::ID::ArrayBufferIsView: + TryInlineArrayBufferIsView(gate, argc, id, skipThis); + break; + case BuiltinsStubCSigns::ID::DataViewGetFloat32: + case BuiltinsStubCSigns::ID::DataViewGetFloat64: + case BuiltinsStubCSigns::ID::DataViewGetInt8: + case BuiltinsStubCSigns::ID::DataViewGetInt16: + case BuiltinsStubCSigns::ID::DataViewGetInt32: + case BuiltinsStubCSigns::ID::DataViewGetUint16: + case BuiltinsStubCSigns::ID::DataViewGetUint32: + case BuiltinsStubCSigns::ID::DataViewGetUint8: + TryInlineDataViewGet(gate, argc, id); + break; + case BuiltinsStubCSigns::ID::DataViewSetFloat32: + case BuiltinsStubCSigns::ID::DataViewSetFloat64: + case BuiltinsStubCSigns::ID::DataViewSetInt8: + case BuiltinsStubCSigns::ID::DataViewSetInt16: + case BuiltinsStubCSigns::ID::DataViewSetInt32: + case BuiltinsStubCSigns::ID::DataViewSetUint8: + case BuiltinsStubCSigns::ID::DataViewSetUint16: + case BuiltinsStubCSigns::ID::DataViewSetUint32: + TryInlineDataViewSet(gate, argc, id); + break; + case BuiltinsStubCSigns::ID::MapGet: + InlineStubBuiltin(gate, 1U, argc, id, circuit_->MapGet(), skipThis); break; default: break; @@ -135,8 +237,23 @@ void NativeInlineLowering::RunNativeInlineLowering() } } -void NativeInlineLowering::TryInlineStringFromCharCode(GateRef gate, size_t argc) +void NativeInlineLowering::AddTraceLogs(GateRef gate, BuiltinsStubCSigns::ID id) { + size_t index = RTSTUB_ID(AotInlineBuiltinTrace); + + GateRef frameState = acc_.GetFrameState(gate); + GateRef frameArgs = acc_.GetValueIn(frameState); + GateRef callerFunc = acc_.GetValueIn(frameArgs, 0); + std::vector args{callerFunc, builder_.Int32(id)}; + + builder_.CallRuntime(glue_, index, Gate::InvalidGateRef, args, gate); +} + +void NativeInlineLowering::TryInlineStringFromCharCode(GateRef gate, size_t argc, bool skipThis) +{ + if (!skipThis) { + return; + } if (argc != 1) { return; } @@ -147,43 +264,346 @@ void NativeInlineLowering::TryInlineStringFromCharCode(GateRef gate, size_t argc builder_.IntPtr(static_cast(BuiltinsStubCSigns::ID::StringFromCharCode)), {tacc.GetArg0()}); } + + if (EnableTrace()) { + AddTraceLogs(gate, BuiltinsStubCSigns::ID::StringFromCharCode); + } + GateRef ret = builder_.StringFromSingleCharCode(tacc.GetArg0()); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); } +void NativeInlineLowering::TryInlineNumberIsFinite(GateRef gate, size_t argc, bool skipThis) +{ + if (!skipThis) { + return; + } + if (argc != 1) { + return; + } + CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate); + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, tacc.GetFunc(), + builder_.IntPtr(static_cast(BuiltinsStubCSigns::ID::NumberIsFinite))); + } + GateRef ret = builder_.NumberIsFinite(tacc.GetArg0()); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); +} + +void NativeInlineLowering::TryInlineNumberIsInteger(GateRef gate, size_t argc, bool skipThis) +{ + if (!skipThis) { + return; + } + if (argc != 1) { + return; + } + CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate); + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, tacc.GetFunc(), + builder_.IntPtr(static_cast(BuiltinsStubCSigns::ID::NumberIsInteger))); + } + GateRef ret = builder_.NumberIsInteger(tacc.GetArg0()); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); +} + +void NativeInlineLowering::TryInlineNumberIsNaN(GateRef gate, size_t argc, bool skipThis) +{ + if (!skipThis) { + return; + } + if (argc != 1) { + return; + } + CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate); + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, tacc.GetFunc(), + builder_.IntPtr(static_cast(BuiltinsStubCSigns::ID::NumberIsNaN))); + } + GateRef ret = builder_.NumberIsNaN(tacc.GetArg0()); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); +} + +void NativeInlineLowering::TryInlineNumberIsSafeInteger(GateRef gate, size_t argc, bool skipThis) +{ + if (!skipThis) { + return; + } + if (argc != 1) { + return; + } + CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate); + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, tacc.GetFunc(), + builder_.IntPtr(static_cast(BuiltinsStubCSigns::ID::NumberIsSafeInteger))); + } + GateRef ret = builder_.NumberIsSafeInteger(tacc.GetArg0()); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); +} + void NativeInlineLowering::TryInlineMathUnaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, - const GateMetaData* op) + const GateMetaData* op, bool skipThis) { Environment env(gate, circuit_, &builder_); + bool firstParam = skipThis ? 1 : 0; if (!Uncheck()) { - builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + 1), + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + firstParam), builder_.IntPtr(static_cast(id))); } - // NOTE(schernykh): Add tracing + + if (EnableTrace()) { + AddTraceLogs(gate, id); + } + if (argc == 0) { acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), builder_.NanValue()); return; } - GateRef ret = builder_.BuildMathBuiltinOp(op, {acc_.GetValueIn(gate, 1)}); + GateRef ret = builder_.BuildControlDependOp(op, {acc_.GetValueIn(gate, firstParam)}); acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); } +void NativeInlineLowering::TryInlineMathClz32Builtin(GateRef gate, size_t argc, bool skipThis) +{ + Environment env(gate, circuit_, &builder_); + bool firstParam = skipThis ? 1 : 0; + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + firstParam), + builder_.IntPtr(static_cast(BuiltinsStubCSigns::ID::MathClz32))); + } + if (EnableTrace()) { + AddTraceLogs(gate, BuiltinsStubCSigns::ID::MathClz32); + } + if (argc == 0) { + const int32_t defaultValue = 32; + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), builder_.Int32(defaultValue)); + return; + } + GateRef ret = builder_.BuildControlDependOp(circuit_->MathClz32(), {acc_.GetValueIn(gate, firstParam)}); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + +void NativeInlineLowering::TryInlineGlobalFiniteBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, + const GateMetaData* op, bool skipThis) +{ + Environment env(gate, circuit_, &builder_); + bool firstParam = skipThis ? 1 : 0; + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + firstParam), + builder_.IntPtr(static_cast(id))); + } + if (EnableTrace()) { + AddTraceLogs(gate, id); + } + if (argc == 0) { + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), builder_.Boolean(false)); + return; + } + GateRef ret = builder_.BuildControlDependOp(op, {acc_.GetValueIn(gate, firstParam)}); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + +void NativeInlineLowering::TryInlineGlobalNanBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, + const GateMetaData* op, bool skipThis) +{ + Environment env(gate, circuit_, &builder_); + bool firstParam = skipThis ? 1 : 0; + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + firstParam), + builder_.IntPtr(static_cast(id))); + } + if (EnableTrace()) { + AddTraceLogs(gate, id); + } + if (argc == 0) { + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), builder_.Boolean(true)); + return; + } + GateRef ret = builder_.BuildControlDependOp(op, {acc_.GetValueIn(gate, firstParam)}); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + +void NativeInlineLowering::TryInlineMathImulBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, + const GateMetaData* op, bool skipThis) +{ + Environment env(gate, circuit_, &builder_); + bool firstParam = skipThis ? 1 : 0; + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + firstParam), + builder_.IntPtr(static_cast(id))); + } + if (EnableTrace()) { + AddTraceLogs(gate, id); + } + if (argc < 2U) { + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), builder_.Int32(0)); + return; + } + GateRef ret = builder_.BuildControlDependOp(op, {acc_.GetValueIn(gate, firstParam), + acc_.GetValueIn(gate, firstParam + 1)}); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); + return; +} + void NativeInlineLowering::TryInlineMathBinaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, - const GateMetaData* op) + const GateMetaData* op, bool skipThis) { Environment env(gate, circuit_, &builder_); + bool firstParam = skipThis ? 1 : 0; if (!Uncheck()) { - builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + 1), + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + firstParam), builder_.IntPtr(static_cast(id))); } - // NOTE(schernykh): Add tracing + if (EnableTrace()) { + AddTraceLogs(gate, id); + } if (argc < 2U) { acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), builder_.NanValue()); return; } - GateRef ret = builder_.BuildMathBuiltinOp(op, {acc_.GetValueIn(gate, 1), acc_.GetValueIn(gate, 2)}); + GateRef ret = builder_.BuildControlDependOp(op, {acc_.GetValueIn(gate, firstParam), + acc_.GetValueIn(gate, firstParam + 1)}); acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); return; } +void NativeInlineLowering::TryInlineMathMinMaxBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, + const GateMetaData* op, double defaultValue, bool skipThis) +{ + Environment env(gate, circuit_, &builder_); + bool firstParam = skipThis ? 1 : 0; + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + firstParam), + builder_.IntPtr(static_cast(id))); + } + if (EnableTrace()) { + AddTraceLogs(gate, id); + } + if (argc == 0) { + GateRef ret = builder_.DoubleToTaggedDoublePtr(builder_.Double(defaultValue)); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); + return; + } + GateRef ret = acc_.GetValueIn(gate, firstParam); + if (argc == 1) { + auto param_check = builder_.TaggedIsNumber(ret); + builder_.DeoptCheck(param_check, acc_.GetFrameState(gate), DeoptType::BUILTIN_INLINING_TYPE_GUARD); + if (acc_.GetGateType(ret).IsAnyType()) { + acc_.SetGateType(ret, GateType::NumberType()); + } + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); + return; + } + for (size_t i = 1; i < argc; i++) { + auto param = acc_.GetValueIn(gate, i + firstParam); + ret = builder_.BuildControlDependOp(op, {ret, param}); + } + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + +void NativeInlineLowering::TryInlineArrayBufferIsView(GateRef gate, + size_t argc, + BuiltinsStubCSigns::ID id, + bool skipThis) +{ + if (!skipThis) { + return; + } + if (argc != 1) { + return; + } + CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate); + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, tacc.GetFunc(), builder_.IntPtr(static_cast(id)), {tacc.GetArg0()}); + } + GateRef arg0 = tacc.GetArg0(); + GateRef ret = builder_.ArrayBufferIsView(arg0); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + +void NativeInlineLowering::TryInlineDataViewGet(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id) +{ + if (argc != 1 && argc != 2) { // number of args must be 1/2 + return; + } + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + 1), builder_.IntPtr(static_cast(id))); + } + GateRef thisObj = acc_.GetValueIn(gate, 0); // 0: this + builder_.IsEcmaObjectCheck(thisObj); + builder_.IsDataViewCheck(thisObj); + GateRef dataViewCallID = builder_.Int32(id); + GateRef index = acc_.GetValueIn(gate, 1); // 1: index of dataView + GateRef ret = Circuit::NullGate(); + GateRef frameState = acc_.GetFrameState(gate); + if (argc == 1) { // if not provide isLittleEndian, default use big endian + ret = builder_.DataViewGet(thisObj, index, dataViewCallID, builder_.TaggedFalse(), frameState); + } else if (argc == 2) { // 2: provide isLittleEndian + GateRef isLittleEndian = acc_.GetValueIn(gate, 2); // 2: is little endian mode + builder_.IsTaggedBooleanCheck(isLittleEndian); + ret = builder_.DataViewGet(thisObj, index, dataViewCallID, isLittleEndian, frameState); + } + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + +void NativeInlineLowering::TryInlineDataViewSet(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id) +{ + if (argc != 1 && argc != 2 && argc != 3) { // number of args must be 1/2/3 + return; + } + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, argc + 1), builder_.IntPtr(static_cast(id))); + } + GateRef thisObj = acc_.GetValueIn(gate, 0); // 0: this + builder_.IsEcmaObjectCheck(thisObj); + builder_.IsDataViewCheck(thisObj); + GateRef dataViewCallID = builder_.Int32(id); + GateRef index = acc_.GetValueIn(gate, 1); // 1: index + + GateRef ret = Circuit::NullGate(); + GateRef frameState = acc_.GetFrameState(gate); + if (argc == 1) { // arg counts is 1 + ret = builder_.DataViewSet( + thisObj, index, builder_.Double(base::NAN_VALUE), dataViewCallID, builder_.TaggedFalse(), frameState); + } else if (argc == 2) { // arg counts is 2 + GateRef value = acc_.GetValueIn(gate, 2); // 2: value + ret = builder_.DataViewSet(thisObj, index, value, dataViewCallID, builder_.TaggedFalse(), frameState); + } else if (argc == 3) { // arg counts is 3 + GateRef value = acc_.GetValueIn(gate, 2); // 2: value + GateRef isLittleEndian = acc_.GetValueIn(gate, 3); // 3: is little endian mode + builder_.IsTaggedBooleanCheck(isLittleEndian); + ret = builder_.DataViewSet(thisObj, index, value, dataViewCallID, isLittleEndian, frameState); + } + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + +void NativeInlineLowering::InlineStubBuiltin(GateRef gate, size_t builtinArgc, size_t realArgc, + BuiltinsStubCSigns::ID id, const GateMetaData* op, bool skipThis) +{ + if (!skipThis) { + return; + } + Environment env(gate, circuit_, &builder_); + if (!Uncheck()) { + builder_.CallTargetCheck(gate, acc_.GetValueIn(gate, realArgc + 1U), + builder_.IntPtr(static_cast(id))); + } + if (EnableTrace()) { + AddTraceLogs(gate, id); + } + std::vector args {}; + for (size_t i = 0; i <= builtinArgc; i++) { + args.push_back(i <= realArgc ? acc_.GetValueIn(gate, i) : builder_.Undefined()); + } + GateRef ret = builder_.BuildControlDependOp(op, args); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), ret); +} + } // namespace panda::ecmascript diff --git a/ecmascript/compiler/native_inline_lowering.h b/ecmascript/compiler/native_inline_lowering.h index 419a2fbd7d69fe9014d309400b6985de9fa0655a..2c3a7ea6a49c91d850b8ffceb6872b86ff2264d9 100644 --- a/ecmascript/compiler/native_inline_lowering.h +++ b/ecmascript/compiler/native_inline_lowering.h @@ -16,10 +16,14 @@ #ifndef ECMASCRIPT_COMPILER_BUILTIN_INLINE_H #define ECMASCRIPT_COMPILER_BUILTIN_INLINE_H +#include "ecmascript/compiler/builtins/builtins_call_signature.h" #include "ecmascript/compiler/circuit_builder.h" #include "ecmascript/compiler/gate_accessor.h" +#include "ecmascript/compiler/graph_linearizer.h" #include "ecmascript/compiler/pass_manager.h" +#include "ecmascript/compiler/share_gate_meta_data.h" #include "ecmascript/compiler/type_info_accessors.h" +#include "ecmascript/js_dataview.h" #include "ecmascript/ts_types/ts_manager.h" namespace panda::ecmascript::kungfu { @@ -40,11 +44,32 @@ public: void RunNativeInlineLowering(); private: - std::optional GetArgc(GateRef gate); - void TryInlineStringFromCharCode(GateRef gate, size_t argc); - void TryInlineMathMinWithOneArg(GateRef gate, size_t argc); - void TryInlineMathUnaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op); - void TryInlineMathBinaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op); + std::optional> GetCallInfo(GateRef gate); + void TryInlineStringFromCharCode(GateRef gate, size_t argc, bool skipThis); + void TryInlineNumberIsFinite(GateRef gate, size_t argc, bool skipThis); + void TryInlineNumberIsInteger(GateRef gate, size_t argc, bool skipThis); + void TryInlineNumberIsNaN(GateRef gate, size_t argc, bool skipThis); + void TryInlineNumberIsSafeInteger(GateRef gate, size_t argc, bool skipThis); + void TryInlineMathUnaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op, + bool skipThis); + void TryInlineMathBinaryBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op, + bool skipThis); + void TryInlineMathImulBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op, + bool skipThis); + void TryInlineGlobalFiniteBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op, + bool skipThis); + void TryInlineGlobalNanBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op, + bool skipThis); + void TryInlineMathMinMaxBuiltin(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, const GateMetaData* op, + double defaultValue, bool skipThis); + void TryInlineMathClz32Builtin(GateRef gate, size_t argc, bool skipThis); + void TryInlineArrayBufferIsView(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id, bool skipThis); + void TryInlineDataViewGet(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id); + void TryInlineDataViewSet(GateRef gate, size_t argc, BuiltinsStubCSigns::ID id); + void InlineStubBuiltin(GateRef gate, size_t builtinArgc, size_t realArgc, BuiltinsStubCSigns::ID id, + const GateMetaData* op, bool skipThis); + + void AddTraceLogs(GateRef gate, BuiltinsStubCSigns::ID id); bool EnableLog() const { @@ -79,4 +104,4 @@ private: const JSThread *thread_ {nullptr}; }; } -#endif // ECMASCRIPT_COMPILER_BUILTIN_INLINE_H \ No newline at end of file +#endif // ECMASCRIPT_COMPILER_BUILTIN_INLINE_H diff --git a/ecmascript/compiler/new_object_stub_builder.cpp b/ecmascript/compiler/new_object_stub_builder.cpp index 67b2db23c7735258386113841b93065e6928931f..e4fde9da7d15151bbae276933413dbdfc6bda857 100644 --- a/ecmascript/compiler/new_object_stub_builder.cpp +++ b/ecmascript/compiler/new_object_stub_builder.cpp @@ -15,6 +15,7 @@ #include "ecmascript/compiler/new_object_stub_builder.h" +#include "ecmascript/compiler/number_gate_info.h" #include "ecmascript/compiler/stub_builder-inl.h" #include "ecmascript/compiler/stub_builder.h" #include "ecmascript/ecma_string.h" @@ -40,11 +41,11 @@ void NewObjectStubBuilder::NewLexicalEnv(Variable *result, Label *exit, GateRef // Be careful. NO GC is allowed when initization is not complete. Label hasPendingException(env); Label noException(env); - AllocateInYoung(result, &hasPendingException, &noException); + auto hclass = GetGlobalConstantValue( + VariableType::JS_POINTER(), glue_, ConstantIndex::ENV_CLASS_INDEX); + AllocateInYoung(result, &hasPendingException, &noException, hclass); Bind(&noException); { - auto hclass = GetGlobalConstantValue( - VariableType::JS_POINTER(), glue_, ConstantIndex::ENV_CLASS_INDEX); StoreHClass(glue_, result->ReadVariable(), hclass); Label afterInitialize(env); InitializeTaggedArrayWithSpeicalValue(&afterInitialize, @@ -105,7 +106,7 @@ void NewObjectStubBuilder::NewJSObject(Variable *result, Label *exit, GateRef hc // Be careful. NO GC is allowed when initization is not complete. Label hasPendingException(env); Label noException(env); - AllocateInYoung(result, &hasPendingException, &noException); + AllocateInYoung(result, &hasPendingException, &noException, hclass); Bind(&noException); { StoreHClass(glue_, result->ReadVariable(), hclass); @@ -174,11 +175,11 @@ void NewObjectStubBuilder::NewTaggedArrayChecked(Variable *result, GateRef len, size_ = ComputeTaggedArraySize(ZExtInt32ToPtr(len)); // Be careful. NO GC is allowed when initization is not complete. Label noException(env); - AllocateInYoung(result, exit, &noException); + auto hclass = GetGlobalConstantValue( + VariableType::JS_POINTER(), glue_, ConstantIndex::ARRAY_CLASS_INDEX); + AllocateInYoung(result, exit, &noException, hclass); Bind(&noException); { - auto hclass = GetGlobalConstantValue( - VariableType::JS_POINTER(), glue_, ConstantIndex::ARRAY_CLASS_INDEX); StoreBuiltinHClass(glue_, result->ReadVariable(), hclass); Label afterInitialize(env); InitializeTaggedArrayWithSpeicalValue(&afterInitialize, @@ -193,15 +194,15 @@ void NewObjectStubBuilder::NewMutantTaggedArrayChecked(Variable *result, GateRef auto env = GetEnvironment(); size_ = ComputeTaggedArraySize(ZExtInt32ToPtr(len)); Label afterAllocate(env); + auto hclass = GetGlobalConstantValue( + VariableType::JS_POINTER(), glue_, ConstantIndex::MUTANT_TAGGED_ARRAY_CLASS_INDEX); // Be careful. NO GC is allowed when initization is not complete. - AllocateInYoung(result, &afterAllocate); + AllocateInYoung(result, &afterAllocate, hclass); Bind(&afterAllocate); Label noException(env); BRANCH(TaggedIsException(result->ReadVariable()), exit, &noException); Bind(&noException); { - auto hclass = GetGlobalConstantValue( - VariableType::JS_POINTER(), glue_, ConstantIndex::MUTANT_TAGGED_ARRAY_CLASS_INDEX); StoreHClass(glue_, result->ReadVariable(), hclass); Label afterInitialize(env); InitializeTaggedArrayWithSpeicalValue(&afterInitialize, @@ -642,9 +643,19 @@ GateRef NewObjectStubBuilder::NewJSFunction(GateRef glue, GateRef constpool, Gat Label isAotWithCallField(env); Label afterAotWithCallField(env); + Label isJitCompiledCode(env); + Label afterJitCompiledCode(env); BRANCH(IsAotWithCallField(method), &isAotWithCallField, &afterAotWithCallField); { Bind(&isAotWithCallField); + BRANCH(IsJitCompiledCode(method), &isJitCompiledCode, &afterJitCompiledCode); + { + Bind(&isJitCompiledCode); + ClearJitCompiledCodeFlags(glue, method); + Jump(&afterAotWithCallField); + } + Bind(&afterJitCompiledCode); + SetCodeEntryToFunction(glue, *result, method); Jump(&afterAotWithCallField); } @@ -827,12 +838,13 @@ void NewObjectStubBuilder::NewArgumentsList(Variable *result, Label *exit, DEFVARIABLE(i, VariableType::INT32(), Int32(0)); Label setHClass(env); size_ = ComputeTaggedArraySize(ZExtInt32ToPtr(numArgs)); - AllocateInYoung(result, exit, &setHClass); - Bind(&setHClass); GateRef arrayClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::ARRAY_CLASS_INDEX); + AllocateInYoung(result, exit, &setHClass, arrayClass); + Bind(&setHClass); StoreHClass(glue_, result->ReadVariable(), arrayClass); Store(VariableType::INT32(), glue_, result->ReadVariable(), IntPtr(TaggedArray::LENGTH_OFFSET), numArgs); + Store(VariableType::INT32(), glue_, result->ReadVariable(), IntPtr(TaggedArray::EXTRA_LENGTH_OFFSET), Int32(0)); // skip InitializeTaggedArrayWithSpeicalValue due to immediate setting arguments Label setArgumentsBegin(env); Label setArgumentsAgain(env); @@ -889,7 +901,7 @@ void NewObjectStubBuilder::NewJSArrayLiteral(Variable *result, Label *exit, Regi auto env = GetEnvironment(); Label initializeArray(env); Label afterInitialize(env); - HeapAlloc(result, &initializeArray, spaceType); + HeapAlloc(result, &initializeArray, spaceType, hclass); Bind(&initializeArray); Store(VariableType::JS_POINTER(), glue_, result->ReadVariable(), IntPtr(0), hclass); InitializeWithSpeicalValue(&afterInitialize, result->ReadVariable(), Undefined(), Int32(JSArray::SIZE), @@ -924,21 +936,21 @@ void NewObjectStubBuilder::NewJSArrayLiteral(Variable *result, Label *exit, Regi Jump(exit); } -void NewObjectStubBuilder::HeapAlloc(Variable *result, Label *exit, RegionSpaceFlag spaceType) +void NewObjectStubBuilder::HeapAlloc(Variable *result, Label *exit, RegionSpaceFlag spaceType, GateRef hclass) { switch (spaceType) { case RegionSpaceFlag::IN_YOUNG_SPACE: - AllocateInYoung(result, exit); + AllocateInYoung(result, exit, hclass); break; default: break; } } -void NewObjectStubBuilder::AllocateInSOld(Variable *result, Label *exit) +void NewObjectStubBuilder::AllocateInSOld(Variable *result, Label *exit, GateRef hclass) { DEFVARIABLE(ret, VariableType::JS_ANY(), Undefined()); - ret = CallRuntime(glue_, RTSTUB_ID(AllocateInSOld), {IntToTaggedInt(size_)}); + ret = CallRuntime(glue_, RTSTUB_ID(AllocateInSOld), {IntToTaggedInt(size_), hclass}); result->WriteVariable(*ret); Jump(exit); } @@ -978,7 +990,7 @@ void NewObjectStubBuilder::AllocateInYoungPrologue(Variable *result, Label *call #endif } -void NewObjectStubBuilder::AllocateInYoung(Variable *result, Label *exit) +void NewObjectStubBuilder::AllocateInYoung(Variable *result, Label *exit, GateRef hclass) { auto env = GetEnvironment(); Label callRuntime(env); @@ -987,13 +999,13 @@ void NewObjectStubBuilder::AllocateInYoung(Variable *result, Label *exit) { DEFVARIABLE(ret, VariableType::JS_ANY(), Undefined()); ret = CallRuntime(glue_, RTSTUB_ID(AllocateInYoung), { - IntToTaggedInt(size_) }); + IntToTaggedInt(size_), hclass }); result->WriteVariable(*ret); Jump(exit); } } -void NewObjectStubBuilder::AllocateInYoung(Variable *result, Label *error, Label *noError) +void NewObjectStubBuilder::AllocateInYoung(Variable *result, Label *error, Label *noError, GateRef hclass) { auto env = GetEnvironment(); Label callRuntime(env); @@ -1002,7 +1014,7 @@ void NewObjectStubBuilder::AllocateInYoung(Variable *result, Label *error, Label { DEFVARIABLE(ret, VariableType::JS_ANY(), Undefined()); ret = CallRuntime(glue_, RTSTUB_ID(AllocateInYoung), { - IntToTaggedInt(size_) }); + IntToTaggedInt(size_), hclass }); result->WriteVariable(*ret); BRANCH(TaggedIsException(*ret), error, noError); } @@ -1020,7 +1032,7 @@ GateRef NewObjectStubBuilder::NewTrackInfo(GateRef glue, GateRef cachedHClass, G auto hclass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue, ConstantIndex::TRACK_INFO_CLASS_INDEX); GateRef size = GetObjectSizeFromHClass(hclass); SetParameters(glue, size); - HeapAlloc(&result, &initialize, RegionSpaceFlag::IN_YOUNG_SPACE); + HeapAlloc(&result, &initialize, RegionSpaceFlag::IN_YOUNG_SPACE, hclass); Bind(&initialize); Store(VariableType::JS_POINTER(), glue_, *result, IntPtr(0), hclass); GateRef cachedHClassOffset = IntPtr(TrackInfo::CACHED_HCLASS_OFFSET); @@ -1066,6 +1078,7 @@ void NewObjectStubBuilder::InitializeTaggedArrayWithSpeicalValue(Label *exit, GateRef array, GateRef value, GateRef start, GateRef length) { Store(VariableType::INT32(), glue_, array, IntPtr(TaggedArray::LENGTH_OFFSET), length); + Store(VariableType::INT32(), glue_, array, IntPtr(TaggedArray::EXTRA_LENGTH_OFFSET), Int32(0)); auto offset = Int32Mul(start, Int32(JSTaggedValue::TaggedTypeSize())); auto dataOffset = Int32Add(offset, Int32(TaggedArray::DATA_OFFSET)); offset = Int32Mul(length, Int32(JSTaggedValue::TaggedTypeSize())); @@ -1084,11 +1097,11 @@ void NewObjectStubBuilder::AllocLineStringObject(Variable *result, Label *exit, IntPtr(static_cast(MemAlignment::MEM_ALIGN_OBJECT))); } Label afterAllocate(env); - AllocateInSOld(result, &afterAllocate); - - Bind(&afterAllocate); GateRef stringClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::LINE_STRING_CLASS_INDEX); + AllocateInSOld(result, &afterAllocate, stringClass); + + Bind(&afterAllocate); StoreHClass(glue_, result->ReadVariable(), stringClass); SetLength(glue_, result->ReadVariable(), length, compressed); SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False()); @@ -1102,11 +1115,11 @@ void NewObjectStubBuilder::AllocSlicedStringObject(Variable *result, Label *exit size_ = AlignUp(IntPtr(SlicedString::SIZE), IntPtr(static_cast(MemAlignment::MEM_ALIGN_OBJECT))); Label afterAllocate(env); - AllocateInSOld(result, &afterAllocate); - - Bind(&afterAllocate); GateRef stringClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::SLICED_STRING_CLASS_INDEX); + AllocateInSOld(result, &afterAllocate, stringClass); + + Bind(&afterAllocate); StoreHClass(glue_, result->ReadVariable(), stringClass); GateRef mixLength = Load(VariableType::INT32(), flatString->GetFlatString(), IntPtr(EcmaString::MIX_LENGTH_OFFSET)); GateRef isCompressed = Int32And(Int32(EcmaString::STRING_COMPRESSED_BIT), mixLength); @@ -1127,11 +1140,11 @@ void NewObjectStubBuilder::AllocTreeStringObject(Variable *result, Label *exit, size_ = AlignUp(IntPtr(TreeEcmaString::SIZE), IntPtr(static_cast(MemAlignment::MEM_ALIGN_OBJECT))); Label afterAllocate(env); - AllocateInSOld(result, &afterAllocate); - - Bind(&afterAllocate); GateRef stringClass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::TREE_STRING_CLASS_INDEX); + AllocateInSOld(result, &afterAllocate, stringClass); + + Bind(&afterAllocate); StoreHClass(glue_, result->ReadVariable(), stringClass); SetLength(glue_, result->ReadVariable(), length, compressed); SetRawHashcode(glue_, result->ReadVariable(), Int32(0), False()); @@ -1503,7 +1516,7 @@ void NewObjectStubBuilder::CreateJSCollectionIterator( Label noException(env); // Be careful. NO GC is allowed when initization is not complete. - AllocateInYoung(result, exit, &noException); + AllocateInYoung(result, exit, &noException, iteratorHClass); Bind(&noException); { StoreBuiltinHClass(glue_, result->ReadVariable(), iteratorHClass); @@ -1562,4 +1575,330 @@ GateRef NewObjectStubBuilder::NewTaggedSubArray(GateRef glue, GateRef srcTypedAr env->SubCfgExit(); return ret; } + +GateRef NewObjectStubBuilder::NewTypedArray(GateRef glue, GateRef srcTypedArray, GateRef srcType, GateRef length) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + + DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); + Label slowPath(env); + Label defaultConstr(env); + Label markerCellValid(env); + Label isProtoChangeMarker(env); + Label accessorNotChanged(env); + Label exit(env); + BRANCH(HasConstructor(srcTypedArray), &slowPath, &defaultConstr); + Bind(&defaultConstr); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + GateRef markerCell = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::TYPED_ARRAY_SPECIES_PROTECT_DETECTOR_INDEX); + BRANCH(IsMarkerCellValid(markerCell), &markerCellValid, &slowPath); + Bind(&markerCellValid); + GateRef marker = GetProtoChangeMarkerFromHClass(LoadHClass(srcTypedArray)); + BRANCH(TaggedIsProtoChangeMarker(marker), &isProtoChangeMarker, &accessorNotChanged); + Bind(&isProtoChangeMarker); + BRANCH(GetAccessorHasChanged(marker), &slowPath, &accessorNotChanged); + + Bind(&accessorNotChanged); + { + DEFVARIABLE(buffer, VariableType::JS_ANY(), Undefined()); + Label next(env); + GateRef hclass = LoadHClass(srcTypedArray); + GateRef obj = NewJSObject(glue, hclass); + result = obj; + GateRef ctorName = Load(VariableType::JS_POINTER(), srcTypedArray, + IntPtr(JSTypedArray::TYPED_ARRAY_NAME_OFFSET)); + GateRef elementSize = GetElementSizeFromType(glue, srcType); + GateRef newByteLength = Int32Mul(elementSize, length); + GateRef contentType = Load(VariableType::INT32(), srcTypedArray, IntPtr(JSTypedArray::CONTENT_TYPE_OFFSET)); + BRANCH(Int32LessThanOrEqual(newByteLength, Int32(RangeInfo::TYPED_ARRAY_ONHEAP_MAX)), &next, &slowPath); + Bind(&next); + { + Label newByteArrayExit(env); + NewByteArray(&buffer, &newByteArrayExit, elementSize, length); + Bind(&newByteArrayExit); + StoreHClass(glue, obj, GetOnHeapHClassFromType(glue, srcType)); + Store(VariableType::JS_POINTER(), glue, obj, IntPtr(JSTypedArray::VIEWED_ARRAY_BUFFER_OFFSET), *buffer); + Store(VariableType::JS_POINTER(), glue, obj, IntPtr(JSTypedArray::TYPED_ARRAY_NAME_OFFSET), ctorName); + Store(VariableType::INT32(), glue, obj, IntPtr(JSTypedArray::BYTE_LENGTH_OFFSET), newByteLength); + Store(VariableType::INT32(), glue, obj, IntPtr(JSTypedArray::BYTE_OFFSET_OFFSET), Int32(0)); + Store(VariableType::INT32(), glue, obj, IntPtr(JSTypedArray::ARRAY_LENGTH_OFFSET), length); + Store(VariableType::INT32(), glue, obj, IntPtr(JSTypedArray::CONTENT_TYPE_OFFSET), contentType); + Jump(&exit); + } + } + + Bind(&slowPath); + { + result = CallRuntime(glue, RTSTUB_ID(TypedArraySpeciesCreate), + { srcTypedArray, IntToTaggedInt(Int32(1)), IntToTaggedInt(length) }); + Jump(&exit); + } + + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +void NewObjectStubBuilder::NewByteArray(Variable *result, Label *exit, GateRef elementSize, GateRef length) +{ + auto env = GetEnvironment(); + + Label noError(env); + Label initializeExit(env); + size_ = AlignUp(ComputeTaggedTypedArraySize(ZExtInt32ToPtr(elementSize), ZExtInt32ToPtr(length)), + IntPtr(static_cast(MemAlignment::MEM_ALIGN_OBJECT))); + auto hclass = GetGlobalConstantValue(VariableType::JS_POINTER(), glue_, ConstantIndex::BYTE_ARRAY_CLASS_INDEX); + AllocateInYoung(result, exit, &noError, hclass); + Bind(&noError); + { + StoreBuiltinHClass(glue_, result->ReadVariable(), hclass); + GateRef byteLength = Int32Mul(elementSize, length); + auto startOffset = Int32(ByteArray::DATA_OFFSET); + auto endOffset = Int32Add(Int32(ByteArray::DATA_OFFSET), byteLength); + InitializeWithSpeicalValue(&initializeExit, result->ReadVariable(), Int32(0), startOffset, endOffset); + Bind(&initializeExit); + Store(VariableType::INT32(), glue_, result->ReadVariable(), IntPtr(ByteArray::ARRAY_LENGTH_OFFSET), length); + Store(VariableType::INT32(), glue_, result->ReadVariable(), IntPtr(ByteArray::BYTE_LENGTH_OFFSET), elementSize); + Jump(exit); + } +} + +GateRef NewObjectStubBuilder::GetElementSizeFromType(GateRef glue, GateRef type) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + + DEFVARIABLE(result, VariableType::INT32(), Int32(0)); + Label defaultLabel(env); + Label exit(env); + Label labelBuffer[11] = { + Label(env), Label(env), Label(env), Label(env), Label(env), Label(env), + Label(env), Label(env), Label(env), Label(env), Label(env) }; + int64_t valueBuffer[11] = { + static_cast(JSType::JS_INT8_ARRAY), + static_cast(JSType::JS_UINT8_ARRAY), + static_cast(JSType::JS_UINT8_CLAMPED_ARRAY), + static_cast(JSType::JS_INT16_ARRAY), + static_cast(JSType::JS_UINT16_ARRAY), + static_cast(JSType::JS_INT32_ARRAY), + static_cast(JSType::JS_UINT32_ARRAY), + static_cast(JSType::JS_FLOAT32_ARRAY), + static_cast(JSType::JS_FLOAT64_ARRAY), + static_cast(JSType::JS_BIGINT64_ARRAY), + static_cast(JSType::JS_BIGUINT64_ARRAY) }; + + // 11 : this switch has 11 case + Switch(type, &defaultLabel, valueBuffer, labelBuffer, 11); + // 0 : index of this buffer + Bind(&labelBuffer[0]); + { + // 1 : the elementSize of this type is 1 + result = Int32(1); + Jump(&exit); + } + // 1 : index of this buffer + Bind(&labelBuffer[1]); + { + // 1 : the elementSize of this type is 1 + result = Int32(1); + Jump(&exit); + } + // 2 : index of this buffer + Bind(&labelBuffer[2]); + { + // 1 : the elementSize of this type is 1 + result = Int32(1); + Jump(&exit); + } + // 3 : index of this buffer + Bind(&labelBuffer[3]); + { + // 2 : the elementSize of this type is 2 + result = Int32(2); + Jump(&exit); + } + // 4 : index of this buffer + Bind(&labelBuffer[4]); + { + // 2 : the elementSize of this type is 2 + result = Int32(2); + Jump(&exit); + } + // 5 : index of this buffer + Bind(&labelBuffer[5]); + { + // 4 : the elementSize of this type is 4 + result = Int32(4); + Jump(&exit); + } + // 6 : index of this buffer + Bind(&labelBuffer[6]); + { + // 4 : the elementSize of this type is 4 + result = Int32(4); + Jump(&exit); + } + // 7 : index of this buffer + Bind(&labelBuffer[7]); + { + // 4 : the elementSize of this type is 4 + result = Int32(4); + Jump(&exit); + } + // 8 : index of this buffer + Bind(&labelBuffer[8]); + { + // 8 : the elementSize of this type is 8 + result = Int32(8); + Jump(&exit); + } + // 9 : index of this buffer + Bind(&labelBuffer[9]); + { + // 8 : the elementSize of this type is 8 + result = Int32(8); + Jump(&exit); + } + // 10 : index of this buffer + Bind(&labelBuffer[10]); + { + // 8 : the elementSize of this type is 8 + result = Int32(8); + Jump(&exit); + } + Bind(&defaultLabel); + { + FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) }); + Jump(&exit); + } + + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} + +GateRef NewObjectStubBuilder::GetOnHeapHClassFromType(GateRef glue, GateRef type) +{ + auto env = GetEnvironment(); + Label entry(env); + env->SubCfgEntry(&entry); + + DEFVARIABLE(result, VariableType::JS_ANY(), Undefined()); + GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); + GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); + Label defaultLabel(env); + Label exit(env); + Label labelBuffer[11] = { + Label(env), Label(env), Label(env), Label(env), Label(env), Label(env), + Label(env), Label(env), Label(env), Label(env), Label(env) }; + int64_t valueBuffer[11] = { + static_cast(JSType::JS_INT8_ARRAY), + static_cast(JSType::JS_UINT8_ARRAY), + static_cast(JSType::JS_UINT8_CLAMPED_ARRAY), + static_cast(JSType::JS_INT16_ARRAY), + static_cast(JSType::JS_UINT16_ARRAY), + static_cast(JSType::JS_INT32_ARRAY), + static_cast(JSType::JS_UINT32_ARRAY), + static_cast(JSType::JS_FLOAT32_ARRAY), + static_cast(JSType::JS_FLOAT64_ARRAY), + static_cast(JSType::JS_BIGINT64_ARRAY), + static_cast(JSType::JS_BIGUINT64_ARRAY) }; + + // 11 : this switch has 11 case + Switch(type, &defaultLabel, valueBuffer, labelBuffer, 11); + // 0 : index of this buffer + Bind(&labelBuffer[0]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::INT8_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 1 : index of this buffer + Bind(&labelBuffer[1]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::UINT8_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 2 : index of this buffer + Bind(&labelBuffer[2]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::UINT8_CLAMPED_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 3 : index of this buffer + Bind(&labelBuffer[3]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::INT16_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 4 : index of this buffer + Bind(&labelBuffer[4]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::UINT16_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 5 : index of this buffer + Bind(&labelBuffer[5]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::INT32_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 6 : index of this buffer + Bind(&labelBuffer[6]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::UINT32_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 7 : index of this buffer + Bind(&labelBuffer[7]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::FLOAT32_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 8 : index of this buffer + Bind(&labelBuffer[8]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::FLOAT64_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 9 : index of this buffer + Bind(&labelBuffer[9]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::BIGINT64_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + // 10 : index of this buffer + Bind(&labelBuffer[10]); + { + result = GetGlobalEnvValue(VariableType::JS_ANY(), glueGlobalEnv, + GlobalEnv::BIGUINT64_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX); + Jump(&exit); + } + Bind(&defaultLabel); + { + FatalPrint(glue, { Int32(GET_MESSAGE_STRING_ID(ThisBranchIsUnreachable)) }); + Jump(&exit); + } + + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/new_object_stub_builder.h b/ecmascript/compiler/new_object_stub_builder.h index 243a75096a8924f4bda1ef6ac8b35d6af1dedb14..28d058eb45e23544affb95251ace551133818956 100644 --- a/ecmascript/compiler/new_object_stub_builder.h +++ b/ecmascript/compiler/new_object_stub_builder.h @@ -66,7 +66,7 @@ public: FlatStringStubBuilder *flatString); void AllocTreeStringObject(Variable *result, Label *exit, GateRef first, GateRef second, GateRef length, bool compressed); - void HeapAlloc(Variable *result, Label *exit, RegionSpaceFlag spaceType); + void HeapAlloc(Variable *result, Label *exit, RegionSpaceFlag spaceType, GateRef hclass); void NewJSArrayLiteral(Variable *result, Label *exit, RegionSpaceFlag spaceType, GateRef obj, GateRef hclass, GateRef trackInfo, bool isEmptyArray); GateRef NewTrackInfo(GateRef glue, GateRef cachedHClass, GateRef cachedFunc, RegionSpaceFlag spaceFlag, @@ -87,6 +87,10 @@ public: void CreateJSCollectionIterator(Variable *result, Label *exit, GateRef set, GateRef kind); GateRef NewTaggedSubArray(GateRef glue, GateRef srcTypedArray, GateRef elementSize, GateRef newLength, GateRef beginIndex, GateRef arrayCls, GateRef buffer); + GateRef NewTypedArray(GateRef glue, GateRef srcTypedArray, GateRef srcType, GateRef length); + void NewByteArray(Variable *result, Label *exit, GateRef elementSize, GateRef length); + GateRef GetElementSizeFromType(GateRef glue, GateRef type); + GateRef GetOnHeapHClassFromType(GateRef glue, GateRef type); private: static constexpr int MAX_TAGGED_ARRAY_LENGTH = 50; @@ -96,9 +100,9 @@ private: GateRef glue, GateRef jsFunc, GateRef pc, GateRef arrayLiteral, ProfileOperation callback); GateRef CreateEmptyArrayCommon(GateRef glue, GateRef hclass, GateRef trackInfo); void AllocateInYoungPrologue(Variable *result, Label *callRuntime, Label *exit); - void AllocateInYoung(Variable *result, Label *exit); - void AllocateInYoung(Variable *result, Label *error, Label *noError); - void AllocateInSOld(Variable *result, Label *exit); + void AllocateInYoung(Variable *result, Label *exit, GateRef hclass); + void AllocateInYoung(Variable *result, Label *error, Label *noError, GateRef hclass); + void AllocateInSOld(Variable *result, Label *exit, GateRef hclass); void InitializeTaggedArrayWithSpeicalValue(Label *exit, GateRef array, GateRef value, GateRef start, GateRef length); GateRef glue_ {Circuit::NullGate()}; diff --git a/ecmascript/compiler/ntype_bytecode_lowering.cpp b/ecmascript/compiler/ntype_bytecode_lowering.cpp index 6b6fc1658cdbd6252f7deeb2f3d365aeef81772a..e1286903c9d6e19067d2011a1e3b75774063fcf4 100644 --- a/ecmascript/compiler/ntype_bytecode_lowering.cpp +++ b/ecmascript/compiler/ntype_bytecode_lowering.cpp @@ -14,9 +14,10 @@ */ #include "ecmascript/compiler/ntype_bytecode_lowering.h" -#include "ecmascript/compiler/circuit_builder-inl.h" -#include "ecmascript/dfx/vmstat/opt_code_profiler.h" + #include "ecmascript/compiler/type_info_accessors.h" +#include "ecmascript/dfx/vmstat/opt_code_profiler.h" +#include "ecmascript/jspandafile/program_object.h" namespace panda::ecmascript::kungfu { @@ -204,8 +205,8 @@ void NTypeBytecodeLowering::LowerNTypedCreateArrayWithBuffer(GateRef gate) GateRef index = acc_.GetValueIn(gate, 0); uint32_t cpIdx = static_cast(acc_.GetConstantValue(index)); auto methodOffset = acc_.TryGetMethodOffset(gate); - uint32_t cpId = tsManager_->GetConstantPoolId(methodOffset); - JSTaggedValue cp = tsManager_->GetConstantPool(methodOffset); + uint32_t cpId = ptManager_->GetConstantPoolIDByMethodOffset(methodOffset); + JSTaggedValue cp = ptManager_->GetConstantPoolByMethodOffset(methodOffset); panda_file::File::EntityId id = ConstantPool::GetIdFromCache(cp, cpIdx); int elementIndex = ptManager_->GetElementsIndexByEntityId(id); @@ -301,19 +302,21 @@ void NTypeBytecodeLowering::AddProfiling(GateRef gate) current = gate; } + GateRef func = builder_.Undefined(); if (acc_.HasFrameState(gate)) { - GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); - GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate))); - EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate); - auto ecmaOpcodeGate = builder_.Int32(static_cast(ecmaOpcode)); - GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate); - GateRef mode = - builder_.Int32ToTaggedInt(builder_.Int32(static_cast(OptCodeProfiler::Mode::TYPED_PATH))); - GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current), - { func, bcIndex, constOpcode, mode }, gate); - acc_.SetDep(current, profiling); - builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT + func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); } + + GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate))); + EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate); + auto ecmaOpcodeGate = builder_.Int32(static_cast(ecmaOpcode)); + GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate); + GateRef mode = + builder_.Int32ToTaggedInt(builder_.Int32(static_cast(OptCodeProfiler::Mode::TYPED_PATH))); + GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current), + { func, bcIndex, constOpcode, mode }, gate); + acc_.SetDep(current, profiling); + builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT } } diff --git a/ecmascript/compiler/ntype_bytecode_lowering.h b/ecmascript/compiler/ntype_bytecode_lowering.h index 1c48b74f6c017d20499745a01b65ab0aa17c7bb8..31ff0a5226942ea31651a5e437f83c3601a6b06d 100644 --- a/ecmascript/compiler/ntype_bytecode_lowering.h +++ b/ecmascript/compiler/ntype_bytecode_lowering.h @@ -17,20 +17,16 @@ #define ECMASCRIPT_COMPILER_NTYPE_BYTECODE_LOWERING_H #include "ecmascript/compiler/argument_accessor.h" -#include "ecmascript/compiler/builtins/builtins_call_signature.h" -#include "ecmascript/compiler/bytecode_circuit_builder.h" -#include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/pass_manager.h" namespace panda::ecmascript::kungfu { class NTypeBytecodeLowering { public: - NTypeBytecodeLowering(Circuit *circuit, PassContext *ctx, TSManager *tsManager, + NTypeBytecodeLowering(Circuit *circuit, PassContext *ctx, bool enableLog, const std::string& name) : circuit_(circuit), acc_(circuit), builder_(circuit, ctx->GetCompilerConfig()), - tsManager_(tsManager), ptManager_(ctx->GetPTManager()), jsPandaFile_(ctx->GetJSPandaFile()), enableLog_(enableLog), @@ -89,7 +85,6 @@ private: Circuit *circuit_ {nullptr}; GateAccessor acc_; CircuitBuilder builder_; - TSManager *tsManager_ {nullptr}; PGOTypeManager *ptManager_ {nullptr}; const JSPandaFile *jsPandaFile_ {nullptr}; bool enableLog_ {false}; diff --git a/ecmascript/compiler/ntype_hcr_lowering.cpp b/ecmascript/compiler/ntype_hcr_lowering.cpp index 2e7a5db43c7ad1e1fea43dc29ce94a15f1d219be..56bbeb5a1a6697dd9783dd60b4a1a2d58f6f967f 100644 --- a/ecmascript/compiler/ntype_hcr_lowering.cpp +++ b/ecmascript/compiler/ntype_hcr_lowering.cpp @@ -13,13 +13,9 @@ * limitations under the License. */ -#include "ecmascript/js_arguments.h" #include "ecmascript/compiler/ntype_hcr_lowering.h" -#include "ecmascript/dfx/vmstat/opt_code_profiler.h" -#include "ecmascript/compiler/new_object_stub_builder.h" namespace panda::ecmascript::kungfu { - GateRef NTypeHCRLowering::VisitGate(GateRef gate) { GateRef glue = acc_.GetGlueFromArgList(); @@ -172,15 +168,14 @@ GateRef NTypeHCRLowering::NewJSArrayLiteral(GateRef glue, GateRef gate, GateRef ElementsKind kind = acc_.GetArrayMetaDataAccessor(gate).GetElementsKind(); GateRef hclass = Circuit::NullGate(); if (!Elements::IsGeneric(kind)) { - auto thread = tsManager_->GetEcmaVM()->GetJSThread(); - auto hclassIndex = thread->GetArrayHClassIndexMap().at(kind); + auto hclassIndex = thread_->GetArrayHClassIndexMap().at(kind); hclass = builder_.GetGlobalConstantValue(hclassIndex); } else { GateRef globalEnv = builder_.GetGlobalEnv(); hclass = builder_.GetGlobalEnvObjHClass(globalEnv, GlobalEnv::ARRAY_FUNCTION_INDEX); } - JSHandle arrayFunc(tsManager_->GetEcmaVM()->GetGlobalEnv()->GetArrayFunction()); + JSHandle arrayFunc(thread_->GetEcmaVM()->GetGlobalEnv()->GetArrayFunction()); JSTaggedValue protoOrHClass = arrayFunc->GetProtoOrHClass(); JSHClass *arrayHC = JSHClass::Cast(protoOrHClass.GetTaggedObject()); size_t arraySize = arrayHC->GetObjectSize(); diff --git a/ecmascript/compiler/ntype_hcr_lowering.h b/ecmascript/compiler/ntype_hcr_lowering.h index 6732adbd79bab7625afc32a42900adb43b5ffd4d..a524ee37f44fd423174c0cd8ecf46d592dbcd9a9 100644 --- a/ecmascript/compiler/ntype_hcr_lowering.h +++ b/ecmascript/compiler/ntype_hcr_lowering.h @@ -16,12 +16,9 @@ #ifndef ECMASCRIPT_COMPILER_NTYPE_HCR_LOWERING_H #define ECMASCRIPT_COMPILER_NTYPE_HCR_LOWERING_H -#include "ecmascript/compiler/argument_accessor.h" -#include "ecmascript/compiler/builtins/builtins_call_signature.h" -#include "ecmascript/compiler/bytecode_circuit_builder.h" -#include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/combined_pass_visitor.h" #include "ecmascript/compiler/pass_manager.h" +#include "ecmascript/jspandafile/program_object.h" namespace panda::ecmascript::kungfu { class NTypeHCRLowering : public PassVisitor { @@ -33,7 +30,6 @@ public: thread_(ctx->GetEcmaVM()->GetJSThread()), builder_(circuit, ctx->GetCompilerConfig()), dependEntry_(circuit->GetDependRoot()), - tsManager_(ctx->GetTSManager()), jsPandaFile_(ctx->GetJSPandaFile()), recordName_(recordName), profiling_(ctx->GetCompilerConfig()->IsProfiling()), @@ -74,7 +70,7 @@ private: JSTaggedValue GetArrayLiteralValue(uint32_t cpId, uint32_t cpIdx) { JSTaggedValue cp = GetConstantpoolValue(cpId); - JSTaggedValue unsharedCp = thread_->GetCurrentEcmaContext()->FindUnsharedConstpool(cp); + JSTaggedValue unsharedCp = thread_->GetCurrentEcmaContext()->FindOrCreateUnsharedConstpool(cp); return ConstantPool::GetLiteralFromCache( thread_, unsharedCp, cpIdx, recordName_); } @@ -84,7 +80,6 @@ private: JSThread *thread_ {nullptr}; CircuitBuilder builder_; GateRef dependEntry_; - TSManager *tsManager_ {nullptr}; const JSPandaFile *jsPandaFile_ {nullptr}; const CString &recordName_; panda_file::File::EntityId methodId_ {0}; diff --git a/ecmascript/compiler/number_speculative_lowering.cpp b/ecmascript/compiler/number_speculative_lowering.cpp index 5f5027a5b01901f3440acd4fed354ace0bfe7026..27f0908a0ec64652d65e2c1658ba4128d904bdf1 100644 --- a/ecmascript/compiler/number_speculative_lowering.cpp +++ b/ecmascript/compiler/number_speculative_lowering.cpp @@ -73,11 +73,6 @@ void NumberSpeculativeLowering::VisitGate(GateRef gate) VisitConstant(gate); break; } - case OpCode::TYPED_CALL_BUILTIN: - case OpCode::TYPED_CALL_BUILTIN_SIDE_EFFECT:{ - VisitCallBuiltins(gate); - break; - } case OpCode::LOAD_ELEMENT: { VisitLoadElement(gate); break; @@ -107,6 +102,10 @@ void NumberSpeculativeLowering::VisitGate(GateRef gate) VisitLoadPropertyOnProto(gate); break; } + case OpCode::MATH_ROUND: { + VisitRound(gate); + break; + } default: break; } @@ -132,7 +131,7 @@ void NumberSpeculativeLowering::VisitTypedBinaryOp(GateRef gate) break; } default: { - if (acc_.HasPrimitiveNumberType(gate)) { + if (acc_.HasNumberType(gate)) { VisitNumberBinaryOp(gate); } break; @@ -280,7 +279,7 @@ void NumberSpeculativeLowering::VisitTypedUnaryOp(GateRef gate) void NumberSpeculativeLowering::VisitTypedConditionJump(GateRef gate) { Environment env(gate, circuit_, &builder_); - GateType type = acc_.GetTypedJumpAccessor(gate).GetTypeValue(); + ParamType type = acc_.GetTypedJumpAccessor(gate).GetParamType(); if (type.IsBooleanType()) { VisitBooleanJump(gate); } else { @@ -293,17 +292,11 @@ void NumberSpeculativeLowering::VisitNumberCalculate(GateRef gate) { GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); - GateType gateType = acc_.GetGateType(gate); - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - gateType = GateType::IntType(); - } else { - gateType = GateType::DoubleType(); - } - } + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); GateRef result = Circuit::NullGate(); - if (gateType.IsIntType()) { + if (paramType.IsIntType()) { result = CalculateInts(left, right); // int op int UpdateRange(result, GetRange(gate)); acc_.SetMachineType(gate, MachineType::I32); @@ -320,20 +313,11 @@ void NumberSpeculativeLowering::VisitNumberCompare(GateRef gate) { GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); - GateType leftType = acc_.GetLeftType(gate); - GateType rightType = acc_.GetRightType(gate); - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - leftType = GateType::IntType(); - rightType = GateType::IntType(); - } else { - leftType = GateType::NumberType(); - rightType = GateType::NumberType(); - } - } + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); GateRef result = Circuit::NullGate(); - if (leftType.IsIntType() && rightType.IsIntType()) { + if (paramType.IsIntType()) { result = CompareInts(left, right); // int op int } else { result = CompareDoubles(left, right); // float op float @@ -371,17 +355,11 @@ void NumberSpeculativeLowering::VisitNumberDiv(GateRef gate) { GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); - GateType gateType = acc_.GetGateType(gate); - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - gateType = GateType::IntType(); - } else { - gateType = GateType::DoubleType(); - } - } + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); GateRef result = Circuit::NullGate(); - if (gateType.IsIntType()) { + if (paramType.IsIntType()) { result = builder_.Int32DivWithCheck(left, right); acc_.SetMachineType(gate, MachineType::I32); } else { @@ -398,19 +376,11 @@ void NumberSpeculativeLowering::VisitNumberMod(GateRef gate) { GateRef left = acc_.GetValueIn(gate, 0); GateRef right = acc_.GetValueIn(gate, 1); - GateType gateType = acc_.GetGateType(gate); - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - gateType = GateType::IntType(); - } else if (sampleType->IsDouble()) { - gateType = GateType::DoubleType(); - } else { - gateType = GateType::NumberType(); - } - } + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); GateRef result = Circuit::NullGate(); - if (gateType.IsIntType()) { + if (paramType.IsIntType()) { if (GetRange(right).MaybeZero()) { builder_.Int32CheckRightIsZero(right); } @@ -435,8 +405,8 @@ template void NumberSpeculativeLowering::VisitNumberMonocular(GateRef gate) { TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); - GateType type = accessor.GetTypeValue(); - ASSERT(type.IsPrimitiveNumberType()); + ParamType type = accessor.GetParamType(); + ASSERT(type.HasNumberType()); GateRef value = acc_.GetValueIn(gate, 0); GateRef result = Circuit::NullGate(); if (type.IsIntType()) { @@ -456,7 +426,7 @@ void NumberSpeculativeLowering::VisitNumberMonocular(GateRef gate) void NumberSpeculativeLowering::VisitNumberNot(GateRef gate) { - ASSERT(TypedUnaryAccessor(acc_.TryGetValue(gate)).GetTypeValue().IsPrimitiveNumberType()); + ASSERT(TypedUnaryAccessor(acc_.TryGetValue(gate)).GetParamType().HasNumberType()); GateRef value = acc_.GetValueIn(gate, 0); GateRef result = builder_.Int32Not(value); UpdateRange(result, GetRange(gate)); @@ -529,19 +499,6 @@ void NumberSpeculativeLowering::VisitUndefinedEqOrUndefinedNotEq(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } -void NumberSpeculativeLowering::VisitCallBuiltins(GateRef gate) -{ - auto valuesIn = acc_.GetNumValueIn(gate); - auto idGate = acc_.GetValueIn(gate, valuesIn - 1); - auto id = static_cast(acc_.GetConstantValue(idGate)); - if (id != BUILTINS_STUB_ID(SQRT)) { - return; - } - - BuiltinLowering lowering(circuit_); - lowering.LowerTypedSqrt(gate); -} - void NumberSpeculativeLowering::VisitConstant(GateRef gate) { TypeInfo output = GetOutputType(gate); @@ -1054,4 +1011,14 @@ void NumberSpeculativeLowering::VisitLoadPropertyOnProto(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } } + +void NumberSpeculativeLowering::VisitRound(GateRef gate) +{ + TypeInfo output = GetOutputType(gate); + GateRef in = acc_.GetValueIn(gate, 0); + if (output == TypeInfo::INT32) { + acc_.ReplaceGate(gate, in); + } +} + } // namespace panda::ecmascript diff --git a/ecmascript/compiler/number_speculative_lowering.h b/ecmascript/compiler/number_speculative_lowering.h index 582c5a6018c28e64f51128a9f5d4a6e4b1f5df05..27075dcc622bb204e4be8b35b02030375e704bc3 100644 --- a/ecmascript/compiler/number_speculative_lowering.h +++ b/ecmascript/compiler/number_speculative_lowering.h @@ -46,7 +46,6 @@ private: void VisitUndefinedStrictEqOrUndefinedStrictNotEq(GateRef gate); void VisitUndefinedEqOrUndefinedNotEq(GateRef gate); void VisitEqualOrNotEqual(GateRef gate); - void VisitCallBuiltins(GateRef gate); void VisitRangeGuard(GateRef gate); void VisitRangeCheckPredicate(GateRef gate); void VisitIndexCheck(GateRef gate); @@ -55,6 +54,8 @@ private: void VisitLoadElement(GateRef gate); void VisitLoadProperty(GateRef gate); void VisitLoadPropertyOnProto(GateRef gate); + void VisitRound(GateRef gate); + void VisitFRound(GateRef gate); template void VisitNumberCalculate(GateRef gate); diff --git a/ecmascript/compiler/number_speculative_retype.cpp b/ecmascript/compiler/number_speculative_retype.cpp index 3f2eafaf503187d95aa6248be331f2307d6d0ca6..4f905dfa6aaac4c2996792a9b684c636bff46364 100644 --- a/ecmascript/compiler/number_speculative_retype.cpp +++ b/ecmascript/compiler/number_speculative_retype.cpp @@ -14,11 +14,17 @@ */ #include "ecmascript/compiler/number_speculative_retype.h" + +#include "ecmascript/compiler/builtins/builtins_call_signature.h" +#include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/circuit_builder-inl.h" -#include "ecmascript/compiler/share_gate_meta_data.h" +#include "ecmascript/compiler/circuit_builder.h" #include "ecmascript/compiler/number_gate_info.h" +#include "ecmascript/compiler/rt_call_signature.h" +#include "ecmascript/compiler/share_gate_meta_data.h" +#include "ecmascript/compiler/share_opcodes.h" #include "ecmascript/compiler/type.h" -#include +#include "ecmascript/compiler/variable_type.h" namespace panda::ecmascript::kungfu { GateRef NumberSpeculativeRetype::SetOutputType(GateRef gate, GateType gateType) @@ -38,14 +44,22 @@ GateRef NumberSpeculativeRetype::SetOutputType(GateRef gate, GateType gateType) return old == type ? Circuit::NullGate() : gate; } -GateRef NumberSpeculativeRetype::SetOutputType(GateRef gate, PGOSampleType pgoType) +GateRef NumberSpeculativeRetype::SetOutputType(GateRef gate, ParamType paramType) { TypeInfo type = GetOutputTypeInfo(gate); TypeInfo old = type; - if (pgoType.IsInt()) { + if (paramType.IsIntType()) { type = TypeInfo::INT32; - } else { + } else if (paramType.IsNumberType()) { + type = TypeInfo::FLOAT64; + } else if (paramType.IsDoubleType()) { + type = TypeInfo::FLOAT64; + } else if (paramType.IsIntOverflowType()) { type = TypeInfo::FLOAT64; + } else if (paramType.IsBooleanType()) { + type = TypeInfo::INT1; + } else { + type = TypeInfo::TAGGED; } SetOutputTypeInfo(gate, type); return old == type ? Circuit::NullGate() : gate; @@ -72,6 +86,49 @@ GateRef NumberSpeculativeRetype::SetOutputType(GateRef gate, TypeInfo type) SetOutputTypeInfo(gate, type); return old == type ? Circuit::NullGate() : gate; } + +TypeInfo NumberSpeculativeRetype::GetNumberTypeInfo(GateRef gate) +{ + TypeInfo typeInfo = GetOutputTypeInfo(gate); + switch (typeInfo) { + case TypeInfo::INT1: + case TypeInfo::INT32: + case TypeInfo::HOLE_INT: + return TypeInfo::INT32; + case TypeInfo::UINT32: + case TypeInfo::FLOAT64: + case TypeInfo::HOLE_DOUBLE: + return TypeInfo::FLOAT64; + case TypeInfo::NONE: + case TypeInfo::TAGGED: { + GateType gateType = acc_.GetGateType(gate); + if (gateType.IsIntType() || gateType.IsBooleanType()) { + return TypeInfo::INT32; + } else if (gateType.IsDoubleType()) { + return TypeInfo::FLOAT64; + } else { + return TypeInfo::TAGGED; + } + } + case TypeInfo::CHAR: + return TypeInfo::TAGGED; + } + UNREACHABLE(); +} + +static TypeInfo GetCommonTypeInfo(TypeInfo left, TypeInfo right) +{ + if (left == TypeInfo::TAGGED || right == TypeInfo::TAGGED) { + return TypeInfo::TAGGED; + } + ASSERT(left == TypeInfo::INT32 || left == TypeInfo::FLOAT64); + ASSERT(right == TypeInfo::INT32 || right == TypeInfo::FLOAT64); + if (left == right) { + return left; + } + return TypeInfo::FLOAT64; +} + void NumberSpeculativeRetype::setState(NumberSpeculativeRetype::State state) { state_ = state; @@ -115,9 +172,6 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate) return VisitPhi(gate); case OpCode::CONSTANT: return VisitConstant(gate); - case OpCode::TYPED_CALL_BUILTIN: - case OpCode::TYPED_CALL_BUILTIN_SIDE_EFFECT: - return VisitCallBuiltins(gate); case OpCode::TYPE_CONVERT: return VisitTypeConvert(gate); case OpCode::FRAME_STATE: @@ -138,6 +192,8 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate) case OpCode::MATH_LOG2: case OpCode::MATH_LOG10: case OpCode::MATH_LOG1P: + case OpCode::MATH_EXP: + case OpCode::MATH_EXPM1: case OpCode::MATH_ACOS: case OpCode::MATH_ACOSH: case OpCode::MATH_ASIN: @@ -149,13 +205,42 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate) case OpCode::MATH_COSH: case OpCode::MATH_SIN: case OpCode::MATH_SINH: + case OpCode::MATH_SQRT: case OpCode::MATH_TAN: case OpCode::MATH_TANH: case OpCode::MATH_POW: - return VisitMathBuiltin(gate); + case OpCode::MATH_CBRT: + case OpCode::MATH_FROUND: + case OpCode::MATH_CEIL: + case OpCode::MATH_FLOOR: + return VisitMathDoubleParamsBuiltin(gate); + case OpCode::MATH_CLZ32: + return VisitClz32Builtin(gate); case OpCode::MATH_ABS: - return VisitMathAbs(gate); + case OpCode::MATH_MIN: + case OpCode::MATH_MAX: + case OpCode::MATH_SIGN: + case OpCode::MATH_ROUND: + return VisitMathTaggedNumberParamsBuiltin(gate); + case OpCode::MATH_TRUNC: + return VisitMathTrunc(gate); + case OpCode::GLOBAL_IS_FINITE: + case OpCode::NUMBER_IS_FINITE: + return VisitNumberOrGlobalBuiltin(gate); + case OpCode::GLOBAL_IS_NAN: + case OpCode::NUMBER_IS_NAN: + return VisitNumberOrGlobalBuiltin(gate); + case OpCode::NUMBER_IS_INTEGER: + case OpCode::NUMBER_IS_SAFEINTEGER: + return VisitNumberIsInteger(gate); + case OpCode::MATH_IMUL: + return VisitMathImul(gate); + case OpCode::DATA_VIEW_GET: + return VisitDataViewGet(gate); + case OpCode::DATA_VIEW_SET: + return VisitDataViewSet(gate); case OpCode::JS_BYTECODE: + case OpCode::RUNTIME_CALL: case OpCode::PRIMITIVE_TYPE_CHECK: case OpCode::STABLE_ARRAY_CHECK: case OpCode::TYPED_ARRAY_CHECK: @@ -166,6 +251,7 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate) case OpCode::TYPED_SUPER_ALLOCATE_THIS: case OpCode::GET_SUPER_CONSTRUCTOR: case OpCode::ARG: + case OpCode::INITVREG: case OpCode::RETURN: case OpCode::FRAME_ARGS: case OpCode::SAVE_REGISTER: @@ -183,6 +269,9 @@ GateRef NumberSpeculativeRetype::VisitGate(GateRef gate) case OpCode::ECMA_STRING_CHECK: case OpCode::CREATE_ARGUMENTS: case OpCode::TAGGED_TO_INT64: + case OpCode::TYPED_CALL_BUILTIN: + case OpCode::TYPED_CALL_BUILTIN_SIDE_EFFECT: + case OpCode::MAP_GET: return VisitOthers(gate); default: return Circuit::NullGate(); @@ -199,7 +288,7 @@ GateRef NumberSpeculativeRetype::VisitTypedBinaryOp(GateRef gate) acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_STRICTNOTEQ && acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_EQ && acc_.GetTypedBinaryOp(gate) != TypedBinOp::TYPED_NOTEQ) { - if (acc_.HasPrimitiveNumberType(gate)) { + if (acc_.HasNumberType(gate)) { return VisitNumberBinaryOp(gate); } } @@ -338,8 +427,7 @@ GateRef NumberSpeculativeRetype::VisitStringAdd(GateRef gate) GateRef input = acc_.GetValueIn(gate, i); TypeInfo inputInfo = GetOutputTypeInfo(input); if (inputInfo == TypeInfo::CHAR) { - GateRef glue = acc_.GetGlueFromArgList(); - input = builder_.CallStub(glue, gate, CommonStubCSigns::CreateStringBySingleCharCode, { glue, input }); + input = builder_.ConvertCharToEcmaString(input); } acc_.ReplaceValueIn(gate, input, i); } @@ -459,8 +547,11 @@ GateRef NumberSpeculativeRetype::VisitNumberBinaryOp(GateRef gate) case TypedBinOp::TYPED_XOR: { return VisitNumberShiftAndLogical(gate); } - default: - return VisitNumberRelated(gate); + default: { + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + return VisitNumberRelated(gate, paramType); + } } } @@ -478,16 +569,19 @@ GateRef NumberSpeculativeRetype::VisitTypedUnaryOp(GateRef gate) case TypedUnOp::TYPED_ISFALSE: case TypedUnOp::TYPED_ISTRUE: return VisitIsTrueOrFalse(gate); - default: - return VisitNumberRelated(gate); + default: { + TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); + ParamType paramType = accessor.GetParamType(); + return VisitNumberRelated(gate, paramType); + } } } GateRef NumberSpeculativeRetype::VisitTypedConditionJump(GateRef gate) { Environment env(gate, circuit_, &builder_); - TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); - auto type = accessor.GetTypeValue(); + TypedJumpAccessor accessor(acc_.TryGetValue(gate)); + ParamType type = accessor.GetParamType(); if (type.IsBooleanType()) { return VisitBooleanJump(gate); } else { @@ -499,17 +593,13 @@ GateRef NumberSpeculativeRetype::VisitTypedConditionJump(GateRef gate) GateRef NumberSpeculativeRetype::VisitNumberCalculate(GateRef gate) { if (IsRetype()) { - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - return SetOutputType(gate, *sampleType); - } else { - GateType gateType = acc_.GetGateType(gate); - GateType resType = gateType.IsIntType() ? GateType::IntType() : GateType::DoubleType(); - return SetOutputType(gate, resType); - } + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); + return SetOutputType(gate, paramType); } else if (IsConvert()) { Environment env(gate, circuit_, &builder_); - ConvertForBinaryOp(gate); + ConvertForNumberBinaryOp(gate); } return Circuit::NullGate(); } @@ -521,7 +611,7 @@ GateRef NumberSpeculativeRetype::VisitNumberCompare(GateRef gate) } if (IsConvert()) { Environment env(gate, circuit_, &builder_); - ConvertForCompareOp(gate); + ConvertForNumberCompareOp(gate); } return Circuit::NullGate(); } @@ -533,19 +623,7 @@ GateRef NumberSpeculativeRetype::VisitNumberShiftAndLogical(GateRef gate) } if (IsConvert()) { Environment env(gate, circuit_, &builder_); - GateType leftType = acc_.GetLeftType(gate); - GateType rightType = acc_.GetRightType(gate); - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - leftType = GateType::IntType(); - rightType = GateType::IntType(); - } else { - leftType = GateType::NumberType(); - rightType = GateType::NumberType(); - } - } - ConvertForShiftAndLogicalOperator(gate, leftType, rightType); + ConvertForNumberShiftAndLogicalOperator(gate); } return Circuit::NullGate(); } @@ -553,8 +631,8 @@ GateRef NumberSpeculativeRetype::VisitNumberShiftAndLogical(GateRef gate) GateRef NumberSpeculativeRetype::VisitNumberMonocular(GateRef gate) { TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); - GateType type = accessor.GetTypeValue(); - ASSERT(type.IsPrimitiveNumberType()); + ParamType type = accessor.GetParamType(); + ASSERT(type.HasNumberType()); if (type.IsIntType()) { return VisitIntMonocular(gate); } else { @@ -585,8 +663,15 @@ GateRef NumberSpeculativeRetype::VisitDoubleMonocular(GateRef gate) if (IsConvert()) { TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); + ParamType paramType = accessor.GetParamType(); GateRef value = acc_.GetValueIn(gate, 0); - acc_.ReplaceValueIn(gate, CheckAndConvertToFloat64(value, accessor.GetTypeValue()), 0); + GateType valueType = GateType::NumberType(); + if (paramType.IsIntType()) { + valueType = GateType::IntType(); + } else if (paramType.IsDoubleType()) { + valueType = GateType::DoubleType(); + } + acc_.ReplaceValueIn(gate, CheckAndConvertToFloat64(value, valueType), 0); acc_.ReplaceStateIn(gate, builder_.GetState()); acc_.ReplaceDependIn(gate, builder_.GetDepend()); } @@ -596,14 +681,23 @@ GateRef NumberSpeculativeRetype::VisitDoubleMonocular(GateRef gate) GateRef NumberSpeculativeRetype::VisitIsTrueOrFalse(GateRef gate) { TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); - GateType valueType = accessor.GetTypeValue(); - ASSERT(valueType.IsPrimitiveNumberType()); + ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType() || paramType.IsBooleanType()); if (IsRetype()) { return SetOutputType(gate, GateType::BooleanType()); } if (IsConvert()) { Environment env(gate, circuit_, &builder_); GateRef value = acc_.GetValueIn(gate, 0); + GateType valueType = GateType::NumberType(); + // NOTICE-PGO: wx support undefined + if (paramType.IsIntType()) { + valueType = GateType::IntType(); + } else if (paramType.IsDoubleType()) { + valueType = GateType::DoubleType(); + } else if (paramType.IsBooleanType()) { + valueType = GateType::BooleanType(); + } auto input = CheckAndConvertToBool(value, valueType); ResizeAndSetTypeInfo(input, TypeInfo::INT1); acc_.ReplaceValueIn(gate, input, 0); @@ -616,14 +710,20 @@ GateRef NumberSpeculativeRetype::VisitIsTrueOrFalse(GateRef gate) GateRef NumberSpeculativeRetype::VisitNumberNot(GateRef gate) { TypedUnaryAccessor accessor(acc_.TryGetValue(gate)); - GateType valueType = accessor.GetTypeValue(); - ASSERT(valueType.IsPrimitiveNumberType()); + ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); if (IsRetype()) { return SetOutputType(gate, GateType::IntType()); } if (IsConvert()) { Environment env(gate, circuit_, &builder_); GateRef value = acc_.GetValueIn(gate, 0); + GateType valueType = GateType::NumberType(); + if (paramType.IsIntType()) { + valueType = GateType::IntType(); + } else if (paramType.IsDoubleType()) { + valueType = GateType::DoubleType(); + } acc_.ReplaceValueIn(gate, CheckAndConvertToInt32(value, valueType, ConvertSupport::ENABLE, OpType::SHIFT_AND_LOGICAL), 0); acc_.ReplaceStateIn(gate, builder_.GetState()); @@ -655,7 +755,7 @@ GateRef NumberSpeculativeRetype::VisitBooleanJump(GateRef gate) return Circuit::NullGate(); } -GateRef NumberSpeculativeRetype::VisitNumberRelated(GateRef gate) +GateRef NumberSpeculativeRetype::VisitNumberRelated(GateRef gate, ParamType paramType) { if (IsRetype()) { return SetOutputType(gate, GateType::NumberType()); @@ -663,10 +763,19 @@ GateRef NumberSpeculativeRetype::VisitNumberRelated(GateRef gate) if (IsConvert()) { Environment env(gate, circuit_, &builder_); size_t valueNum = acc_.GetNumValueIn(gate); + GateType inputType = GateType::AnyType(); + if (paramType.IsIntType() || paramType.IsIntOverflowType()) { + inputType = GateType::IntType(); + } else if (paramType.IsDoubleType()) { + inputType = GateType::DoubleType(); + } else if (paramType.IsNumberType()) { + inputType = GateType::NumberType(); + } else if (paramType.IsBooleanType()) { + inputType = GateType::BooleanType(); + } for (size_t i = 0; i < valueNum; ++i) { GateRef input = acc_.GetValueIn(gate, i); - GateType inputType = acc_.GetGateType(input); - if (inputType.IsNumberType() || inputType.IsBooleanType()) { + if (paramType.HasNumberType() || paramType.IsBooleanType()) { acc_.ReplaceValueIn(gate, CheckAndConvertToTagged(input, inputType, ConvertToNumber::BOOL_ONLY), i); } } @@ -676,32 +785,6 @@ GateRef NumberSpeculativeRetype::VisitNumberRelated(GateRef gate) return Circuit::NullGate(); } -GateRef NumberSpeculativeRetype::VisitCallBuiltins(GateRef gate) -{ - auto valuesIn = acc_.GetNumValueIn(gate); - auto idGate = acc_.GetValueIn(gate, valuesIn - 1); - auto id = static_cast(acc_.GetConstantValue(idGate)); - if (id != BUILTINS_STUB_ID(SQRT)) { - return VisitOthers(gate); - } - - if (IsRetype()) { - // Sqrt output is double - return SetOutputType(gate, GateType::DoubleType()); - } - if (IsConvert()) { - Environment env(gate, circuit_, &builder_); - acc_.ReplaceValueIn(gate, ConvertToTagged(idGate), valuesIn - 1); - for (size_t i = 0; i < valuesIn - 1; ++i) { - GateRef input = acc_.GetValueIn(gate, i); - acc_.ReplaceValueIn(gate, CheckAndConvertToFloat64(input, GateType::NumberType()), i); - } - acc_.ReplaceStateIn(gate, builder_.GetState()); - acc_.ReplaceDependIn(gate, builder_.GetDepend()); - } - return Circuit::NullGate(); -} - GateRef NumberSpeculativeRetype::VisitFrameState(GateRef gate) { if (IsRetype()) { @@ -775,59 +858,44 @@ GateRef NumberSpeculativeRetype::CheckAndConvertToBool(GateRef gate, GateType ga } } -void NumberSpeculativeRetype::ConvertForBinaryOp(GateRef gate) +void NumberSpeculativeRetype::ConvertForNumberBinaryOp(GateRef gate) { - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - GateType leftType = GateType::IntType(); - GateType rightType = GateType::IntType(); - ConvertForIntOperator(gate, leftType, rightType); - } else { - GateType leftType = GateType::NumberType(); - GateType rightType = GateType::NumberType(); - if (sampleType->IsIntOverFlow()) { - leftType = GateType::IntType(); - rightType = GateType::IntType(); - } else if (sampleType->IsDouble()) { - leftType = GateType::DoubleType(); - rightType = GateType::DoubleType(); - } - ConvertForDoubleOperator(gate, leftType, rightType); - } + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); + if (paramType.IsIntType()) { + ConvertForIntOperator(gate, GateType::IntType(), GateType::IntType()); + } else if (paramType.IsIntOverflowType()) { + ConvertForDoubleOperator(gate, GateType::IntType(), GateType::IntType()); + } else if (paramType.IsDoubleType()) { + ConvertForDoubleOperator(gate, GateType::DoubleType(), GateType::DoubleType()); + } else if (paramType.IsNumberType()) { + ConvertForDoubleOperator(gate, GateType::NumberType(), GateType::NumberType()); + } +} + +void NumberSpeculativeRetype::ConvertForNumberCompareOp(GateRef gate) +{ + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); + ASSERT(!paramType.IsIntOverflowType()); + if (paramType.IsIntType()) { + ConvertForIntOperator(gate, GateType::IntType(), GateType::IntType()); } else { - GateType gateType = acc_.GetGateType(gate); - GateType leftType = acc_.GetLeftType(gate); - GateType rightType = acc_.GetRightType(gate); - if (gateType.IsIntType()) { - ConvertForIntOperator(gate, leftType, rightType); - } else { - ConvertForDoubleOperator(gate, leftType, rightType); - } + ConvertForDoubleOperator(gate, GateType::NumberType(), GateType::NumberType()); } } -void NumberSpeculativeRetype::ConvertForCompareOp(GateRef gate) +void NumberSpeculativeRetype::ConvertForNumberShiftAndLogicalOperator(GateRef gate) { - const PGOSampleType *sampleType = acc_.GetTypedBinaryType(gate).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - GateType leftType = GateType::IntType(); - GateType rightType = GateType::IntType(); - ConvertForIntOperator(gate, leftType, rightType); - } else { - GateType leftType = GateType::NumberType(); - GateType rightType = GateType::NumberType(); - ConvertForDoubleOperator(gate, leftType, rightType); - } + TypedBinaryAccessor accessor(acc_.TryGetValue(gate)); + const ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.HasNumberType()); + if (paramType.IsIntType()) { + ConvertForShiftAndLogicalOperator(gate, GateType::IntType(), GateType::IntType()); } else { - GateType leftType = acc_.GetLeftType(gate); - GateType rightType = acc_.GetRightType(gate); - if (leftType.IsIntType() && rightType.IsIntType()) { - ConvertForIntOperator(gate, leftType, rightType); - } else { - ConvertForDoubleOperator(gate, leftType, rightType); - } + ConvertForShiftAndLogicalOperator(gate, GateType::NumberType(), GateType::NumberType()); } } @@ -901,6 +969,38 @@ GateRef NumberSpeculativeRetype::TryConvertConstant(GateRef gate, bool needInt32 return Circuit::NullGate(); } +GateRef NumberSpeculativeRetype::TryConvertConstantToInt32(GateRef gate) +{ + if (acc_.GetOpCode(gate) != OpCode::CONSTANT) { + return Circuit::NullGate(); + } + + if (acc_.GetGateType(gate).IsNJSValueType()) { + MachineType mType = acc_.GetMachineType(gate); + if (mType == MachineType::I32) { + int32_t rawValue = acc_.GetInt32FromConstant(gate); + return builder_.Int32(rawValue); + } else if (mType == MachineType::F64) { + double rawValue = acc_.GetFloat64FromConstant(gate); + int32_t int32Value = base::NumberHelper::DoubleInRangeInt32(rawValue); + return builder_.Int32(int32Value); + } else { + return Circuit::NullGate(); + } + } + + JSTaggedValue value(acc_.GetConstantValue(gate)); + if (value.IsInt()) { + int32_t rawValue = value.GetInt(); + return builder_.Int32(rawValue); + } else if (value.IsDouble()) { + double rawValue = value.GetDouble(); + int32_t int32Value = base::NumberHelper::DoubleInRangeInt32(rawValue); + return builder_.Int32(int32Value); + } + return Circuit::NullGate(); +} + GateRef NumberSpeculativeRetype::CheckAndConvertToInt32(GateRef gate, GateType gateType, ConvertSupport support, OpType type) { @@ -967,6 +1067,70 @@ GateRef NumberSpeculativeRetype::CheckAndConvertToInt32(GateRef gate, GateType g return result; } +GateRef NumberSpeculativeRetype::CheckBoundAndConvertToInt32(GateRef gate, ConvertSupport support, OpType type) +{ + auto result = TryConvertConstantToInt32(gate); + GateType gateType = acc_.GetGateType(gate); + if (result != Circuit::NullGate()) { + acc_.DeleteGateIfNoUse(gate); + ResizeAndSetTypeInfo(result, TypeInfo::INT32); + return result; + } + TypeInfo output = GetOutputTypeInfo(gate); + switch (output) { + case TypeInfo::INT1: + result = builder_.ConvertBoolToInt32(gate, support); + break; + case TypeInfo::CHAR: + case TypeInfo::INT32: + return gate; + case TypeInfo::UINT32: { + result = builder_.CheckUInt32AndConvertToInt32(gate); + break; + } + case TypeInfo::FLOAT64: { + result = builder_.DoubleCheckINFInRangeInt32(gate); + break; + } + case TypeInfo::HOLE_INT: + result = builder_.CheckHoleIntAndConvertToInt32(gate); + break; + case TypeInfo::HOLE_DOUBLE: + result = builder_.CheckHoleDoubleAndConvertToInt32(gate); + break; + case TypeInfo::NONE: + case TypeInfo::TAGGED: { + if (gateType.IsIntType()) { + result = builder_.CheckTaggedIntAndConvertToInt32(gate); + } else if (gateType.IsDoubleType()) { + GateRef doubleValue = builder_.CheckTaggedDoubleAndConvertToFloat64(gate); + result = builder_.DoubleInRangeInt32(doubleValue); + } else if (gateType.IsNullType()) { + result = builder_.CheckNullAndConvertToInt32(gate); + } else if (gateType.IsBooleanType()) { + result = builder_.CheckTaggedBooleanAndConvertToInt32(gate); + } else if (gateType.IsUndefinedType()) { + if (type == OpType::SHIFT_AND_LOGICAL) { + result = builder_.CheckUndefinedAndConvertToInt32(gate); + } else { + LOG_ECMA(FATAL) << "undefined cannot convert to int type"; + } + } else { + GateRef doubleValue = builder_.CheckTaggedNumberAndConvertToFloat64(gate); + result = builder_.DoubleInRangeInt32(doubleValue); + } + break; + } + default: { + LOG_ECMA(FATAL) << "this branch is unreachable"; + UNREACHABLE(); + return Circuit::NullGate(); + } + } + ResizeAndSetTypeInfo(result, TypeInfo::INT32); + return result; +} + GateRef NumberSpeculativeRetype::CheckAndConvertToFloat64(GateRef gate, GateType gateType, ConvertToNumber convert) { @@ -1008,7 +1172,6 @@ GateRef NumberSpeculativeRetype::CheckAndConvertToFloat64(GateRef gate, GateType } else if (gateType.IsUndefinedType()) { result = builder_.CheckUndefinedAndConvertToFloat64(gate); } else { - ASSERT(gateType.IsNumberType()); if (convert == ConvertToNumber::ALL) { GateRef glue = acc_.GetGlueFromArgList(); GateRef number = builder_.ToNumber(glue, gate, glue); @@ -1034,8 +1197,12 @@ GateRef NumberSpeculativeRetype::CheckAndConvertToTagged(GateRef gate, GateType { TypeInfo output = GetOutputTypeInfo(gate); switch (output) { - case TypeInfo::INT1: + case TypeInfo::INT1: { + if (gateType.IsNumberType() && convert != ConvertToNumber::DISABLE) { + return builder_.ConvertInt32ToTaggedInt(builder_.BooleanToInt32(gate)); + } return builder_.ConvertBoolToTaggedBoolean(gate); + } case TypeInfo::INT32: return builder_.ConvertInt32ToTaggedInt(gate); case TypeInfo::UINT32: @@ -1131,6 +1298,9 @@ GateRef NumberSpeculativeRetype::VisitIndexCheck(GateRef gate) GateRef index = acc_.GetValueIn(gate, 1); GateType receiverType = acc_.GetGateType(receiver); GateType indexType = acc_.GetGateType(index); + if (indexType.IsAnyType()) { + indexType = GateType::IntType(); + } acc_.ReplaceValueIn(gate, CheckAndConvertToInt32(receiver, receiverType), 0); acc_.ReplaceValueIn(gate, CheckAndConvertToInt32(index, indexType), 1); @@ -1290,15 +1460,15 @@ GateRef NumberSpeculativeRetype::VisitTypeConvert(GateRef gate) { GateRef input = acc_.GetValueIn(gate, 0); TypeInfo inputInfo = GetOutputTypeInfo(input); + TypeConvertAccessor accessor(acc_.TryGetValue(gate)); + ParamType paramType = accessor.GetLeftType(); if (IsRetype()) { if (inputInfo == TypeInfo::TAGGED) { if (acc_.IsConstantNumber(input)) { return Circuit::NullGate(); } - GateType gateType = acc_.GetGateType(gate); - ASSERT(gateType.IsNumberType()); - GateType resType = gateType.IsIntType() ? GateType::IntType() : GateType::DoubleType(); - return SetOutputType(gate, resType); + ASSERT(paramType.HasNumberType()); + return SetOutputType(gate, paramType); } TypeInfo oldType = GetOutputTypeInfo(gate); SetOutputTypeInfo(gate, inputInfo); @@ -1308,9 +1478,8 @@ GateRef NumberSpeculativeRetype::VisitTypeConvert(GateRef gate) ASSERT(inputInfo != TypeInfo::INT1 && inputInfo != TypeInfo::NONE); Environment env(gate, circuit_, &builder_); if (inputInfo == TypeInfo::TAGGED && !acc_.IsConstantNumber(input)) { - GateType gateType = acc_.GetGateType(gate); - ASSERT(gateType.IsNumberType()); - if (gateType.IsIntType()) { + ASSERT(paramType.HasNumberType()); + if (paramType.IsIntType()) { input = CheckAndConvertToInt32(input, GateType::IntType()); ResizeAndSetTypeInfo(input, TypeInfo::INT32); } else { @@ -1322,7 +1491,7 @@ GateRef NumberSpeculativeRetype::VisitTypeConvert(GateRef gate) return Circuit::NullGate(); } -GateRef NumberSpeculativeRetype::VisitMathBuiltin(GateRef gate) +GateRef NumberSpeculativeRetype::VisitMathDoubleParamsBuiltin(GateRef gate) { if (IsRetype()) { return SetOutputType(gate, GateType::DoubleType()); @@ -1332,17 +1501,208 @@ GateRef NumberSpeculativeRetype::VisitMathBuiltin(GateRef gate) size_t valueNum = acc_.GetNumValueIn(gate); for (size_t i = 0; i < valueNum; ++i) { GateRef input = acc_.GetValueIn(gate, i); - acc_.ReplaceValueIn(gate, CheckAndConvertToFloat64(input, GateType::NumberType(), ConvertToNumber::BOOL_ONLY), i); + GateRef convertedInput = CheckAndConvertToFloat64(input, GateType::NumberType(), ConvertToNumber::BOOL_ONLY); + acc_.ReplaceValueIn(gate, convertedInput, i); } acc_.ReplaceStateIn(gate, builder_.GetState()); acc_.ReplaceDependIn(gate, builder_.GetDepend()); return Circuit::NullGate(); } -GateRef NumberSpeculativeRetype::VisitMathAbs(GateRef gate) +double NumberSpeculativeRetype::GetDoubleValueFromConst(GateRef gate) +{ + ASSERT(acc_.GetOpCode(gate) == OpCode::CONSTANT); + double rawValue; + if (acc_.GetGateType(gate).IsNJSValueType()) { + ASSERT(GetNumberInputTypeInfo(gate) == TypeInfo::FLOAT64); + rawValue = acc_.GetFloat64FromConstant(gate); + } else { + JSTaggedValue value(acc_.GetConstantValue(gate)); + ASSERT(value.IsDouble()); + rawValue = value.GetDouble(); + } + return rawValue; +} + +template +GateRef NumberSpeculativeRetype::VisitNumberOrGlobalBuiltin(GateRef gate) { if (IsRetype()) { - return SetOutputType(gate, GateType::NumberType()); + ASSERT(acc_.GetOpCode(gate) == OpCode::GLOBAL_IS_FINITE || + acc_.GetOpCode(gate) == OpCode::NUMBER_IS_FINITE || + acc_.GetOpCode(gate) == OpCode::GLOBAL_IS_NAN || + acc_.GetOpCode(gate) == OpCode::NUMBER_IS_NAN); + return SetOutputType(gate, GateType::BooleanType()); + } + ASSERT(IsConvert()); + Environment env(gate, circuit_, &builder_); + ASSERT(acc_.GetNumValueIn(gate) == 1); + GateRef input = acc_.GetValueIn(gate, 0); + // We change IsNan/IsFinite to constant if input is INT32 without check + // So we skip tagged input with int profiled type + auto type = GetNumberInputTypeInfo(input, true); + if (type == TypeInfo::INT32) { + GateRef result; + if constexpr (IS_NAN) { + result = builder_.TaggedFalse(); + } else { + result = builder_.TaggedTrue(); + } + ResizeAndSetTypeInfo(result, TypeInfo::TAGGED); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); + return Circuit::NullGate(); + } else { + ASSERT(type == TypeInfo::FLOAT64); + input = CheckAndConvertToFloat64(input, GateType::NumberType()); + } + + acc_.ReplaceValueIn(gate, input, 0); + ResizeAndSetTypeInfo(input, TypeInfo::FLOAT64); + acc_.ReplaceStateIn(gate, builder_.GetState()); + acc_.ReplaceDependIn(gate, builder_.GetDepend()); + return Circuit::NullGate(); +} + +GateRef NumberSpeculativeRetype::VisitNumberIsInteger(GateRef gate) +{ + if (IsRetype()) { + ASSERT(acc_.GetOpCode(gate) == OpCode::NUMBER_IS_INTEGER || + acc_.GetOpCode(gate) == OpCode::NUMBER_IS_SAFEINTEGER); + return SetOutputType(gate, GateType::BooleanType()); + } + ASSERT(IsConvert()); + Environment env(gate, circuit_, &builder_); + ASSERT(acc_.GetNumValueIn(gate) == 1); + GateRef input = acc_.GetValueIn(gate, 0); + auto type = GetNumberInputTypeInfo(input); + if (type == TypeInfo::FLOAT64) { + GateRef result = builder_.TaggedFalse(); + ResizeAndSetTypeInfo(result, TypeInfo::TAGGED); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); + return Circuit::NullGate(); + } + input = CheckAndConvertToInt32(input, GateType::NumberType()); + acc_.ReplaceValueIn(gate, input, 0); + ResizeAndSetTypeInfo(input, TypeInfo::FLOAT64); + acc_.ReplaceStateIn(gate, builder_.GetState()); + acc_.ReplaceDependIn(gate, builder_.GetDepend()); + return Circuit::NullGate(); +} + +GateRef NumberSpeculativeRetype::VisitClz32Builtin(GateRef gate) +{ + if (IsRetype()) { + return SetOutputType(gate, GateType::IntType()); + } + ASSERT(IsConvert()); + Environment env(gate, circuit_, &builder_); + GateRef input = acc_.GetValueIn(gate, 0); + + TypeInfo type = GetNumberTypeInfo(input); + if (type == TypeInfo::INT32) { + input = CheckAndConvertToInt32(input, GateType::IntType()); + acc_.SetMetaData(gate, circuit_->MathClz32Int32()); + } else { // All other types describe in ConvertToFloat64 + input = CheckAndConvertToFloat64(input, GateType::NumberType(), ConvertToNumber::BOOL_ONLY); + acc_.SetMetaData(gate, circuit_->MathClz32Double()); + } + acc_.ReplaceValueIn(gate, input, 0); + acc_.ReplaceStateIn(gate, builder_.GetState()); + acc_.ReplaceDependIn(gate, builder_.GetDepend()); + return Circuit::NullGate(); +} + +const GateMetaData *NumberSpeculativeRetype::GetNewMeta(OpCode op, TypeInfo type) +{ + if (type == TypeInfo::INT32) { + switch (op) { + case OpCode::MATH_ABS: + return circuit_->MathAbsInt32(); + case OpCode::MATH_MIN: + return circuit_->MathMinInt32(); + case OpCode::MATH_MAX: + return circuit_->MathMaxInt32(); + default: + return nullptr; + } + } else if (type == TypeInfo::FLOAT64) { + switch (op) { + case OpCode::MATH_ABS: + return circuit_->MathAbsDouble(); + case OpCode::MATH_MIN: + return circuit_->MathMinDouble(); + case OpCode::MATH_MAX: + return circuit_->MathMaxDouble(); + case OpCode::MATH_ROUND: + return circuit_->MathRoundDouble(); + default: + return nullptr; + } + } else if (type == TypeInfo::TAGGED) { + if (op == OpCode::MATH_SIGN) { + return circuit_->MathSignTagged(); + } + return nullptr; + } else { + return nullptr; + } +} + +GateRef NumberSpeculativeRetype::VisitMathTaggedNumberParamsBuiltin(GateRef gate) +{ + size_t valueNum = acc_.GetNumValueIn(gate); + ASSERT(valueNum <= 2U); + OpCode op = acc_.GetOpCode(gate); + if (IsRetype()) { + TypeInfo type = GetNumberTypeInfo(acc_.GetValueIn(gate, 0)); + if (valueNum > 1U) { + TypeInfo secondInputType = GetNumberTypeInfo(acc_.GetValueIn(gate, 1U)); + type = GetCommonTypeInfo(type, secondInputType); + } + if (type == TypeInfo::TAGGED && op == OpCode::MATH_ROUND) { + type = TypeInfo::FLOAT64; + } + if (op == OpCode::MATH_SIGN) { + if (type == TypeInfo::INT32) { + return SetOutputType(gate, TypeInfo::INT32); + } + return SetOutputType(gate, TypeInfo::TAGGED); + } + return SetOutputType(gate, type); + } + ASSERT(IsConvert()); + TypeInfo type = GetOutputTypeInfo(gate); // load type computed in retype phase + if (op == OpCode::MATH_ROUND) { + type = GetNumberTypeInfo(acc_.GetValueIn(gate, 0)); + } + const GateMetaData* meta = GetNewMeta(op, type); + if (meta != nullptr) { + acc_.SetMetaData(gate, meta); + acc_.SetGateType(gate, GateType::NJSValue()); + acc_.SetMachineType(gate, type == TypeInfo::INT32 ? MachineType::I32 : MachineType::F64); + } + Environment env(gate, circuit_, &builder_); + for (size_t i = 0; i < valueNum; ++i) { + GateRef input = acc_.GetValueIn(gate, i); + if (type == TypeInfo::INT32) { + input = CheckAndConvertToInt32(input, GateType::IntType()); + } else if (type == TypeInfo::FLOAT64) { + input = CheckAndConvertToFloat64(input, acc_.GetGateType(input), ConvertToNumber::BOOL_ONLY); + } else { + ASSERT(type == TypeInfo::TAGGED); + input = CheckAndConvertToTagged(input, GateType::NumberType(), ConvertToNumber::BOOL_ONLY); + } + acc_.ReplaceValueIn(gate, input, i); + } + acc_.ReplaceStateIn(gate, builder_.GetState()); + acc_.ReplaceDependIn(gate, builder_.GetDepend()); + return Circuit::NullGate(); +} + +GateRef NumberSpeculativeRetype::VisitMathTrunc(GateRef gate) +{ + if (IsRetype()) { + return SetOutputType(gate, GateType::DoubleType()); } ASSERT(IsConvert()); Environment env(gate, circuit_, &builder_); @@ -1354,6 +1714,121 @@ GateRef NumberSpeculativeRetype::VisitMathAbs(GateRef gate) return Circuit::NullGate(); } +TypeInfo NumberSpeculativeRetype::GetNumberInputTypeInfo(GateRef gate, bool skipTagged) +{ + TypeInfo typeInfo = GetOutputTypeInfo(gate); + switch (typeInfo) { + case TypeInfo::INT1: + case TypeInfo::INT32: + case TypeInfo::HOLE_INT: + return TypeInfo::INT32; + case TypeInfo::NONE: + case TypeInfo::TAGGED: { + if (skipTagged) { + return TypeInfo::FLOAT64; + } + GateType gateType = acc_.GetGateType(gate); + if (gateType.IsIntType() || gateType.IsBooleanType()) { + return TypeInfo::INT32; + } + return TypeInfo::FLOAT64; + } + default: + return TypeInfo::FLOAT64; + } +} + +void NumberSpeculativeRetype::SetNewInputForMathImul(GateRef gate, int idx, Label *exit) +{ + GateRef input = acc_.GetValueIn(gate, idx); + auto type = GetNumberInputTypeInfo(input); + if (type == TypeInfo::INT32) { + input = CheckAndConvertToInt32(input, GateType::IntType()); + } else { + ASSERT(type == TypeInfo::FLOAT64); + input = CheckAndConvertToFloat64(input, GateType::NumberType(), ConvertToNumber::BOOL_ONLY); + input = builder_.DoubleToInt(input, exit); + } + ResizeAndSetTypeInfo(input, TypeInfo::INT32); + acc_.ReplaceValueIn(gate, input, idx); +} + +GateRef NumberSpeculativeRetype::VisitMathImul(GateRef gate) +{ + if (IsRetype()) { + return SetOutputType(gate, GateType::IntType()); + } + ASSERT(IsConvert()); + Environment env(gate, circuit_, &builder_); + ASSERT(acc_.GetNumValueIn(gate) == 2U); + + Label exit1(&builder_); + Label exit2(&builder_); + + SetNewInputForMathImul(gate, 0, &exit1); + SetNewInputForMathImul(gate, 1, &exit2); + + acc_.SetGateType(gate, GateType::NJSValue()); + acc_.SetMachineType(gate, MachineType::I32); + acc_.ReplaceStateIn(gate, builder_.GetState()); + acc_.ReplaceDependIn(gate, builder_.GetDepend()); + return Circuit::NullGate(); +} + +GateRef NumberSpeculativeRetype::VisitDataViewGet(GateRef gate) +{ + GateRef builtinsID = acc_.GetValueIn(gate, 2); + auto ID = static_cast(acc_.GetConstantValue(builtinsID)); + if (IsRetype()) { + switch (ID) { + case BuiltinsStubCSigns::ID::DataViewGetInt8: + return SetOutputType(gate, GateType::IntType()); + case BuiltinsStubCSigns::ID::DataViewGetUint8: + return SetOutputType(gate, GateType::IntType()); + case BuiltinsStubCSigns::ID::DataViewGetInt16: + return SetOutputType(gate, GateType::IntType()); + case BuiltinsStubCSigns::ID::DataViewGetUint16: + return SetOutputType(gate, GateType::IntType()); + case BuiltinsStubCSigns::ID::DataViewGetInt32: + return SetOutputType(gate, GateType::IntType()); + case BuiltinsStubCSigns::ID::DataViewGetUint32: + return SetOutputType(gate, TypeInfo::UINT32); + case BuiltinsStubCSigns::ID::DataViewGetFloat32: + return SetOutputType(gate, GateType::DoubleType()); + case BuiltinsStubCSigns::ID::DataViewGetFloat64: + return SetOutputType(gate, GateType::DoubleType()); + default: + UNREACHABLE(); + } + } + ASSERT(IsConvert()); + Environment env(gate, circuit_, &builder_); + GateRef index = acc_.GetValueIn(gate, 1); + GateRef input = CheckBoundAndConvertToInt32(index, ConvertSupport::ENABLE, OpType::SHIFT_AND_LOGICAL); + acc_.ReplaceValueIn(gate, input, 1); + acc_.ReplaceStateIn(gate, builder_.GetState()); + acc_.ReplaceDependIn(gate, builder_.GetDepend()); + return Circuit::NullGate(); +} + +GateRef NumberSpeculativeRetype::VisitDataViewSet(GateRef gate) +{ + if (IsRetype()) { + return SetOutputType(gate, GateType::UndefinedType()); + } + ASSERT(IsConvert()); + Environment env(gate, circuit_, &builder_); + GateRef index = acc_.GetValueIn(gate, 1); + GateRef inputIndex = CheckBoundAndConvertToInt32(index, ConvertSupport::ENABLE, OpType::SHIFT_AND_LOGICAL); + GateRef value = acc_.GetValueIn(gate, 2); + GateRef inputValue = CheckAndConvertToFloat64(value, acc_.GetGateType(value), ConvertToNumber::BOOL_ONLY); + acc_.ReplaceValueIn(gate, inputIndex, 1); // replace index of dataview to Int32 + acc_.ReplaceValueIn(gate, inputValue, 2); // replace input value to Double64 + acc_.ReplaceStateIn(gate, builder_.GetState()); + acc_.ReplaceDependIn(gate, builder_.GetDepend()); + return Circuit::NullGate(); +} + GateRef NumberSpeculativeRetype::VisitMonoLoadPropertyOnProto(GateRef gate) { if (IsRetype()) { diff --git a/ecmascript/compiler/number_speculative_retype.h b/ecmascript/compiler/number_speculative_retype.h index bb72586759e3d143bab72dddd0b5c95eb5dc26cb..a0d62b7860c76df891489b535c824936d54085ba 100644 --- a/ecmascript/compiler/number_speculative_retype.h +++ b/ecmascript/compiler/number_speculative_retype.h @@ -66,10 +66,11 @@ private: return state_ == State::Convert; } - GateRef SetOutputType(GateRef gate, PGOSampleType type); GateRef SetOutputType(GateRef gate, GateType type); + GateRef SetOutputType(GateRef gate, ParamType type); GateRef SetOutputType(GateRef gate, Representation rep); GateRef SetOutputType(GateRef gate, TypeInfo type); + TypeInfo GetNumberTypeInfo(GateRef gate); GateRef VisitPhi(GateRef gate); GateRef VisitConstant(GateRef gate); GateRef VisitTypedBinaryOp(GateRef gate); @@ -89,8 +90,15 @@ private: GateRef VisitNumberCompare(GateRef gate); GateRef VisitNumberShiftAndLogical(GateRef gate); GateRef VisitNumberToString(GateRef gate); - GateRef VisitMathBuiltin(GateRef gate); - GateRef VisitMathAbs(GateRef gate); + GateRef VisitMathDoubleParamsBuiltin(GateRef gate); + const GateMetaData *GetNewMeta(OpCode op, TypeInfo type); + GateRef VisitMathTaggedNumberParamsBuiltin(GateRef gate); + GateRef VisitClz32Builtin(GateRef gate); + GateRef VisitMathTrunc(GateRef gate); + GateRef VisitMathImul(GateRef gate); + template + GateRef VisitNumberOrGlobalBuiltin(GateRef gate); + GateRef VisitNumberIsInteger(GateRef gate); GateRef VisitBooleanJump(GateRef gate); GateRef VisitRangeCheckPredicate(GateRef gate); GateRef VisitIndexCheck(GateRef gate); @@ -100,8 +108,10 @@ private: GateRef VisitStoreElement(GateRef gate); GateRef VisitStoreProperty(GateRef gate); GateRef VisitLoadProperty(GateRef gate); - GateRef VisitNumberRelated(GateRef gate); + GateRef VisitNumberRelated(GateRef gate, ParamType paramType); GateRef VisitCallBuiltins(GateRef gate); + GateRef VisitDataViewGet(GateRef gate); + GateRef VisitDataViewSet(GateRef gate); GateRef VisitOthers(GateRef gate); GateRef VisitTypeConvert(GateRef gate); GateRef VisitFrameState(GateRef gate); @@ -116,20 +126,30 @@ private: GateRef VisitMonoCallGetterOnProto(GateRef gate); GateRef VisitMonoStoreProperty(GateRef gate); - void ConvertForBinaryOp(GateRef gate); - void ConvertForCompareOp(GateRef gate); + void ConvertForNumberBinaryOp(GateRef gate); + void ConvertForNumberCompareOp(GateRef gate); + void ConvertForNumberShiftAndLogicalOperator(GateRef gate); + void ConvertForIntOperator(GateRef gate, GateType leftType, GateType rightType); void ConvertForShiftAndLogicalOperator(GateRef gate, GateType leftType, GateType rightType); void ConvertForDoubleOperator(GateRef gate, GateType leftType, GateType rightType); + TypeInfo GetNumberInputTypeInfo(GateRef gate, bool skipTagged = false); + void SetNewInputForMathImul(GateRef gate, int idx, Label *exit); + double GetDoubleValueFromConst(GateRef gate); + GateRef CheckAndConvertToInt32(GateRef gate, GateType gateType, ConvertSupport support = ConvertSupport::ENABLE, OpType type = OpType::NORMAL); + GateRef CheckBoundAndConvertToInt32(GateRef gate, + ConvertSupport support = ConvertSupport::ENABLE, + OpType type = OpType::NORMAL); GateRef CheckAndConvertToFloat64(GateRef gate, GateType gateType, ConvertToNumber convert = ConvertToNumber::BOOL_ONLY); GateRef CheckAndConvertToTagged(GateRef gate, GateType gateType, ConvertToNumber convert); GateRef CheckAndConvertToBool(GateRef gate, GateType gateType); GateRef ConvertToTagged(GateRef gate); GateRef TryConvertConstant(GateRef gate, bool needInt32); + GateRef TryConvertConstantToInt32(GateRef gate); GateRef ConvertTaggedToNJSValue(GateRef gate, TypeInfo output); TypeInfo GetOuputForPhi(GateRef gate, bool ignoreConstant); diff --git a/ecmascript/compiler/pass.h b/ecmascript/compiler/pass.h index 3786d82671ca026b2875e7b7624bf6129584d59b..36984b0557935eec69fc891e2cac5c83a091665e 100644 --- a/ecmascript/compiler/pass.h +++ b/ecmascript/compiler/pass.h @@ -16,12 +16,10 @@ #ifndef ECMASCRIPT_COMPILER_PASS_H #define ECMASCRIPT_COMPILER_PASS_H -#include "ecmascript/compiler/array_bounds_check_elimination.h" #include "ecmascript/compiler/async_function_lowering.h" #include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/codegen/llvm/llvm_codegen.h" #include "ecmascript/compiler/combined_pass_visitor.h" -#include "ecmascript/compiler/common_stubs.h" #include "ecmascript/compiler/compiler_log.h" #include "ecmascript/compiler/constant_folding.h" #include "ecmascript/compiler/dead_code_elimination.h" @@ -30,6 +28,7 @@ #include "ecmascript/compiler/escape_analysis_editor.h" #include "ecmascript/compiler/graph_editor.h" #include "ecmascript/compiler/graph_linearizer.h" +#include "ecmascript/compiler/induction_variable_analysis.h" #include "ecmascript/compiler/later_elimination.h" #include "ecmascript/compiler/mcr_lowering.h" #include "ecmascript/compiler/lexical_env_specialization_pass.h" @@ -48,8 +47,6 @@ #include "ecmascript/compiler/ts_inline_lowering.h" #include "ecmascript/compiler/typed_bytecode_lowering.h" #include "ecmascript/compiler/ts_hcr_opt_pass.h" -#include "ecmascript/compiler/type_inference/global_type_infer.h" -#include "ecmascript/compiler/type_inference/initialization_analysis.h" #include "ecmascript/compiler/type_inference/pgo_type_infer.h" #include "ecmascript/compiler/typed_hcr_lowering.h" #include "ecmascript/compiler/typed_native_inline_lowering.h" @@ -72,12 +69,14 @@ public: PassData(BytecodeCircuitBuilder *builder, Circuit *circuit, PassContext *ctx, CompilerLog *log, std::string methodName, MethodInfo *methodInfo = nullptr, bool hasTypes = false, const CString &recordName = "", MethodLiteral *methodLiteral = nullptr, - uint32_t methodOffset = 0, NativeAreaAllocator *allocator = nullptr, + uint32_t methodOffset = 0, const CallMethodFlagMap *callMethodFlagMap = nullptr, + const CVector &fileInfos = CVector{}, NativeAreaAllocator *allocator = nullptr, PGOProfilerDecoder *decoder = nullptr, PassOptions *passOptions = nullptr, std::string optBCRange = "") : builder_(builder), circuit_(circuit), ctx_(ctx), log_(log), methodName_(methodName), methodInfo_(methodInfo), hasTypes_(hasTypes), recordName_(recordName), methodLiteral_(methodLiteral), - methodOffset_(methodOffset), allocator_(allocator), decoder_(decoder), passOptions_(passOptions), + methodOffset_(methodOffset), callMethodFlagMap_(callMethodFlagMap), fileInfos_(fileInfos), + allocator_(allocator), decoder_(decoder), passOptions_(passOptions), optBCRange_(optBCRange) { } @@ -193,6 +192,16 @@ public: { return optBCRange_; } + + const CallMethodFlagMap *GetCallMethodFlagMap() const + { + return callMethodFlagMap_; + } + + const CVector &GetFileInfos() const + { + return fileInfos_; + } bool IsTypeAbort() const { @@ -241,6 +250,8 @@ private: const CString &recordName_; MethodLiteral *methodLiteral_ {nullptr}; uint32_t methodOffset_; + const CallMethodFlagMap *callMethodFlagMap_ {nullptr}; + const CVector &fileInfos_; NativeAreaAllocator *allocator_ {nullptr}; PGOProfilerDecoder *decoder_ {nullptr}; PassOptions *passOptions_ {nullptr}; @@ -263,24 +274,6 @@ private: T1* data_; }; -class TypeInferPass { -public: - bool Run(PassData* data) - { - PassOptions *passOptions = data->GetPassOptions(); - if (passOptions != nullptr && !passOptions->EnableTypeInfer()) { - return false; - } - TimeScope timescope("TypeInferPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog()); - bool enableLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputType(); - GlobalTypeInfer globalTypeInfer(data->GetPassContext(), data->GetMethodOffset(), data->GetRecordName(), - data->GetPGOProfilerDecoder(), passOptions->EnableOptTrackField(), - enableLog, data->HasTypes()); - globalTypeInfer.ProcessTypeInference(data->GetBuilder(), data->GetCircuit()); - return true; - } -}; - class PGOTypeInferPass { public: bool Run(PassData* data) @@ -288,7 +281,7 @@ public: TimeScope timescope("PGOTypeInferPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog()); bool enableLog = data->GetLog()->GetEnableMethodLog() && data->GetLog()->OutputType(); Chunk chunk(data->GetNativeAreaAllocator()); - PGOTypeInfer pgoTypeInfer(data->GetCircuit(), data->GetTSManager(), data->GetBuilder(), + PGOTypeInfer pgoTypeInfer(data->GetCircuit(), data->GetTSManager(), data->GetPTManager(), data->GetBuilder(), data->GetMethodName(), &chunk, enableLog); pgoTypeInfer.Run(); return true; @@ -332,6 +325,27 @@ public: } }; +class InductionVariableAnalysisPass { +public: + bool Run(PassData *data) + { + PassOptions *passOptions = data->GetPassOptions(); + if (!passOptions->EnableInductionVariableAnalysis()) { + return false; + } + TimeScope timescope("InductionVariableAnalysisPass", data->GetMethodName(), + data->GetMethodOffset(), data->GetLog()); + bool enableLog = data->GetLog()->EnableMethodCIRLog(); + JSRuntimeOptions runtimeOption = data->GetPassContext()->GetEcmaVM()->GetJSOptions(); + Chunk chunk(data->GetNativeAreaAllocator()); + InductionVariableAnalysis inductionVariableAnalysis(data->GetCircuit(), data->GetPassContext(), enableLog, + data->GetMethodName(), &chunk, + runtimeOption.GetTraceInductionVariableAnalysis()); + inductionVariableAnalysis.Run(); + return true; + } +}; + class TypeBytecodeLoweringPass { public: bool Run(PassData* data) @@ -351,6 +365,8 @@ public: data->GetMethodName(), passOptions->EnableLoweringBuiltin(), data->GetRecordName(), + data->GetCallMethodFlagMap(), + data->GetPGOProfilerDecoder(), data->GetOptBCRange()); bool success = lowering.RunTypedBytecodeLowering(); if (!success) { @@ -380,8 +396,7 @@ public: TimeScope timescope("NTypeBytecodeLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog()); bool enableLog = data->GetLog()->EnableMethodCIRLog(); - NTypeBytecodeLowering lowering(data->GetCircuit(), data->GetPassContext(), data->GetTSManager(), - enableLog, data->GetMethodName()); + NTypeBytecodeLowering lowering(data->GetCircuit(), data->GetPassContext(), enableLog, data->GetMethodName()); lowering.RunNTypeBytecodeLowering(); Chunk chunk(data->GetNativeAreaAllocator()); CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); @@ -445,6 +460,7 @@ public: CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); TypedNativeInlineLowering lowering(data->GetCircuit(), &visitor, + data->GetPassContext(), data->GetCompilerConfig(), &chunk); visitor.AddPass(&lowering); @@ -545,7 +561,7 @@ public: { TimeScope timescope("SlowPathLoweringPass", data->GetMethodName(), data->GetMethodOffset(), data->GetLog()); bool enableLog = data->GetLog()->EnableMethodCIRLog(); - SlowPathLowering lowering(data->GetCircuit(), data->GetCompilerConfig(), data->GetTSManager(), + SlowPathLowering lowering(data->GetCircuit(), data->GetCompilerConfig(), data->GetPassContext(), data->GetMethodLiteral(), enableLog, data->GetMethodName()); lowering.CallRuntimeLowering(); return true; @@ -670,7 +686,8 @@ public: bool enableLog = data->GetLog()->EnableMethodCIRLog() || data->GetLog()->EnableMethodASMLog(); Chunk chunk(data->GetNativeAreaAllocator()); CombinedPassVisitor visitor(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk); - EarlyElimination earlyElimination(data->GetCircuit(), &visitor, &chunk); + JSRuntimeOptions runtimeOption = data->GetPassContext()->GetEcmaVM()->GetJSOptions(); + EarlyElimination earlyElimination(data->GetCircuit(), &visitor, &chunk, runtimeOption.IsEnableMemoryAnalysis()); visitor.AddPass(&earlyElimination); visitor.VisitGraph(); visitor.PrintLog("early elimination"); @@ -782,7 +799,7 @@ public: Chunk chunk(data->GetNativeAreaAllocator()); bool enableLog = data->GetLog()->EnableMethodCIRLog(); bool licm = data->GetPassOptions()->EnableOptLoopInvariantCodeMotion(); - bool liteCG = data->GetTSManager()->GetEcmaVM()->GetJSOptions().IsCompilerEnableLiteCG(); + bool liteCG = data->GetPassContext()->GetEcmaVM()->GetJSOptions().IsCompilerEnableLiteCG(); GraphLinearizer(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk, false, licm, liteCG) .Run(data->GetCfg()); PostSchedule(data->GetCircuit(), enableLog, data->GetMethodName(), &chunk).Run(data->GetCfg()); diff --git a/ecmascript/compiler/pass_manager.cpp b/ecmascript/compiler/pass_manager.cpp index 117d67c746607b7ea22180866bade79435a7c7a7..ec41790e49b07d5550a46fd0adb8a15490e446aa 100644 --- a/ecmascript/compiler/pass_manager.cpp +++ b/ecmascript/compiler/pass_manager.cpp @@ -13,20 +13,19 @@ * limitations under the License. */ #include "ecmascript/compiler/pass_manager.h" + #include "ecmascript/compiler/bytecodes.h" #include "ecmascript/compiler/compilation_driver.h" #include "ecmascript/compiler/pass.h" #include "ecmascript/ecma_handle_scope.h" #include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/jspandafile/panda_file_translator.h" #include "ecmascript/log.h" #include "ecmascript/log_wrapper.h" #include "ecmascript/pgo_profiler/pgo_profiler_manager.h" -#include "ecmascript/ts_types/ts_manager.h" namespace panda::ecmascript::kungfu { using PGOProfilerManager = pgo::PGOProfilerManager; -bool JitPassManager::Compile(JSHandle &jsFunction, AOTFileGenerator &gen) +bool JitPassManager::Compile(JSHandle &jsFunction, AOTFileGenerator &gen, int32_t osrOffset) { [[maybe_unused]] EcmaHandleScope handleScope(vm_->GetJSThread()); const JSPandaFile *jsPandaFile = Method::Cast(jsFunction->GetMethod().GetTaggedObject())->GetJSPandaFile(); @@ -52,7 +51,7 @@ bool JitPassManager::Compile(JSHandle &jsFunction, AOTFileGenerator log_->OutputASM(), maxMethodsInModule_, vm_->GetJSOptions().GetCompilerMethodsRange()); - cmpDriver_->CompileMethod(jsFunction, [this, &fileName] (const CString recordName, + cmpDriver_->CompileMethod(jsFunction, [this, &fileName, &osrOffset] (const CString recordName, const std::string &methodName, MethodLiteral *methodLiteral, uint32_t methodOffset, @@ -66,10 +65,7 @@ bool JitPassManager::Compile(JSHandle &jsFunction, AOTFileGenerator auto jsPandaFile = ctx_->GetJSPandaFile(); auto cmpCfg = ctx_->GetCompilerConfig(); - auto tsManager = ctx_->GetTSManager(); auto module = m->GetModule(); - // note: TSManager need to set current constantpool before all pass - tsManager->SetCurConstantPool(jsPandaFile, methodOffset); log_->SetMethodLog(fileName, methodName, logList_); std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile); @@ -87,17 +83,18 @@ bool JitPassManager::Compile(JSHandle &jsFunction, AOTFileGenerator fullName.c_str(), cmpCfg->Is64Bit(), FrameType::OPTIMIZED_JS_FUNCTION_FRAME); PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : nullptr; - builder_ = new BytecodeCircuitBuilder(jsPandaFile, methodLiteral, methodPCInfo, tsManager, - circuit_, ctx_->GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(), - passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false, - passOptions_->EnableOptTrackField()); + builder_ = new BytecodeCircuitBuilder(jsPandaFile, methodLiteral, methodPCInfo, + circuit_, ctx_->GetByteCodes(), enableMethodLog && log_->OutputCIR(), + passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false); + builder_->SetOsrOffset(osrOffset); { TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_); builder_->BytecodeToCircuit(); } data_ = new PassData(builder_, circuit_, ctx_, log_, fullName, &methodInfo, hasTypes, recordName, - methodLiteral, methodOffset, vm_->GetNativeAreaAllocator(), decoder, passOptions_); + methodLiteral, methodOffset, nullptr, CVector {}, + vm_->GetNativeAreaAllocator(), decoder, passOptions_); PassRunner pipeline(data_); if (data_->GetMethodLiteral()->HasDebuggerStmt()) { data_->AbortCompilation(); @@ -109,17 +106,13 @@ bool JitPassManager::Compile(JSHandle &jsFunction, AOTFileGenerator pipeline.RunPass(); pipeline.RunPass(); } - pipeline.RunPass(); - if (data_->IsTypeAbort()) { - data_->AbortCompilation(); - return; - } pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); + pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); if (data_->IsTypeAbort()) { @@ -226,10 +219,7 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, PassContext ctx(triple_, log_, &collector, m->GetModule(), &profilerDecoder_); auto jsPandaFile = ctx.GetJSPandaFile(); auto cmpCfg = ctx.GetCompilerConfig(); - auto tsManager = ctx.GetTSManager(); auto module = m->GetModule(); - // note: TSManager need to set current constantpool before all pass - tsManager->SetCurConstantPool(jsPandaFile, methodOffset); log_->SetMethodLog(fileName, methodName, logList_); std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile); @@ -248,17 +238,17 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, PGOProfilerDecoder *decoder = passOptions_->EnableOptPGOType() ? &profilerDecoder_ : nullptr; - BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, tsManager, &circuit, - ctx.GetByteCodes(), hasTypes, enableMethodLog && log_->OutputCIR(), - passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false, - passOptions_->EnableOptTrackField()); + BytecodeCircuitBuilder builder(jsPandaFile, methodLiteral, methodPCInfo, &circuit, + ctx.GetByteCodes(), enableMethodLog && log_->OutputCIR(), + passOptions_->EnableTypeLowering(), fullName, recordName, decoder, false); { TimeScope timeScope("BytecodeToCircuit", methodName, methodOffset, log_); builder.BytecodeToCircuit(); } PassData data(&builder, &circuit, &ctx, log_, fullName, &methodInfo, hasTypes, recordName, - methodLiteral, methodOffset, vm_->GetNativeAreaAllocator(), decoder, passOptions_, + methodLiteral, methodOffset, callMethodFlagMap_, fileInfos_, + vm_->GetNativeAreaAllocator(), decoder, passOptions_, optBCRange_); PassRunner pipeline(&data); if (data.GetMethodLiteral()->HasDebuggerStmt()) { @@ -271,28 +261,14 @@ bool PassManager::Compile(JSPandaFile *jsPandaFile, const std::string &fileName, pipeline.RunPass(); pipeline.RunPass(); } - pipeline.RunPass(); - if (data.IsTypeAbort()) { - data.AbortCompilation(); - return; - } pipeline.RunPass(); - pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); - // skip async function, because some application run with errors. - if (methodInfo.IsTypeInferAbort()) { - data.AbortCompilation(); - return; - } pipeline.RunPass(); + pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); - if (data.IsTypeAbort()) { - data.AbortCompilation(); - return; - } pipeline.RunPass(); pipeline.RunPass(); pipeline.RunPass(); diff --git a/ecmascript/compiler/pass_manager.h b/ecmascript/compiler/pass_manager.h index 5c0ca17398adaa9bc610cbe6f92aaf1cd72f6a7d..637e85da6fb3120be4f9324ce18f35e41d80d460 100644 --- a/ecmascript/compiler/pass_manager.h +++ b/ecmascript/compiler/pass_manager.h @@ -16,16 +16,15 @@ #ifndef ECMASCRIPT_COMPILER_PASS_MANAGER_H #define ECMASCRIPT_COMPILER_PASS_MANAGER_H +#include "ecmascript/compiler/aot_compiler_preprocessor.h" #include "ecmascript/compiler/bytecode_info_collector.h" #include "ecmascript/compiler/compiler_log.h" #include "ecmascript/compiler/file_generators.h" #include "ecmascript/compiler/ir_module.h" -#include "ecmascript/compiler/pass_options.h" #include "ecmascript/compiler/ir_module.h" +#include "ecmascript/compiler/pass_options.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/jspandafile/method_literal.h" -#include "ecmascript/pgo_profiler/pgo_profiler_decoder.h" -#include "ecmascript/pgo_profiler/pgo_profiler_manager.h" #include "ecmascript/ts_types/ts_manager.h" namespace panda::ecmascript::kungfu { @@ -33,6 +32,9 @@ class Bytecodes; class LexEnvManager; class CompilationConfig; class PassData; +class CallMethodFlagMap; +struct AbcFileInfo; + class PassContext { public: PassContext(const std::string &triple, CompilerLog *log, BytecodeInfoCollector* collector, IRModule *aotModule, @@ -142,10 +144,12 @@ class PassManager { public: explicit PassManager(EcmaVM* vm, std::string &triple, size_t optLevel, size_t relocMode, CompilerLog *log, AotMethodLogList *logList, size_t maxAotMethodSize, size_t maxMethodsInModule, - PGOProfilerDecoder &profilerDecoder, PassOptions *passOptions, std::string optBCRange) + PGOProfilerDecoder &profilerDecoder, PassOptions *passOptions, + const CallMethodFlagMap *callMethodFlagMap, const CVector &fileInfos, std::string optBCRange) : vm_(vm), triple_(triple), optLevel_(optLevel), relocMode_(relocMode), log_(log), logList_(logList), maxAotMethodSize_(maxAotMethodSize), maxMethodsInModule_(maxMethodsInModule), - profilerDecoder_(profilerDecoder), passOptions_(passOptions), optBCRange_(optBCRange) { + profilerDecoder_(profilerDecoder), passOptions_(passOptions), + callMethodFlagMap_(callMethodFlagMap), fileInfos_(fileInfos), optBCRange_(optBCRange) { enableJITLog_ = vm_->GetJSOptions().GetTraceJIT(); }; @@ -165,6 +169,8 @@ protected: size_t maxMethodsInModule_ {0}; PGOProfilerDecoder &profilerDecoder_; PassOptions *passOptions_ {nullptr}; + const CallMethodFlagMap *callMethodFlagMap_ {nullptr}; + const CVector &fileInfos_; std::string optBCRange_ {}; bool enableJITLog_ {false}; }; @@ -174,9 +180,10 @@ public: JitPassManager(EcmaVM* vm, std::string &triple, size_t optLevel, size_t relocMode, CompilerLog *log, AotMethodLogList *logList, PGOProfilerDecoder &profilerDecoder, PassOptions *passOptions) - : PassManager(vm, triple, optLevel, relocMode, log, logList, 1, 1, profilerDecoder, passOptions, "") { }; + : PassManager(vm, triple, optLevel, relocMode, log, logList, 1, 1, profilerDecoder, passOptions, + nullptr, CVector {}, "") { }; - bool Compile(JSHandle &jsFunction, AOTFileGenerator &gen); + bool Compile(JSHandle &jsFunction, AOTFileGenerator &gen, int32_t osrOffset = -1); bool RunCg(); virtual ~JitPassManager(); diff --git a/ecmascript/compiler/pass_options.h b/ecmascript/compiler/pass_options.h index 801d161f174fd47d975ff2595af8901564d4cc41..2eff553e9d6d4c9c67b2a4bf811e83cbc58d88cc 100644 --- a/ecmascript/compiler/pass_options.h +++ b/ecmascript/compiler/pass_options.h @@ -39,7 +39,8 @@ namespace panda::ecmascript::kungfu { V(LoweringBuiltin, false) \ V(FastModule, false) \ V(OptBranchProfiling, true) \ - V(EscapeAnalysis, false) + V(EscapeAnalysis, false) \ + V(InductionVariableAnalysis, false) #define OPTION_BUILDER(NAME, DEFAULT) \ Builder &Enable##NAME(bool value) { \ diff --git a/ecmascript/compiler/pgo_type/pgo_type_manager.cpp b/ecmascript/compiler/pgo_type/pgo_type_manager.cpp index 198c32450ea251702256d31ad3e3efd67f3a2cb6..cf1cf5bef3f904d0b5fbdd9d0d3585b630270d37 100644 --- a/ecmascript/compiler/pgo_type/pgo_type_manager.cpp +++ b/ecmascript/compiler/pgo_type/pgo_type_manager.cpp @@ -16,8 +16,8 @@ #include "ecmascript/compiler/pgo_type/pgo_type_manager.h" #include "ecmascript/ecma_vm.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/object_factory.h" -#include "ecmascript/tagged_array-inl.h" #include "index_accessor.h" namespace panda::ecmascript::kungfu { @@ -31,11 +31,24 @@ void PGOTypeManager::Iterate(const RootVisitor &v) aotSnapshot_.Iterate(v); } -int32_t PGOTypeManager::GetConstantPoolIDByMethodOffset(const JSPandaFile *jsPandaFile, uint32_t methodOffset) +uint32_t PGOTypeManager::GetConstantPoolIDByMethodOffset(const uint32_t methodOffset) const { - panda_file::IndexAccessor indexAccessor(*jsPandaFile->GetPandaFile(), + ASSERT(curJSPandaFile_!=nullptr); + panda_file::IndexAccessor indexAccessor(*curJSPandaFile_->GetPandaFile(), panda_file::File::EntityId(methodOffset)); - return static_cast(indexAccessor.GetHeaderIndex()); + return static_cast(indexAccessor.GetHeaderIndex()); +} + +JSTaggedValue PGOTypeManager::GetConstantPoolByMethodOffset(const uint32_t methodOffset) const +{ + uint32_t cpId = GetConstantPoolIDByMethodOffset(methodOffset); + return thread_->GetCurrentEcmaContext()->FindConstpool(curJSPandaFile_, cpId); +} + +JSTaggedValue PGOTypeManager::GetStringFromConstantPool(const uint32_t methodOffset, const uint16_t cpIdx) const +{ + JSTaggedValue cp = GetConstantPoolByMethodOffset(methodOffset); + return ConstantPool::GetStringFromCache(thread_, cp, cpIdx); } void PGOTypeManager::InitAOTSnapshot(uint32_t compileFilesCount) @@ -180,10 +193,4 @@ JSTaggedValue PGOTypeManager::QueryHClass(ProfileType rootType, ProfileType chil } return result; } - -void PGOTypeManager::SetCurConstantPool(const JSPandaFile *jsPandaFile, uint32_t methodOffset) -{ - curCPID_ = GetConstantPoolIDByMethodOffset(jsPandaFile, methodOffset); - curCP_ = thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile, curCPID_); -} } // namespace panda::ecmascript diff --git a/ecmascript/compiler/pgo_type/pgo_type_manager.h b/ecmascript/compiler/pgo_type/pgo_type_manager.h index 68b16412c107b4ac5f72132b87b9a354b6a44888..0c26d0c42a62aec0df0a61cabe2b4bd5ed33958e 100644 --- a/ecmascript/compiler/pgo_type/pgo_type_manager.h +++ b/ecmascript/compiler/pgo_type/pgo_type_manager.h @@ -25,27 +25,27 @@ public: : thread_(vm->GetJSThread()), aotSnapshot_(vm) {} ~PGOTypeManager() = default; - static int32_t GetConstantPoolIDByMethodOffset(const JSPandaFile *jsPandaFile, uint32_t methodOffset); - void Iterate(const RootVisitor &v); // common - JSThread* GetJSThread() + uint32_t PUBLIC_API GetConstantPoolIDByMethodOffset(const uint32_t methodOffset) const; + + JSTaggedValue PUBLIC_API GetConstantPoolByMethodOffset(const uint32_t methodOffset) const; + + JSTaggedValue PUBLIC_API GetStringFromConstantPool(const uint32_t methodOffset, const uint16_t cpIdx) const; + + inline JSThread* GetJSThread() { return thread_; } - void PUBLIC_API SetCurConstantPool(const JSPandaFile *jsPandaFile, uint32_t methodOffset); - - JSHandle GetCurConstantPool() const + void PUBLIC_API SetCurCompilationFile(const JSPandaFile *jsPandaFile) { - return JSHandle(uintptr_t(&curCP_)); + curJSPandaFile_ = jsPandaFile; } // snapshot void PUBLIC_API InitAOTSnapshot(uint32_t compileFilesCount); - void GenArrayInfo(); - void GenConstantIndexInfo(); AOTSnapshot& GetAOTSnapshot() { @@ -103,10 +103,12 @@ public: { locToElmsKindMap_.emplace(loc, kind); } - + private: // snapshot void GenHClassInfo(); + void GenArrayInfo(); + void GenConstantIndexInfo(); // opt to std::unordered_map using TransIdToHClass = std::map; @@ -123,10 +125,9 @@ private: std::map idElmsKindMap_ {}; AOTSnapshot aotSnapshot_; - // When the passmanager iterates each method, the curCP_ and curCPID_ should be updated, - // so that subsequent passes (type_infer, ts_hcr_lowering) can obtain the correct constpool. - JSTaggedValue curCP_ {JSTaggedValue::Hole()}; - int32_t curCPID_ {0}; + // Since there is only one PGOTypeManager instance during compilation, + // the currently compiled jspandafile needs to be set to satisfy multi-file compilation. + const JSPandaFile *curJSPandaFile_ {nullptr}; }; } // panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_PGO_TYPE_PGO_TYPE_MANAGER_H diff --git a/ecmascript/compiler/profiler_stub_builder.cpp b/ecmascript/compiler/profiler_stub_builder.cpp index 5bcf1fbe50a96b22e495ff1f98128a56d6d5e29b..bb4856b58ba7ba620e975a6104e1075af018ea2d 100644 --- a/ecmascript/compiler/profiler_stub_builder.cpp +++ b/ecmascript/compiler/profiler_stub_builder.cpp @@ -58,7 +58,7 @@ void ProfilerStubBuilder::PGOProfiler(GateRef glue, GateRef pc, GateRef func, Ga ProfileGetIterator(glue, pc, func, values[0], profileTypeInfo, format); break; case OperationType::TRY_JIT: - TryJitCompile(glue, func, profileTypeInfo); + TryJitCompile(glue, pc, func, profileTypeInfo); break; default: break; @@ -265,7 +265,7 @@ void ProfilerStubBuilder::ProfileCall( Bind(¤tIsHotness); { Label icSlotValid(env); - Label isInt(env); + Label isHeapObject(env); Label uninitialized(env); Label updateSlot(env); @@ -274,23 +274,21 @@ void ProfilerStubBuilder::ProfileCall( BRANCH(Int32LessThan(slotId, length), &icSlotValid, &exit); Bind(&icSlotValid); GateRef slotValue = GetValueFromTaggedArray(profileTypeInfo, slotId); - BRANCH(TaggedIsInt(slotValue), &isInt, &uninitialized); - Bind(&isInt); + BRANCH(TaggedIsHeapObject(slotValue), &isHeapObject, &uninitialized); + Bind(&isHeapObject); { Label change(env); Label resetSlot(env); - GateRef oldSlotValue = TaggedGetInt(slotValue); - GateRef methodId = env->GetBuilder()->GetMethodId(target); - BRANCH(Int32Equal(oldSlotValue, TruncInt64ToInt32(methodId)), &exit, &change); + GateRef method = env->GetBuilder()->GetMethodFromFunction(target); + BRANCH(Int64Equal(slotValue, method), &exit, &change); Bind(&change); { - GateRef polyCallCheck = Int32Equal(oldSlotValue, Int32(base::PGO_POLY_INLINE_REP)); - GateRef emptyCallCheck = Int32Equal(oldSlotValue, Int32(0)); - BRANCH(BoolOr(polyCallCheck, emptyCallCheck), &exit, &resetSlot); + BRANCH(Int64Equal(ChangeTaggedPointerToInt64(slotValue), Int64(0)), &exit, &resetSlot); } Bind(&resetSlot); { - GateRef nonType = IntToTaggedInt(Int32(base::PGO_POLY_INLINE_REP)); + // NOTICE-PGO: lx about poly + GateRef nonType = IntToTaggedInt(Int64(0)); SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, nonType); TryPreDumpInner(glue, func, profileTypeInfo); Jump(&exit); @@ -302,9 +300,8 @@ void ProfilerStubBuilder::ProfileCall( } Bind(&updateSlot); { - GateRef methodId = env->GetBuilder()->GetMethodId(target); - GateRef methodIdValue = IntToTaggedInt(TruncInt64ToInt32(methodId)); - SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, methodIdValue); + GateRef method = env->GetBuilder()->GetMethodFromFunction(target); + SetValueToTaggedArray(VariableType::JS_ANY(), glue, profileTypeInfo, slotId, method); TryPreDumpInner(glue, func, profileTypeInfo); Jump(&exit); } @@ -468,7 +465,7 @@ void ProfilerStubBuilder::UpdatePropAttrIC( env->SubCfgExit(); } -void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef jsType, GateRef layout, GateRef attr, +void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef layout, GateRef attr, GateRef attrIndex, GateRef value, ProfileOperation callback) { if (callback.IsEmpty()) { @@ -479,9 +476,9 @@ void ProfilerStubBuilder::UpdatePropAttrWithValue(GateRef glue, GateRef jsType, env->SubCfgEntry(&entry); Label exit(env); Label updateLayout(env); - Label notSharedType(env); - BRANCH(IsJSSharedType(jsType), &exit, ¬SharedType); - Bind(¬SharedType); + Label isNotJSShared(env); + BRANCH(IsJSShared(receiver), &exit, &isNotJSShared); + Bind(&isNotJSShared); GateRef newAttr = UpdateTrackTypeInPropAttr(attr, value, callback); BRANCH(Equal(attr, newAttr), &exit, &updateLayout); Bind(&updateLayout); @@ -663,7 +660,7 @@ GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterat BRANCH(Int64Equal(iterator, *maybeFunc), &isArrayProtoValues, ¬ArrayProtoValues); Bind(&isArrayProtoValues); { - functionId = Int32(PGO_BUILTINS_STUB_ID(ARRAY_PROTO_ITERATOR)); + functionId = Int32(PGO_BUILTINS_STUB_ID(ArrayProtoIterator)); Jump(&exit); } Bind(¬ArrayProtoValues); @@ -671,7 +668,7 @@ GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterat BRANCH(Int64Equal(iterator, *maybeFunc), &isSetProtoValues, ¬SetProtoValues); Bind(&isSetProtoValues); { - functionId = Int32(PGO_BUILTINS_STUB_ID(SET_PROTO_ITERATOR)); + functionId = Int32(PGO_BUILTINS_STUB_ID(SetProtoIterator)); Jump(&exit); } Bind(¬SetProtoValues); @@ -679,7 +676,7 @@ GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterat BRANCH(Int64Equal(iterator, *maybeFunc), &isMapProtoEntries, ¬MapProtoEntries); Bind(&isMapProtoEntries); { - functionId = Int32(PGO_BUILTINS_STUB_ID(MAP_PROTO_ITERATOR)); + functionId = Int32(PGO_BUILTINS_STUB_ID(MapProtoIterator)); Jump(&exit); } Bind(¬MapProtoEntries); @@ -687,7 +684,7 @@ GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterat BRANCH(Int64Equal(iterator, *maybeFunc), &isStringProtoIter, ¬StringProtoIter); Bind(&isStringProtoIter); { - functionId = Int32(PGO_BUILTINS_STUB_ID(STRING_PROTO_ITERATOR)); + functionId = Int32(PGO_BUILTINS_STUB_ID(StringProtoIterator)); Jump(&exit); } Bind(¬StringProtoIter); @@ -696,7 +693,7 @@ GateRef ProfilerStubBuilder::GetIterationFunctionId(GateRef glue, GateRef iterat BRANCH(Int64Equal(iterator, *maybeFunc), &isTypedArrayProtoValues, &exit); Bind(&isTypedArrayProtoValues); { - functionId = Int32(PGO_BUILTINS_STUB_ID(TYPED_ARRAY_PROTO_ITERATOR)); + functionId = Int32(PGO_BUILTINS_STUB_ID(TypeArrayProtoIterator)); Jump(&exit); } Bind(&exit); @@ -842,6 +839,33 @@ GateRef ProfilerStubBuilder::GetJitHotnessThreshold(GateRef profileTypeInfo) return ZExtInt16ToInt32(hotnessThreshold); } +GateRef ProfilerStubBuilder::GetOsrHotnessThresholdOffset(GateRef profileTypeInfo) +{ + GateRef bitFieldOffset = GetBitFieldOffsetFromProfileTypeInfo(profileTypeInfo); + return PtrAdd(bitFieldOffset, + IntPtr(ProfileTypeInfo::OSR_HOTNESS_THRESHOLD_OFFSET_FROM_BITFIELD)); +} + +GateRef ProfilerStubBuilder::GetOsrHotnessThreshold(GateRef profileTypeInfo) +{ + GateRef hotnessThresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo); + GateRef hotnessThreshold = Load(VariableType::INT16(), profileTypeInfo, hotnessThresholdOffset); + return ZExtInt16ToInt32(hotnessThreshold); +} + +GateRef ProfilerStubBuilder::GetOsrHotnessCntOffset(GateRef profileTypeInfo) +{ + GateRef thresholdOffset = GetOsrHotnessThresholdOffset(profileTypeInfo); + return PtrAdd(thresholdOffset, IntPtr(ProfileTypeInfo::OSR_CNT_OFFSET_FROM_OSR_THRESHOLD)); +} + +GateRef ProfilerStubBuilder::GetOsrHotnessCnt(GateRef profileTypeInfo) +{ + GateRef hotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo); + GateRef hotnessCnt = Load(VariableType::INT16(), profileTypeInfo, hotnessCntOffset); + return ZExtInt16ToInt32(hotnessCnt); +} + GateRef ProfilerStubBuilder::IsHotForJitCompiling(GateRef profileTypeInfo) { auto env = GetEnvironment(); @@ -862,31 +886,86 @@ GateRef ProfilerStubBuilder::IsHotForJitCompiling(GateRef profileTypeInfo) return ret; } -void ProfilerStubBuilder::TryJitCompile(GateRef glue, GateRef func, GateRef profileTypeInfo) +void ProfilerStubBuilder::TryJitCompile(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo) { auto env = GetEnvironment(); Label subEntry(env); env->SubCfgEntry(&subEntry); + Label equalJitThreshold(env); + Label notEqualJitThreshold(env); + Label incJitHotnessCntAndCmpOpcode(env); + Label incJitHotnessCntAndExit(env); + Label cmpOpcode(env); + Label cmpOsrThreshold(env); + Label equalOsrThreshold(env); + Label notEqualOsrThreshold(env); + Label incOsrHotnessCnt(env); Label exit(env); - GateRef hotnessThreshold = GetJitHotnessThreshold(profileTypeInfo); - GateRef hotnessCnt = GetJitHotnessCnt(profileTypeInfo); - Label equalThreshold(env); - Label notEqualThreshold(env); - Label incCnt(env); - BRANCH(Int32Equal(hotnessCnt, hotnessThreshold), &equalThreshold, ¬EqualThreshold); - Bind(&equalThreshold); + GateRef jitHotnessThreshold = GetJitHotnessThreshold(profileTypeInfo); + GateRef jitHotnessCnt = GetJitHotnessCnt(profileTypeInfo); + GateRef osrHotnessThreshold = GetOsrHotnessThreshold(profileTypeInfo); + GateRef osrHotnessCnt = GetOsrHotnessCnt(profileTypeInfo); + + BRANCH(Int32Equal(jitHotnessCnt, jitHotnessThreshold), &equalJitThreshold, ¬EqualJitThreshold); + Bind(&equalJitThreshold); + { + DEFVARIABLE(varOffset, VariableType::INT32(), Int32(MachineCode::INVALID_OSR_OFFSET)); + CallRuntime(glue, RTSTUB_ID(JitCompile), { func, *varOffset }); + Jump(&incJitHotnessCntAndExit); + } + Bind(¬EqualJitThreshold); + { + BRANCH(Int32LessThan(jitHotnessCnt, jitHotnessThreshold), &incJitHotnessCntAndCmpOpcode, &exit); + } + Bind(&incJitHotnessCntAndCmpOpcode); + { + GateRef newJitHotnessCnt = Int16Add(jitHotnessCnt, Int16(1)); + GateRef jitHotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo); + Store(VariableType::INT16(), glue, profileTypeInfo, jitHotnessCntOffset, newJitHotnessCnt); + Jump(&cmpOpcode); + } + Bind(&incJitHotnessCntAndExit); + { + GateRef newJitHotnessCnt = Int16Add(jitHotnessCnt, Int16(1)); + GateRef jitHotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo); + Store(VariableType::INT16(), glue, profileTypeInfo, jitHotnessCntOffset, newJitHotnessCnt); + Jump(&exit); + } + Bind(&cmpOpcode); + { + GateRef opcode = Load(VariableType::INT8(), pc); + GateRef jmpImm8 = Int8(static_cast(EcmaOpcode::JMP_IMM8)); + GateRef jmpImm16 = Int8(static_cast(EcmaOpcode::JMP_IMM16)); + GateRef jmpImm32 = Int8(static_cast(EcmaOpcode::JMP_IMM32)); + GateRef isJmp = BoolOr(Int8Equal(opcode, jmpImm8), Int8Equal(opcode, jmpImm16)); + isJmp = BoolOr(isJmp, Int8Equal(opcode, jmpImm32)); + BRANCH(isJmp, &cmpOsrThreshold, &exit); + } + Bind(&cmpOsrThreshold); + { + BRANCH(Int32Equal(osrHotnessCnt, osrHotnessThreshold), &equalOsrThreshold, ¬EqualOsrThreshold); + } + Bind(&equalOsrThreshold); + { + GateRef method = GetMethodFromJSFunction(func); + GateRef firstPC = Load(VariableType::NATIVE_POINTER(), method, + IntPtr(Method::NATIVE_POINTER_OR_BYTECODE_ARRAY_OFFSET)); + GateRef offset = TaggedPtrToTaggedIntPtr(PtrSub(pc, firstPC)); + CallRuntime(glue, RTSTUB_ID(JitCompile), { func, offset }); + GateRef osrHotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo); + Store(VariableType::INT16(), glue, profileTypeInfo, osrHotnessCntOffset, Int16(0)); + Jump(&exit); + } + Bind(¬EqualOsrThreshold); { - CallRuntime(glue, RTSTUB_ID(JitCompile), { func }); - Jump(&incCnt); + BRANCH(Int32LessThan(osrHotnessCnt, osrHotnessThreshold), &incOsrHotnessCnt, &exit); } - Bind(¬EqualThreshold); - BRANCH(Int32LessThan(hotnessCnt, hotnessThreshold), &incCnt, &exit); - Bind(&incCnt); + Bind(&incOsrHotnessCnt); { - GateRef newCnt = Int16Add(hotnessCnt, Int16(1)); - GateRef hotnessCntOffset = GetJitHotnessCntOffset(profileTypeInfo); - Store(VariableType::INT16(), glue, profileTypeInfo, hotnessCntOffset, newCnt); + GateRef newOsrHotnessCnt = Int16Add(osrHotnessCnt, Int16(1)); + GateRef osrHotnessCntOffset = GetOsrHotnessCntOffset(profileTypeInfo); + Store(VariableType::INT16(), glue, profileTypeInfo, osrHotnessCntOffset, newOsrHotnessCnt); Jump(&exit); } Bind(&exit); diff --git a/ecmascript/compiler/profiler_stub_builder.h b/ecmascript/compiler/profiler_stub_builder.h index e5833c0808b2915b7425423ee1255d18b88ad6b7..0b074808a7380790e08499e9cca17ac4a30f4444 100644 --- a/ecmascript/compiler/profiler_stub_builder.h +++ b/ecmascript/compiler/profiler_stub_builder.h @@ -51,12 +51,12 @@ public: GateRef UpdateTrackTypeInPropAttr(GateRef attr, GateRef value, ProfileOperation callback); void UpdatePropAttrIC(GateRef glue, GateRef receiver, GateRef value, GateRef handler, ProfileOperation callback); - void UpdatePropAttrWithValue(GateRef glue, GateRef jsType, GateRef layout, GateRef attr, GateRef attrIndex, + void UpdatePropAttrWithValue(GateRef glue, GateRef receiver, GateRef layout, GateRef attr, GateRef attrIndex, GateRef value, ProfileOperation callback); GateRef IsProfileTypeInfoDumped(GateRef profileTypeInfo, ProfileOperation callback); - void TryJitCompile(GateRef glue, GateRef func, GateRef profileTypeInfo); + void TryJitCompile(GateRef glue, GateRef pc, GateRef func, GateRef profileTypeInfo); GateRef IsHotForJitCompiling(GateRef profileTypeInfo, ProfileOperation callback); GateRef IsHotForJitCompiling(GateRef profileTypeInfo); @@ -82,6 +82,10 @@ private: GateRef GetJitHotnessThreshold(GateRef profileTypeInfo); GateRef GetJitHotnessThresholdOffset(GateRef profileTypeInfo); GateRef GetJitHotnessCntOffset(GateRef profileTypeInfo); + GateRef GetOsrHotnessThresholdOffset(GateRef profileTypeInfo); + GateRef GetOsrHotnessThreshold(GateRef profileTypeInfo); + GateRef GetOsrHotnessCntOffset(GateRef profileTypeInfo); + GateRef GetOsrHotnessCnt(GateRef profileTypeInfo); }; } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_PROFILER_STUB_BUILDER_H diff --git a/ecmascript/compiler/range_analysis.cpp b/ecmascript/compiler/range_analysis.cpp index 6837a091798aea514272d35f738140c5f8400d51..47d51671ac39e51f919ee8c242af537e2161fc02 100644 --- a/ecmascript/compiler/range_analysis.cpp +++ b/ecmascript/compiler/range_analysis.cpp @@ -274,10 +274,10 @@ RangeInfo RangeAnalysis::GetRangeOfCompare(GateRef gate, GateRef value, bool fla ASSERT((left == value) || (right == value)); bool swap = right == value; if (flag) { - op = TypedBinaryMetaData::GetRevCompareOp(op); + op = acc_.GetRevCompareOpForTypedBinOp(op); } if (swap) { - op = TypedBinaryMetaData::GetSwapCompareOp(op); + op = acc_.GetSwapCompareOpForTypedBinOp(op); } auto range = GetRange(swap ? left : right); if (range.IsNone()) { diff --git a/ecmascript/compiler/share_gate_meta_data.cpp b/ecmascript/compiler/share_gate_meta_data.cpp index 95e30fd791a3b6695850f22f8fb82dc736939c4c..1888d020e16b65d65afd6fb11033775dbf530326 100644 --- a/ecmascript/compiler/share_gate_meta_data.cpp +++ b/ecmascript/compiler/share_gate_meta_data.cpp @@ -58,7 +58,7 @@ bool GateMetaData::IsRoot() const bool GateMetaData::IsProlog() const { - return (opcode_ == OpCode::ARG); + return (opcode_ == OpCode::ARG || opcode_ == OpCode::INITVREG); } bool GateMetaData::IsFixed() const @@ -345,4 +345,11 @@ CACHED_ARG_LIST(DECLARE_CACHED_VALUE_CASE) meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER); return meta; } + +const GateMetaData* GateMetaBuilder::InitVreg(uint64_t value) +{ + auto meta = new (chunk_) OneParameterMetaData(OpCode::INITVREG, GateFlags::HAS_ROOT, 0, 0, 0, value); + meta->SetKind(GateMetaData::Kind::MUTABLE_ONE_PARAMETER); + return meta; +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/share_gate_meta_data.h b/ecmascript/compiler/share_gate_meta_data.h index c977016d493a56bc7bd7baa3ed103177858f8866..145243358180092cbbb2321b9b1bf8871fda5200 100644 --- a/ecmascript/compiler/share_gate_meta_data.h +++ b/ecmascript/compiler/share_gate_meta_data.h @@ -29,6 +29,7 @@ #include "libpandabase/macros.h" namespace panda::ecmascript::kungfu { +using ProfileType = pgo::ProfileType; using GateRef = int32_t; using PGOTypeRef = pgo::PGOTypeRef; using PGODefineOpType = pgo::PGODefineOpType; @@ -76,6 +77,7 @@ enum class TypedCallTargetCheckOp : uint8_t; V(InconsistentHClass9, INCONSISTENTHCLASS9) \ V(InconsistentHClass10, INCONSISTENTHCLASS10) \ V(InconsistentHClass11, INCONSISTENTHCLASS11) \ + V(InconsistentHClass12, INCONSISTENTHCLASS12) \ V(NotEcmaObject1, NOTECMAOBJECT1) \ V(NotNewObj1, NOTNEWOBJ1) \ V(NotNewObj2, NOTNEWOBJ2) \ @@ -113,6 +115,13 @@ enum class TypedCallTargetCheckOp : uint8_t; V(IsUndefinedOrHole, ISUNDEFINEDORHOLE) \ V(IsNotUndefinedOrHole, ISNOTUNDEFINEDORHOLE) \ V(BuiltinInliningTypeGuard, BUILTIN_INLINING_TYPE_GUARD) \ + V(OsrLoopExit, OSRLOOPEXIT) \ + V(IsNotEcmaObject, ISNOTECMAOBJECT) \ + V(IsNotDataView, ISNOTDATAVIEW) \ + V(IsNotTaggedBoolean, ISNOTTAGGEDBOOLEAN) \ + V(IndexLessZeroOrInfinity, INDEXLESSZEROORINFINITY) \ + V(ArrayBufferIsDetached, ARRAYBUFFERISDETACHED) \ + V(TotalSizeOverflow, TOTALSIZEOVERFLOW) enum class DeoptType : uint8_t { NOTCHECK = 0, @@ -458,15 +467,15 @@ public: GateType GetGateType() const { - return type_; + return GateType(type_); } - static uint64_t ToValue(GateType type) + ParamType GetParamType() const { - return static_cast(type.Value()); + return ParamType(type_); } private: - GateType type_; + uint32_t type_; }; class ValuePairTypeAccessor { @@ -505,15 +514,15 @@ private: uint64_t bitField_; }; -class GatePairTypeAccessor { +class TypeConvertAccessor { public: // type bits shift static constexpr int OPRAND_TYPE_BITS = 32; - explicit GatePairTypeAccessor(uint64_t value) : bitField_(value) {} + explicit TypeConvertAccessor(uint64_t value) : bitField_(value) {} - GateType GetLeftType() const + ParamType GetLeftType() const { - return GateType(LeftBits::Get(bitField_)); + return ParamType(LeftBits::Get(bitField_)); } GateType GetRightType() const @@ -521,7 +530,7 @@ public: return GateType(RightBits::Get(bitField_)); } - static uint64_t ToValue(GateType leftType, GateType rightType) + static uint64_t ToValue(ParamType leftType, GateType rightType) { return LeftBits::Encode(leftType.Value()) | RightBits::Encode(rightType.Value()); } @@ -662,18 +671,12 @@ private: class ObjectTypeAccessor { public: - static constexpr int TYPE_BITS_SIZE = 32; static constexpr int IS_HEAP_OBJECT_BIT_SIZE = 1; explicit ObjectTypeAccessor(uint64_t value) : bitField_(value) {} - explicit ObjectTypeAccessor(GateType type, bool isHeapObject = false) - { - bitField_ = TypeBits::Encode(type.Value()) | IsHeapObjectBit::Encode(isHeapObject); - } - - GateType GetType() const + explicit ObjectTypeAccessor(bool isHeapObject = false) { - return GateType(TypeBits::Get(bitField_)); + bitField_ = IsHeapObjectBit::Encode(isHeapObject); } bool IsHeapObject() const @@ -687,8 +690,7 @@ public: } private: - using TypeBits = panda::BitField; - using IsHeapObjectBit = TypeBits::NextField; + using IsHeapObjectBit = panda::BitField; uint64_t bitField_; }; @@ -745,18 +747,14 @@ public: }; static constexpr int TYPE_BITS_SIZE = 32; - static constexpr int MODE_BITS_SIZE = 8; - static constexpr int ON_HEAP_MODE_BITS_SIZE = 8; + static constexpr int MODE_BITS_SIZE = 2; + static constexpr int ON_HEAP_MODE_BITS_SIZE = 2; explicit TypedArrayMetaDateAccessor(uint64_t value) : bitField_(value) {} - explicit TypedArrayMetaDateAccessor(GateType type, Mode mode, OnHeapMode onHeap) - { - bitField_ = TypeBits::Encode(type.Value()) | ModeBits::Encode(mode) | OnHeapModeBits::Encode(onHeap); - } - GateType GetType() const + ParamType GetParamType() const { - return GateType(TypeBits::Get(bitField_)); + return ParamType(TypeBits::Get(bitField_)); } OnHeapMode GetOnHeapMode() const @@ -769,9 +767,9 @@ public: return ModeBits::Get(bitField_) == Mode::ACCESS_ELEMENT; } - uint64_t ToValue() const + static uint64_t ToValue(ParamType paramType, Mode mode, OnHeapMode onHeap) { - return bitField_; + return TypeBits::Encode(paramType.Value()) | ModeBits::Encode(mode) | OnHeapModeBits::Encode(onHeap); } private: diff --git a/ecmascript/compiler/share_opcodes.h b/ecmascript/compiler/share_opcodes.h index 55a233709a80355b32e9b37a6271493f51469ec0..6d343c0daea6db74522b7c4b478866cb29878a46 100644 --- a/ecmascript/compiler/share_opcodes.h +++ b/ecmascript/compiler/share_opcodes.h @@ -81,6 +81,7 @@ namespace panda::ecmascript::kungfu { #define SHARE_GATE_META_DATA_LIST_WITH_ONE_PARAMETER(V) \ V(Arg, ARG, GateFlags::HAS_ROOT, 0, 0, 0) \ + V(InitVreg, INITVREG, GateFlags::HAS_ROOT, 0, 0, 0) \ SHARE_GATE_META_DATA_LIST_WITH_VALUE(V) #define IMMUTABLE_META_DATA_CACHE_LIST(V) \ @@ -132,10 +133,9 @@ namespace panda::ecmascript::kungfu { #define GATE_OPCODE_LIST(V) \ SHARE_GATE_OPCODE_LIST(V) \ - MCR_GATE_OPCODE_LIST(V) \ HCR_GATE_OPCODE_LIST(V) -enum class OpCode : uint8_t { +enum class OpCode : uint16_t { NOP = 0, #define DECLARE_GATE_OPCODE(NAME, OP, R, S, D, V) OP, IMMUTABLE_META_DATA_CACHE_LIST(DECLARE_GATE_OPCODE) @@ -152,6 +152,15 @@ enum class OpCode : uint8_t { #undef DECLARE_GATE_OPCODE }; +// Special virtual register in the OSR. +static constexpr size_t INIT_VRGE_GLUE = -1; +static constexpr size_t INIT_VRGE_ARGS = -2; +static constexpr size_t INIT_VRGE_FUNCTION = -3; +static constexpr size_t INIT_VRGE_NEW_TARGET = -4; +static constexpr size_t INIT_VRGE_THIS_OBJECT = -5; +static constexpr size_t INIT_VRGE_NUM_ARGS = -6; +static constexpr size_t INIT_VRGE_ENV = -7; + } #endif // ECMASCRIPT_COMPILER_SHARE_GATE_META_DATA_H diff --git a/ecmascript/compiler/slowpath_lowering.cpp b/ecmascript/compiler/slowpath_lowering.cpp index 67fb5c6e31d5e916721db66f5c870f7a4c684205..483c9fbd7cf553ab3b95d1d0d0a774816615ed66 100644 --- a/ecmascript/compiler/slowpath_lowering.cpp +++ b/ecmascript/compiler/slowpath_lowering.cpp @@ -14,13 +14,15 @@ */ #include "ecmascript/compiler/slowpath_lowering.h" -#include "ecmascript/dfx/vm_thread_control.h" + +#include "ecmascript/compiler/bytecodes.h" +#include "ecmascript/compiler/new_object_stub_builder.h" #include "ecmascript/compiler/share_gate_meta_data.h" +#include "ecmascript/dfx/vm_thread_control.h" #include "ecmascript/dfx/vmstat/opt_code_profiler.h" +#include "ecmascript/js_async_generator_object.h" +#include "ecmascript/js_generator_object.h" #include "ecmascript/js_thread.h" -#include "ecmascript/message_string.h" -#include "ecmascript/compiler/bytecodes.h" -#include "ecmascript/compiler/new_object_stub_builder.h" namespace panda::ecmascript::kungfu { using UseIterator = GateAccessor::UseIterator; @@ -1542,8 +1544,7 @@ GateRef SlowPathLowering::LowerUpdateArrayHClass(GateRef gate, GateRef array) { ElementsKind kind = acc_.TryGetElementsKind(gate); if (!Elements::IsGeneric(kind)) { - auto thread = tsManager_->GetEcmaVM()->GetJSThread(); - size_t hclassIndex = static_cast(thread->GetArrayHClassIndexMap().at(kind)); + size_t hclassIndex = static_cast(thread_->GetArrayHClassIndexMap().at(kind)); GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue_, builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(false))); GateRef constantIndex = builder_.IntPtr(JSTaggedValue::TaggedTypeSize() * hclassIndex); @@ -2744,17 +2745,18 @@ void SlowPathLowering::AddProfiling(GateRef gate, bool skipGenerator) return; } + GateRef func = builder_.Undefined(); if (acc_.HasFrameState(gate)) { - GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); - GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate))); - auto ecmaOpcodeGate = builder_.Int32(static_cast(ecmaOpcode)); - GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate); - GateRef mode = - builder_.Int32ToTaggedInt(builder_.Int32(static_cast(OptCodeProfiler::Mode::SLOW_PATH))); - GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(gate), - { func, bcIndex, constOpcode, mode }, gate); - acc_.SetDep(gate, profiling); + func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); } + GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate))); + auto ecmaOpcodeGate = builder_.Int32(static_cast(ecmaOpcode)); + GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate); + GateRef mode = + builder_.Int32ToTaggedInt(builder_.Int32(static_cast(OptCodeProfiler::Mode::SLOW_PATH))); + GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(gate), + { func, bcIndex, constOpcode, mode }, gate); + acc_.SetDep(gate, profiling); } } diff --git a/ecmascript/compiler/slowpath_lowering.h b/ecmascript/compiler/slowpath_lowering.h index b6480eb1720ecdf53a20c9812427b32c7fec100a..6789c70745e67d57f70eb2a363191b84076a2439 100644 --- a/ecmascript/compiler/slowpath_lowering.h +++ b/ecmascript/compiler/slowpath_lowering.h @@ -17,11 +17,10 @@ #define ECMASCRIPT_COMPILER_SLOWPATH_LOWERING_H #include "ecmascript/compiler/argument_accessor.h" -#include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/circuit_builder.h" -#include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/gate_accessor.h" +#include "ecmascript/compiler/pass_manager.h" namespace panda::ecmascript::kungfu { // slowPath Lowering Process @@ -111,9 +110,9 @@ namespace panda::ecmascript::kungfu { class SlowPathLowering { public: SlowPathLowering(Circuit *circuit, CompilationConfig *cmpCfg, - TSManager *tsManager, const MethodLiteral *methodLiteral, + PassContext *ctx, const MethodLiteral *methodLiteral, bool enableLog, const std::string& name) - : tsManager_(tsManager), methodLiteral_(methodLiteral), + : thread_(ctx->GetEcmaVM()->GetJSThread()), methodLiteral_(methodLiteral), circuit_(circuit), acc_(circuit), argAcc_(circuit), builder_(circuit, cmpCfg), enableLog_(enableLog), methodName_(name), glue_(acc_.GetGlueFromArgList()) @@ -321,7 +320,7 @@ private: void LowerLdStr(GateRef gate); void LowerGetConstPool(GateRef gate); - TSManager *tsManager_ {nullptr}; + JSThread *thread_; const MethodLiteral *methodLiteral_ {nullptr}; Circuit *circuit_; GateAccessor acc_; diff --git a/ecmascript/compiler/stub_builder-inl.h b/ecmascript/compiler/stub_builder-inl.h index 2a150704efc33c7aadf02754995997c20e531191..62df75a7d7690b11fac00cdcd5ab1a688ffa721a 100644 --- a/ecmascript/compiler/stub_builder-inl.h +++ b/ecmascript/compiler/stub_builder-inl.h @@ -30,6 +30,7 @@ #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/ic/proto_change_details.h" #include "ecmascript/js_array.h" +#include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_function.h" #include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_generator_object.h" @@ -609,9 +610,9 @@ inline GateRef StubBuilder::TaggedIsStringIterator(GateRef obj) return env_->GetBuilder()->TaggedIsStringIterator(obj); } -inline GateRef StubBuilder::TaggedIsShared(GateRef obj) +inline GateRef StubBuilder::TaggedIsSharedObj(GateRef obj) { - return env_->GetBuilder()->TaggedIsShared(obj); + return env_->GetBuilder()->TaggedIsSharedObj(obj); } inline GateRef StubBuilder::TaggedIsStringOrSymbol(GateRef obj) @@ -707,6 +708,11 @@ inline GateRef StubBuilder::TaggedIsJSArray(GateRef x) return env_->GetBuilder()->TaggedIsJSArray(x); } +inline GateRef StubBuilder::IsTaggedArray(GateRef x) +{ + return env_->GetBuilder()->IsTaggedArray(x); +} + inline GateRef StubBuilder::TaggedIsAsyncGeneratorObject(GateRef x) { return env_->GetBuilder()->TaggedIsAsyncGeneratorObject(x); @@ -843,6 +849,11 @@ inline GateRef StubBuilder::CastDoubleToInt64(GateRef x) return env_->GetBuilder()->CastDoubleToInt64(x); } +inline GateRef StubBuilder::CastFloat32ToInt32(GateRef x) +{ + return env_->GetBuilder()->CastFloat32ToInt32(x); +} + inline GateRef StubBuilder::TaggedTrue() { return env_->GetBuilder()->TaggedTrue(); @@ -1064,6 +1075,12 @@ inline void StubBuilder::SetPropertiesArray(VariableType type, GateRef glue, Gat Store(type, glue, object, propertiesOffset, propsArray); } +inline GateRef StubBuilder::GetHash(GateRef object) +{ + GateRef hashOffset = IntPtr(ECMAObject::HASH_OFFSET); + return Load(VariableType::JS_ANY(), object, hashOffset); +} + inline void StubBuilder::SetHash(GateRef glue, GateRef object, GateRef hash) { GateRef hashOffset = IntPtr(ECMAObject::HASH_OFFSET); @@ -1216,6 +1233,12 @@ inline GateRef StubBuilder::IsSymbol(GateRef obj) return Int32Equal(objectType, Int32(static_cast(JSType::SYMBOL))); } +inline GateRef StubBuilder::IsDataView(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return Int32Equal(objectType, Int32(static_cast(JSType::JS_DATA_VIEW))); +} + inline GateRef StubBuilder::IsString(GateRef obj) { ASM_ASSERT(GET_MESSAGE_STRING_ID(IsJSObject), TaggedIsHeapObject(obj)); @@ -1265,8 +1288,7 @@ inline GateRef StubBuilder::IsJsProxy(GateRef obj) inline GateRef StubBuilder::IsJSShared(GateRef obj) { - GateRef objectType = GetObjectType(LoadHClass(obj)); - return IsJSSharedType(objectType); + return TaggedIsSharedObj(obj); } inline GateRef StubBuilder::IsJSGlobalObject(GateRef obj) @@ -1301,6 +1323,12 @@ inline GateRef StubBuilder::IsJsArray(GateRef obj) return Int32Equal(objectType, Int32(static_cast(JSType::JS_ARRAY))); } +inline GateRef StubBuilder::IsJsSArray(GateRef obj) +{ + GateRef objectType = GetObjectType(LoadHClass(obj)); + return Int32Equal(objectType, Int32(static_cast(JSType::JS_SHARED_ARRAY))); +} + inline GateRef StubBuilder::IsByteArray(GateRef obj) { GateRef objectType = GetObjectType(LoadHClass(obj)); @@ -1622,7 +1650,7 @@ inline GateRef StubBuilder::IsField(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::KindBit::START_BIT))), Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), Int32(HandlerBase::HandlerKind::FIELD)); } @@ -1631,7 +1659,7 @@ inline GateRef StubBuilder::IsNonSharedStoreField(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::SWholeKindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::SWholeKindBit::START_BIT))), Int32((1LLU << HandlerBase::SWholeKindBit::SIZE) - 1)), Int32(HandlerBase::StoreHandlerKind::S_FIELD)); } @@ -1639,8 +1667,8 @@ inline GateRef StubBuilder::IsNonSharedStoreField(GateRef attr) inline GateRef StubBuilder::IsStoreShared(GateRef attr) { return Int32NotEqual( - Int32And(Int32LSR(attr, - Int32(HandlerBase::SSharedBit::START_BIT)), + Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::SSharedBit::START_BIT))), Int32((1LLU << HandlerBase::SSharedBit::SIZE) - 1)), Int32(0)); } @@ -1649,7 +1677,7 @@ inline GateRef StubBuilder::IsElement(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::KindBit::START_BIT))), Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), Int32(HandlerBase::HandlerKind::ELEMENT)); } @@ -1658,7 +1686,7 @@ inline GateRef StubBuilder::IsStringElement(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::KindBit::START_BIT))), Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), Int32(HandlerBase::HandlerKind::STRING)); } @@ -1667,7 +1695,7 @@ inline GateRef StubBuilder::IsNumber(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::KindBit::START_BIT))), Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), Int32(HandlerBase::HandlerKind::NUMBER)); } @@ -1676,7 +1704,7 @@ inline GateRef StubBuilder::IsStringLength(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::KindBit::START_BIT))), Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), Int32(HandlerBase::HandlerKind::STRING_LENGTH)); } @@ -1685,7 +1713,7 @@ inline GateRef StubBuilder::IsTypedArrayElement(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::KindBit::START_BIT))), Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), Int32(HandlerBase::HandlerKind::TYPED_ARRAY)); } @@ -1694,7 +1722,7 @@ inline GateRef StubBuilder::IsNonExist(GateRef attr) { return Int32Equal( Int32And( - Int32LSR(attr, Int32(HandlerBase::KindBit::START_BIT)), + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::KindBit::START_BIT))), Int32((1LLU << HandlerBase::KindBit::SIZE) - 1)), Int32(HandlerBase::HandlerKind::NON_EXIST)); } @@ -1702,8 +1730,8 @@ inline GateRef StubBuilder::IsNonExist(GateRef attr) inline GateRef StubBuilder::HandlerBaseIsAccessor(GateRef attr) { return Int32NotEqual( - Int32And(Int32LSR(attr, - Int32(HandlerBase::AccessorBit::START_BIT)), + Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::AccessorBit::START_BIT))), Int32((1LLU << HandlerBase::AccessorBit::SIZE) - 1)), Int32(0)); } @@ -1711,8 +1739,8 @@ inline GateRef StubBuilder::HandlerBaseIsAccessor(GateRef attr) inline GateRef StubBuilder::HandlerBaseIsJSArray(GateRef attr) { return Int32NotEqual( - Int32And(Int32LSR(attr, - Int32(HandlerBase::IsJSArrayBit::START_BIT)), + Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::IsJSArrayBit::START_BIT))), Int32((1LLU << HandlerBase::IsJSArrayBit::SIZE) - 1)), Int32(0)); } @@ -1720,30 +1748,31 @@ inline GateRef StubBuilder::HandlerBaseIsJSArray(GateRef attr) inline GateRef StubBuilder::HandlerBaseIsInlinedProperty(GateRef attr) { return Int32NotEqual( - Int32And(Int32LSR(attr, - Int32(HandlerBase::InlinedPropsBit::START_BIT)), + Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::InlinedPropsBit::START_BIT))), Int32((1LLU << HandlerBase::InlinedPropsBit::SIZE) - 1)), Int32(0)); } inline GateRef StubBuilder::HandlerBaseGetOffset(GateRef attr) { - return Int32And(Int32LSR(attr, - Int32(HandlerBase::OffsetBit::START_BIT)), + return Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::OffsetBit::START_BIT))), Int32((1LLU << HandlerBase::OffsetBit::SIZE) - 1)); } inline GateRef StubBuilder::HandlerBaseGetAttrIndex(GateRef attr) { - return Int32And(Int32LSR(attr, - Int32(HandlerBase::AttrIndexBit::START_BIT)), + return Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::AttrIndexBit::START_BIT))), Int32((1LLU << HandlerBase::AttrIndexBit::SIZE) - 1)); } inline GateRef StubBuilder::HandlerBaseGetRep(GateRef attr) { - return Int32And(Int32LSR(attr, Int32(HandlerBase::RepresentationBit::START_BIT)), + return Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::RepresentationBit::START_BIT))), Int32((1LLU << HandlerBase::RepresentationBit::SIZE) - 1)); } @@ -2132,13 +2161,13 @@ inline GateRef StubBuilder::IsSpecialIndexedObj(GateRef jsType) return Int32GreaterThan(jsType, Int32(static_cast(JSType::JS_ARRAY))); } -inline void StubBuilder::CheckUpdateSharedType(bool isDicMode, Variable *result, GateRef glue, GateRef jsType, +inline void StubBuilder::CheckUpdateSharedType(bool isDicMode, Variable *result, GateRef glue, GateRef receiver, GateRef attr, GateRef value, Label *executeSetProp, Label *exit) { auto *env = GetEnvironment(); - Label isSharedObj(env); - BRANCH(IsJSSharedType(jsType), &isSharedObj, executeSetProp); - Bind(&isSharedObj); + Label isJSShared(env); + BRANCH(IsJSShared(receiver), &isJSShared, executeSetProp); + Bind(&isJSShared); { Label typeMismatch(env); GateRef fieldType = isDicMode ? GetDictSharedFieldTypeInPropAttr(attr) : GetSharedFieldTypeInPropAttr(attr); @@ -2170,20 +2199,14 @@ inline void StubBuilder::MatchFieldType(Variable *result, GateRef glue, GateRef inline GateRef StubBuilder::GetFieldTypeFromHandler(GateRef attr) { - return Int32And(Int32LSR(attr, - Int32(HandlerBase::SFieldTypeBit::START_BIT)), + return Int32And( + TruncInt64ToInt32(Int64LSR(attr, Int64(HandlerBase::SFieldTypeBit::START_BIT))), Int32((1LLU << HandlerBase::SFieldTypeBit::SIZE) - 1)); } inline GateRef StubBuilder::ClearSharedStoreKind(GateRef handlerInfo) { - return Int32And(handlerInfo, Int32Not(Int32(HandlerBase::SSharedBit::Mask()))); -} - -inline GateRef StubBuilder::IsJSSharedType(GateRef jsType) -{ - return BoolOr(Int32Equal(jsType, Int32(static_cast(JSType::JS_SHARED_OBJECT))), - Int32Equal(jsType, Int32(static_cast(JSType::JS_SHARED_FUNCTION)))); + return Int64And(handlerInfo, Int64Not(Int64(HandlerBase::SSharedBit::Mask()))); } inline GateRef StubBuilder::IsSpecialContainer(GateRef jsType) @@ -2194,6 +2217,11 @@ inline GateRef StubBuilder::IsSpecialContainer(GateRef jsType) Int32Equal(jsType, Int32(static_cast(JSType::JS_API_VECTOR)))); } +inline GateRef StubBuilder::IsSharedArray(GateRef jsType) +{ + return Int32Equal(jsType, Int32(static_cast(JSType::JS_SHARED_ARRAY))); +} + inline GateRef StubBuilder::IsFastTypeArray(GateRef jsType) { return BoolAnd( @@ -2309,6 +2337,11 @@ inline GateRef StubBuilder::ChangeFloat64ToInt32(GateRef x) return env_->GetBuilder()->ChangeFloat64ToInt32(x); } +inline GateRef StubBuilder::TruncDoubleToFloat32(GateRef x) +{ + return env_->GetBuilder()->TruncDoubleToFloat32(x); +} + inline GateRef StubBuilder::ChangeTaggedPointerToInt64(GateRef x) { return env_->GetBuilder()->ChangeTaggedPointerToInt64(x); @@ -2843,6 +2876,22 @@ inline GateRef StubBuilder::IsFastCall(GateRef method) Int64(0)); } +inline GateRef StubBuilder::IsJitCompiledCode(GateRef method) +{ + GateRef fieldOffset = IntPtr(Method::EXTRA_LITERAL_INFO_OFFSET); + GateRef literalField = Load(VariableType::INT64(), method, fieldOffset); + return Int64NotEqual( + Int64And( + Int64LSR(literalField, Int64(Method::IsJitCompiledCodeBit::START_BIT)), + Int64((1LU << Method::IsJitCompiledCodeBit::SIZE) - 1)), + Int64(0)); +} + +inline void StubBuilder::ClearJitCompiledCodeFlags(GateRef glue, GateRef method) +{ + CallNGCRuntime(glue, RTSTUB_ID(ClearJitCompiledCodeFlags), { method }); +} + inline GateRef StubBuilder::HasPrototype(GateRef kind) { GateRef greater = Int32GreaterThanOrEqual(kind, @@ -3207,5 +3256,44 @@ inline GateRef StubBuilder::GetKey(GateRef layoutInfo, GateRef index) GateRef fixedIdx = GetKeyIndex(index); return GetValueFromTaggedArray(layoutInfo, fixedIdx); } + +inline GateRef StubBuilder::IsMarkerCellValid(GateRef cell) +{ + return env_->GetBuilder()->IsMarkerCellValid(cell); +} + +inline GateRef StubBuilder::GetAccessorHasChanged(GateRef obj) +{ + return env_->GetBuilder()->GetAccessorHasChanged(obj); +} + +inline GateRef StubBuilder::ComputeTaggedTypedArraySize(GateRef elementSize, GateRef length) +{ + return PtrAdd(IntPtr(ByteArray::DATA_OFFSET), PtrMul(elementSize, length)); +} + +inline GateRef StubBuilder::GetViewedArrayBuffer(GateRef dataView) +{ + return Load(VariableType::JS_ANY(), dataView, + IntPtr(JSDataView::VIEW_ARRAY_BUFFER_OFFSET)); +} + +inline GateRef StubBuilder::GetByteOffset(GateRef dataView) +{ + return Load(VariableType::INT32(), dataView, + IntPtr(JSDataView::BYTE_OFFSET_OFFSET)); +} + +inline GateRef StubBuilder::GetByteLength(GateRef dataView) +{ + return Load(VariableType::INT32(), dataView, + IntPtr(JSDataView::BYTE_LENGTH_OFFSET)); +} + +inline GateRef StubBuilder::GetArrayBufferData(GateRef buffer) +{ + GateRef offset = IntPtr(JSArrayBuffer::DATA_OFFSET); + return Load(VariableType::JS_ANY(), buffer, offset); +} } // namespace panda::ecmascript::kungfu #endif // ECMASCRIPT_COMPILER_STUB_INL_H diff --git a/ecmascript/compiler/stub_builder.cpp b/ecmascript/compiler/stub_builder.cpp index 25f4647e8fea81a8b96939fc7491fbca4e4574e7..ae6337e4cc4710772fd87d2274555c6eee2ccc34 100644 --- a/ecmascript/compiler/stub_builder.cpp +++ b/ecmascript/compiler/stub_builder.cpp @@ -21,11 +21,11 @@ #include "ecmascript/compiler/assembler_module.h" #include "ecmascript/compiler/access_object_stub_builder.h" #include "ecmascript/compiler/builtins/builtins_string_stub_builder.h" +#include "ecmascript/compiler/builtins/builtins_typedarray_stub_builder.h" #include "ecmascript/compiler/interpreter_stub.h" #include "ecmascript/compiler/new_object_stub_builder.h" #include "ecmascript/compiler/profiler_stub_builder.h" #include "ecmascript/compiler/rt_call_signature.h" -#include "ecmascript/compiler/typed_array_stub_builder.h" #include "ecmascript/global_env_constants.h" #include "ecmascript/ic/properties_cache.h" #include "ecmascript/js_api/js_api_arraylist.h" @@ -148,58 +148,105 @@ void StubBuilder::MatchFieldType(GateRef fieldType, GateRef value, Label *execut Label isJSShared(env); Label checkBigInt(env); Label isBigInt(env); - Label checkJSNone(env); - Label isJSNone(env); + Label checkNoneOrGeneric(env); + Label isNoneOrGeneric(env); + Label checkNull(env); + Label isNull(env); + Label checkUndefined(env); + Label isUndefined(env); Label exit(env); DEFVARIABLE(result, VariableType::BOOL(), False()); - BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::NUMBER))), &isNumber, &checkBoolean); + GateRef checkType = BoolAnd( + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::NUMBER))), Int32(0)), + TaggedIsNumber(value)); + BRANCH(checkType, &isNumber, &checkBoolean); Bind(&isNumber); { - result = TaggedIsNumber(value); + result = True(); Jump(&exit); } Bind(&checkBoolean); { - BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::BOOLEAN))), &isBoolean, &checkString); + checkType = BoolAnd( + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::BOOLEAN))), Int32(0)), + TaggedIsBoolean(value)); + BRANCH(checkType, &isBoolean, &checkString); Bind(&isBoolean); { - result = TaggedIsBoolean(value); + result = True(); Jump(&exit); } } Bind(&checkString); { - BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::STRING))), &isString, &checkJSShared); + checkType = BoolAnd( + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::STRING))), Int32(0)), + BoolOr(TaggedIsString(value), TaggedIsNull(value))); + BRANCH(checkType, &isString, &checkJSShared); Bind(&isString); { - result = BoolOr(TaggedIsString(value), TaggedIsNull(value)); + result = True(); Jump(&exit); } } Bind(&checkJSShared); { - BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::SENDABLE))), &isJSShared, &checkBigInt); + checkType = BoolAnd( + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::SENDABLE))), Int32(0)), + BoolOr(TaggedIsSharedObj(value), TaggedIsNull(value))); + BRANCH(checkType, &isJSShared, &checkBigInt); Bind(&isJSShared); { - result = BoolOr(TaggedIsShared(value), TaggedIsNull(value)); + result = True(); Jump(&exit); } } Bind(&checkBigInt); { - BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::BIG_INT))), &isBigInt, &checkJSNone); + BRANCH(BoolAnd( + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::BIG_INT))), Int32(0)), + TaggedIsBigInt(value)), + &isBigInt, &checkNoneOrGeneric); Bind(&isBigInt); { - result = TaggedIsBigInt(value); + result = True(); + Jump(&exit); + } + } + Bind(&checkNoneOrGeneric); + { + BRANCH(BoolAnd( + BoolOr(Equal(fieldType, Int32(static_cast(SharedFieldType::NONE))), + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::GENERIC))), Int32(0))), + BoolOr(TaggedIsSharedObj(value), BoolNot(TaggedIsHeapObject(value)))), + &isNoneOrGeneric, &checkNull); + Bind(&isNoneOrGeneric); + { + // (none || generic) && (jsShared || !heapObject) + result = True(); + Jump(&exit); + } + } + Bind(&checkNull); + { + checkType = BoolAnd( + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::NULL_TYPE))), Int32(0)), + TaggedIsNull(value)); + BRANCH(checkType, &isNull, &checkUndefined); + Bind(&isNull); + { + result = True(); Jump(&exit); } } - Bind(&checkJSNone); + Bind(&checkUndefined); { - BRANCH(Equal(fieldType, Int32(static_cast(SharedFieldType::NONE))), &isJSNone, &exit); - Bind(&isJSNone); + checkType = BoolAnd( + Int32NotEqual(Int32And(fieldType, Int32(static_cast(SharedFieldType::UNDEFINED))), Int32(0)), + TaggedIsUndefined(value)); + BRANCH(checkType, &isUndefined, &exit); + Bind(&isUndefined); { - // bypass none type result = True(); Jump(&exit); } @@ -1717,23 +1764,27 @@ GateRef StubBuilder::CheckPolyHClass(GateRef cachedValue, GateRef hclass) BRANCH(TaggedIsWeak(cachedValue), &exit, &cachedValueNotWeak); Bind(&cachedValueNotWeak); { - GateRef length = GetLengthOfTaggedArray(cachedValue); - Jump(&loopHead); - LoopBegin(&loopHead); + Label isTaggedArray(env); + Branch(IsTaggedArray(cachedValue), &isTaggedArray, &exit); + Bind(&isTaggedArray); { - BRANCH(Int32UnsignedLessThan(*i, length), &iLessLength, &exit); - Bind(&iLessLength); + GateRef length = GetLengthOfTaggedArray(cachedValue); + Jump(&loopHead); + LoopBegin(&loopHead); { - GateRef element = GetValueFromTaggedArray(cachedValue, *i); - BRANCH(Equal(LoadObjectFromWeakRef(element), hclass), &hasHclass, &loopEnd); - Bind(&hasHclass); - result = GetValueFromTaggedArray(cachedValue, - Int32Add(*i, Int32(1))); - Jump(&exit); + BRANCH(Int32UnsignedLessThan(*i, length), &iLessLength, &exit); + Bind(&iLessLength); + { + GateRef element = GetValueFromTaggedArray(cachedValue, *i); + BRANCH(Equal(LoadObjectFromWeakRef(element), hclass), &hasHclass, &loopEnd); + Bind(&hasHclass); + result = GetValueFromTaggedArray(cachedValue, Int32Add(*i, Int32(1))); + Jump(&exit); + } + Bind(&loopEnd); + i = Int32Add(*i, Int32(2)); // 2 means one ic, two slot + LoopEnd(&loopHead); } - Bind(&loopEnd); - i = Int32Add(*i, Int32(2)); // 2 means one ic, two slot - LoopEnd(&loopHead); } } Bind(&exit); @@ -1775,7 +1826,7 @@ GateRef StubBuilder::LoadICWithHandler( BRANCH(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt); Bind(&handlerIsInt); { - GateRef handlerInfo = GetInt32OfTInt(*handler); + GateRef handlerInfo = GetInt64OfTInt(*handler); BRANCH(IsField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField); Bind(&handlerInfoIsField); { @@ -1982,13 +2033,13 @@ GateRef StubBuilder::ICStoreElement(GateRef glue, GateRef receiver, GateRef key, BRANCH(TaggedIsInt(*varHandler), &handlerIsInt, &handlerNotInt); Bind(&handlerIsInt); { - GateRef handlerInfo = GetInt32OfTInt(*varHandler); + GateRef handlerInfo = GetInt64OfTInt(*varHandler); BRANCH(IsTypedArrayElement(handlerInfo), &handlerInfoIsTypedArray, &handerInfoNotTypedArray); Bind(&handlerInfoIsTypedArray); { GateRef hclass = LoadHClass(receiver); GateRef jsType = GetObjectType(hclass); - TypedArrayStubBuilder typedArrayBuilder(this); + BuiltinsTypedArrayStubBuilder typedArrayBuilder(this); result = typedArrayBuilder.StoreTypedArrayElement(glue, receiver, index64, value, jsType); Jump(&exit); } @@ -2134,7 +2185,7 @@ GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef BRANCH(TaggedIsInt(*handler), &handlerIsInt, &handlerNotInt); Bind(&handlerIsInt); { - GateRef handlerInfo = GetInt32OfTInt(*handler); + GateRef handlerInfo = GetInt64OfTInt(*handler); BRANCH(IsNonSharedStoreField(handlerInfo), &handlerInfoIsField, &handlerInfoNotField); Bind(&handlerInfoIsField); { @@ -2223,7 +2274,7 @@ GateRef StubBuilder::StoreICWithHandler(GateRef glue, GateRef receiver, GateRef { holder = GetStoreTSHandlerHolder(*handler); handler = GetStoreTSHandlerHandlerInfo(*handler); - GateRef handlerInfo = GetInt32OfTInt(*handler); + GateRef handlerInfo = GetInt64OfTInt(*handler); BRANCH(IsField(handlerInfo), &aotHandlerInfoIsField, &aotHandlerInfoNotField); Bind(&aotHandlerInfoIsField); { @@ -2315,10 +2366,10 @@ GateRef StubBuilder::StoreWithTransition(GateRef glue, GateRef receiver, GateRef GateRef handlerInfo; if (withPrototype) { newHClass = GetTransWithProtoHClass(handler); - handlerInfo = GetInt32OfTInt(GetTransWithProtoHandlerInfo(handler)); + handlerInfo = GetInt64OfTInt(GetTransWithProtoHandlerInfo(handler)); } else { newHClass = GetTransitionHClass(handler); - handlerInfo = GetInt32OfTInt(GetTransitionHandlerInfo(handler)); + handlerInfo = GetInt64OfTInt(GetTransitionHandlerInfo(handler)); } GateRef oldHClass = LoadHClass(receiver); @@ -2531,7 +2582,7 @@ GateRef StubBuilder::GetPropertyByIndex(GateRef glue, GateRef receiver, GateRef BRANCH(IsFastTypeArray(jsType), &isFastTypeArray, ¬FastTypeArray); Bind(&isFastTypeArray); { - TypedArrayStubBuilder typedArrayStubBuilder(this); + BuiltinsTypedArrayStubBuilder typedArrayStubBuilder(this); result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, *holder, index, jsType); Jump(&exit); } @@ -3497,7 +3548,13 @@ GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef } Label isExtensible(env); Label notExtensible(env); + Label throwNotExtensible(env); BRANCH(IsExtensible(receiver), &isExtensible, ¬Extensible); + Bind(¬Extensible); + { + // fixme(hzzhouzebin) this makes SharedArray's frozen no sense. + BRANCH(IsJsSArray(receiver), &isExtensible, &throwNotExtensible); + } Bind(&isExtensible); { Label success(env); @@ -3515,7 +3572,7 @@ GateRef StubBuilder::SetPropertyByIndex(GateRef glue, GateRef receiver, GateRef Jump(&exit); } } - Bind(¬Extensible); + Bind(&throwNotExtensible); { GateRef taggedId = Int32(GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible)); CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(taggedId) }); @@ -3705,11 +3762,11 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k // JSObject::Cast(holder)->SetProperty(thread, hclass, attr, value) // return JSTaggedValue::Undefined() Label executeSetProp(env); - CheckUpdateSharedType(false, &result, glue, jsType, attr, value, &executeSetProp, &exit); + CheckUpdateSharedType(false, &result, glue, receiver, attr, value, &executeSetProp, &exit); Bind(&executeSetProp); JSObjectSetProperty(glue, *holder, hclass, attr, key, value); ProfilerStubBuilder(env).UpdatePropAttrWithValue( - glue, jsType, layOutInfo, attr, entry, value, callback); + glue, receiver, layOutInfo, attr, entry, value, callback); result = Undefined(); Jump(&exit); } @@ -3778,7 +3835,7 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k // dict->UpdateValue(thread, entry, value) // return JSTaggedValue::Undefined() Label executeSetProp(env); - CheckUpdateSharedType(true, &result, glue, jsType, attr1, value, &executeSetProp, &exit); + CheckUpdateSharedType(true, &result, glue, receiver, attr1, value, &executeSetProp, &exit); Bind(&executeSetProp); UpdateValueInDict(glue, array, entry1, value); result = Undefined(); @@ -3813,7 +3870,7 @@ GateRef StubBuilder::SetPropertyByName(GateRef glue, GateRef receiver, GateRef k GateRef holeAttr = GetPropAttrFromLayoutInfo(receiverLayoutInfo, *receiverHoleEntry); JSObjectSetProperty(glue, receiver, receiverHClass, holeAttr, key, value); ProfilerStubBuilder(env).UpdatePropAttrWithValue( - glue, jsType, receiverLayoutInfo, holeAttr, *receiverHoleEntry, value, callback); + glue, receiver, receiverLayoutInfo, holeAttr, *receiverHoleEntry, value, callback); result = Undefined(); Jump(&exit); } @@ -5633,7 +5690,7 @@ GateRef StubBuilder::TryStringAdd(Environment *env, GateRef glue, GateRef left, Bind(&stringLeftAddNumberRight); { Label hasPendingException(env); - callback.ProfileOpType(Int32(PGOSampleType::StringType())); + // NOTICE-PGO: support string and number BuiltinsStringStubBuilder builtinsStringStubBuilder(this); result = builtinsStringStubBuilder.StringConcat(glue, left, NumberToString(glue, right)); BRANCH(HasPendingException(glue), &hasPendingException, &exit); @@ -5644,7 +5701,7 @@ GateRef StubBuilder::TryStringAdd(Environment *env, GateRef glue, GateRef left, Bind(&numberLeftAddStringRight); { Label hasPendingException(env); - callback.ProfileOpType(Int32(PGOSampleType::StringType())); + // NOTICE-PGO: support string and number BuiltinsStringStubBuilder builtinsStringStubBuilder(this); result = builtinsStringStubBuilder.StringConcat(glue, NumberToString(glue, left), right); BRANCH(HasPendingException(glue), &hasPendingException, &exit); @@ -5686,7 +5743,7 @@ GateRef StubBuilder::FastBinaryOp(GateRef glue, GateRef left, GateRef right, DEFVARIABLE(result, VariableType::JS_ANY(), Hole()); DEFVARIABLE(doubleLeft, VariableType::FLOAT64(), Double(0)); DEFVARIABLE(doubleRight, VariableType::FLOAT64(), Double(0)); - + if (Op == OpCode::ADD) { // Try string Add result = TryStringAdd(env, glue, left, right, intOp, floatOp, callback); } else { @@ -6680,6 +6737,107 @@ void StubBuilder::ReturnExceptionIfAbruptCompletion(GateRef glue) return; } +GateRef StubBuilder::CalcHashcodeForInt(GateRef value) +{ + return env_->GetBuilder()->CalcHashcodeForInt(value); +} + +GateRef StubBuilder::CanDoubleRepresentInt(GateRef exp, GateRef expBits, GateRef fractionBits) +{ + GateRef isNanOrInf = Int64Equal(expBits, Int64(base::DOUBLE_EXPONENT_MASK)); + GateRef isSubnormal = BoolAnd( + Int64Equal(expBits, Int64(0)), + Int64NotEqual(fractionBits, Int64(0))); + GateRef hasFraction = Int64NotEqual( + Int64And( + Int64LSL(fractionBits, exp), + Int64(base::DOUBLE_SIGNIFICAND_MASK)), + Int64(0)); + GateRef badExp = BoolOr( + Int64LessThan(exp, Int64(0)), + Int64GreaterThanOrEqual(exp, Int64(31U))); + return BoolOr(BoolOr(BoolOr(isNanOrInf, isSubnormal), badExp), hasFraction); +} + +void StubBuilder::CalcHashcodeForDouble(GateRef x, Variable *res, Label *exit) +{ + auto env = GetEnvironment(); + GateRef xInt64 = Int64Sub(ChangeTaggedPointerToInt64(x), Int64(JSTaggedValue::DOUBLE_ENCODE_OFFSET)); + GateRef fractionBits = Int64And(xInt64, Int64(base::DOUBLE_SIGNIFICAND_MASK)); + GateRef expBits = Int64And(xInt64, Int64(base::DOUBLE_EXPONENT_MASK)); + GateRef signBit = Int64And(xInt64, Int64(base::DOUBLE_SIGN_MASK)); + GateRef isZero = BoolAnd( + Int64Equal(expBits, Int64(0)), + Int64Equal(fractionBits, Int64(0))); + Label zero(env); + Label nonZero(env); + + BRANCH(isZero, &zero, &nonZero); + Bind(&nonZero); + { + DEFVARIABLE(value, VariableType::JS_ANY(), x); + // exp = (u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE - DOUBLE_EXPONENT_BIAS + GateRef exp = Int64Sub( + Int64LSR(expBits, Int64(base::DOUBLE_SIGNIFICAND_SIZE)), + Int64(base::DOUBLE_EXPONENT_BIAS)); + Label convertToInt(env); + Label calcHash(env); + BRANCH(CanDoubleRepresentInt(exp, expBits, fractionBits), &calcHash, &convertToInt); + Bind(&convertToInt); + { + GateRef shift = Int64Sub(Int64(base::DOUBLE_SIGNIFICAND_SIZE), exp); + GateRef intVal = Int64Add( + Int64LSL(Int64(1), exp), + Int64LSR(fractionBits, shift)); + DEFVARIABLE(intVariable, VariableType::INT64(), intVal); + Label negate(env); + Label pass(env); + BRANCH(Int64NotEqual(signBit, Int64(0)), &negate, &pass); + Bind(&negate); + { + intVariable = Int64Sub(Int64(0), intVal); + Jump(&pass); + } + Bind(&pass); + value = IntToTaggedPtr(TruncInt64ToInt32(*intVariable)); + Jump(&calcHash); + } + Bind(&calcHash); + { + *res = env_->GetBuilder()->CalcHashcodeForInt(*value); + Jump(exit); + } + } + + Bind(&zero); + *res = env_->GetBuilder()->CalcHashcodeForInt(IntToTaggedPtr(Int32(0))); + Jump(exit); +} + +void StubBuilder::CalcHashcodeForObject(GateRef glue, GateRef value, Variable *res, Label *exit) +{ + auto env = GetEnvironment(); + + GateRef hash = GetHash(value); + *res = TruncInt64ToInt32(TaggedCastToIntPtr(hash)); + Label calcHash(env); + BRANCH(Int32Equal(**res, Int32(0)), &calcHash, exit); + Bind(&calcHash); + GateRef offset = IntPtr(JSThread::GlueData::GetRandomStatePtrOffset(env_->Is32Bit())); + GateRef randomStatePtr = Load(VariableType::NATIVE_POINTER(), glue, offset); + GateRef randomState = Load(VariableType::INT64(), randomStatePtr, IntPtr(0)); + GateRef k1 = Int64Xor(randomState, Int64LSR(randomState, Int64(base::RIGHT12))); + GateRef k2 = Int64Xor(k1, Int64LSL(k1, Int64(base::LEFT25))); + GateRef k3 = Int64Xor(k2, Int64LSR(k2, Int64(base::RIGHT27))); + Store(VariableType::INT64(), glue, randomStatePtr, IntPtr(0), k3); + GateRef k4 = Int64Mul(k3, Int64(base::GET_MULTIPLY)); + GateRef k5 = Int64LSR(k4, Int64(base::INT64_BITS - base::INT32_BITS)); + GateRef k6 = Int32And(TruncInt64ToInt32(k5), Int32(INT32_MAX)); + SetHash(glue, value, IntToTaggedPtr(k6)); + *res = k6; + Jump(exit); +} + GateRef StubBuilder::GetHashcodeFromString(GateRef glue, GateRef value) { return env_->GetBuilder()->GetHashcodeFromString(glue, value); @@ -6741,11 +6899,13 @@ GateRef StubBuilder::GetIterator(GateRef glue, GateRef obj, ProfileOperation cal Label exit(env); env->SubCfgEntry(&entryPass); DEFVARIABLE(result, VariableType::JS_ANY(), Exception()); + DEFVARIABLE(taggedId, VariableType::INT32(), Int32(0)); Label isPendingException(env); Label noPendingException(env); Label isHeapObject(env); Label objIsCallable(env); + Label throwError(env); GateRef glueGlobalEnvOffset = IntPtr(JSThread::GlueData::GetGlueGlobalEnvOffset(env->Is32Bit())); GateRef glueGlobalEnv = Load(VariableType::NATIVE_POINTER(), glue, glueGlobalEnvOffset); @@ -6759,16 +6919,22 @@ GateRef StubBuilder::GetIterator(GateRef glue, GateRef obj, ProfileOperation cal } Bind(&noPendingException); callback.ProfileGetIterator(*result); - BRANCH(TaggedIsHeapObject(*result), &isHeapObject, &exit); + BRANCH(TaggedIsHeapObject(*result), &isHeapObject, &throwError); Bind(&isHeapObject); - BRANCH(IsCallable(*result), &objIsCallable, &exit); + BRANCH(IsCallable(*result), &objIsCallable, &throwError); Bind(&objIsCallable); { result = JSCallDispatch(glue, *result, Int32(0), 0, Circuit::NullGate(), JSCallMode::CALL_GETTER, { obj }, ProfileOperation()); Jump(&exit); } - + Bind(&throwError); + { + taggedId = Int32(GET_MESSAGE_STRING_ID(ObjIsNotCallable)); + CallRuntime(glue, RTSTUB_ID(ThrowTypeError), { IntToTaggedInt(*taggedId) }); + result = Exception(); + Jump(&exit); + } Bind(&exit); auto ret = *result; env->SubCfgExit(); @@ -6815,7 +6981,7 @@ bool StubBuilder::IsCallModeSupportPGO(JSCallMode mode) GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize, GateRef hotnessCounter, JSCallMode mode, std::initializer_list args, - ProfileOperation callback) + ProfileOperation callback, bool checkIsCallable) { auto env = GetEnvironment(); Label entryPass(env); @@ -6829,20 +6995,26 @@ GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNu // save pc SavePcIfNeeded(glue); GateRef bitfield = 0; + GateRef hclass = 0; #if ECMASCRIPT_ENABLE_FUNCTION_CALL_TIMER CallNGCRuntime(glue, RTSTUB_ID(StartCallTimer), { glue, func, False()}); #endif - BRANCH(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable); - Bind(&funcIsHeapObject); - GateRef hclass = LoadHClass(func); - bitfield = Load(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET)); - BRANCH(IsCallableFromBitField(bitfield), &funcIsCallable, &funcNotCallable); - Bind(&funcNotCallable); - { - CallRuntime(glue, RTSTUB_ID(ThrowNotCallableException), {}); - Jump(&exit); + if (checkIsCallable) { + BRANCH(TaggedIsHeapObject(func), &funcIsHeapObject, &funcNotCallable); + Bind(&funcIsHeapObject); + hclass = LoadHClass(func); + bitfield = Load(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET)); + BRANCH(IsCallableFromBitField(bitfield), &funcIsCallable, &funcNotCallable); + Bind(&funcNotCallable); + { + CallRuntime(glue, RTSTUB_ID(ThrowNotCallableException), {}); + Jump(&exit); + } + Bind(&funcIsCallable); + } else { + hclass = LoadHClass(func); + bitfield = Load(VariableType::INT32(), hclass, IntPtr(JSHClass::BIT_FIELD_OFFSET)); } - Bind(&funcIsCallable); GateRef method = GetMethodFromJSFunction(func); GateRef callField = GetCallFieldFromMethod(method); GateRef isNativeMask = Int64(static_cast(1) << MethodLiteral::IsNativeBit::START_BIT); @@ -6973,10 +7145,6 @@ GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNu } // 4. call nonNative Bind(&methodNotNative); - - if (IsCallModeSupportPGO(mode)) { - callback.ProfileCall(func); - } Label funcIsClassConstructor(env); Label funcNotClassConstructor(env); Label methodNotAot(env); @@ -6992,6 +7160,9 @@ GateRef StubBuilder::JSCallDispatch(GateRef glue, GateRef func, GateRef actualNu BRANCH(IsClassConstructorFromBitField(bitfield), &funcIsClassConstructor, &methodNotAot); Bind(&funcIsClassConstructor); } + if (IsCallModeSupportPGO(mode)) { + callback.ProfileCall(func); + } GateRef sp = 0; if (env->IsAsmInterp()) { sp = Argument(static_cast(InterpreterHandlerInputs::SP)); @@ -7656,7 +7827,7 @@ GateRef StubBuilder::GetTypeArrayPropertyByName(GateRef glue, GateRef receiver, BRANCH(Int32GreaterThanOrEqual(index, Int32(0)), &validIndex, ¬ValidIndex); Bind(&validIndex); { - TypedArrayStubBuilder typedArrayStubBuilder(this); + BuiltinsTypedArrayStubBuilder typedArrayStubBuilder(this); result = typedArrayStubBuilder.FastGetPropertyByIndex(glue, holder, index, jsType); Jump(&exit); } @@ -8860,4 +9031,35 @@ void StubBuilder::MigrateFromHoleNumberToHoleInt(GateRef glue, GateRef object) Bind(&exit); env->SubCfgExit(); } + +GateRef StubBuilder::IsDetachedBuffer(GateRef buffer) +{ + auto env = GetEnvironment(); + Label entryPass(env); + env->SubCfgEntry(&entryPass); + Label isNull(env); + Label exit(env); + Label isByteArray(env); + Label notByteArray(env); + DEFVARIABLE(result, VariableType::BOOL(), False()); + BRANCH(IsByteArray(buffer), &isByteArray, ¬ByteArray); + Bind(&isByteArray); + { + Jump(&exit); + } + Bind(¬ByteArray); + { + GateRef dataSlot = GetArrayBufferData(buffer); + BRANCH(TaggedIsNull(dataSlot), &isNull, &exit); + Bind(&isNull); + { + result = True(); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env->SubCfgExit(); + return ret; +} } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/stub_builder.h b/ecmascript/compiler/stub_builder.h index 2cbe2451de0f5875434d5fda6b6c395eb13569e9..9b231d4fc75f2834861aa83f26ecd3850fd7d1b7 100644 --- a/ecmascript/compiler/stub_builder.h +++ b/ecmascript/compiler/stub_builder.h @@ -241,6 +241,7 @@ public: GateRef InSharedSweepableSpace(GateRef region); GateRef TaggedIsGeneratorObject(GateRef x); GateRef TaggedIsJSArray(GateRef x); + GateRef IsTaggedArray(GateRef x); GateRef TaggedIsAsyncGeneratorObject(GateRef x); GateRef TaggedIsJSGlobalObject(GateRef x); GateRef TaggedIsWeak(GateRef x); @@ -250,7 +251,7 @@ public: GateRef TaggedIsTransitionHandler(GateRef x); GateRef TaggedIsString(GateRef obj); GateRef TaggedIsStringIterator(GateRef obj); - GateRef TaggedIsShared(GateRef obj); + GateRef TaggedIsSharedObj(GateRef obj); GateRef BothAreString(GateRef x, GateRef y); GateRef TaggedIsStringOrSymbol(GateRef obj); GateRef TaggedIsSymbol(GateRef obj); @@ -276,6 +277,7 @@ public: GateRef TaggedPtrToTaggedDoublePtr(GateRef x); GateRef TaggedPtrToTaggedIntPtr(GateRef x); GateRef CastDoubleToInt64(GateRef x); + GateRef CastFloat32ToInt32(GateRef x); GateRef TaggedTrue(); GateRef TaggedFalse(); GateRef TaggedUndefined(); @@ -321,6 +323,7 @@ public: GateRef GetPropertiesArray(GateRef object); // SetProperties in js_object.h void SetPropertiesArray(VariableType type, GateRef glue, GateRef object, GateRef propsArray); + GateRef GetHash(GateRef object); void SetHash(GateRef glue, GateRef object, GateRef hash); GateRef GetLengthOfTaggedArray(GateRef array); GateRef GetLengthOfJSTypedArray(GateRef array); @@ -345,6 +348,7 @@ public: GateRef IsExtensible(GateRef object); GateRef TaggedObjectIsEcmaObject(GateRef obj); GateRef IsEcmaObject(GateRef obj); + GateRef IsDataView(GateRef obj); GateRef IsSymbol(GateRef obj); GateRef IsString(GateRef obj); GateRef IsLineString(GateRef obj); @@ -365,6 +369,7 @@ public: GateRef IsConstructor(GateRef object); GateRef IsBase(GateRef func); GateRef IsJsArray(GateRef obj); + GateRef IsJsSArray(GateRef obj); GateRef IsByteArray(GateRef obj); GateRef IsJsCOWArray(GateRef obj); GateRef IsMutantTaggedArray(GateRef elements); @@ -450,6 +455,9 @@ public: GateRef GetLayoutFromHClass(GateRef hClass); GateRef GetBitFieldFromHClass(GateRef hClass); GateRef GetLengthFromString(GateRef value); + GateRef CalcHashcodeForInt(GateRef value); + void CalcHashcodeForDouble(GateRef value, Variable *res, Label *exit); + void CalcHashcodeForObject(GateRef glue, GateRef value, Variable *res, Label *exit); GateRef GetHashcodeFromString(GateRef glue, GateRef value); inline GateRef IsIntegerString(GateRef string); inline void SetRawHashcode(GateRef glue, GateRef str, GateRef rawHashcode, GateRef isInteger); @@ -495,7 +503,7 @@ public: GateRef GetUnsharedConstpoolIndex(GateRef constpool); GateRef GetUnsharedConstpool(GateRef array, GateRef index); GateRef GetValueFromMutantTaggedArray(GateRef elements, GateRef index); - void CheckUpdateSharedType(bool isDicMode, Variable *result, GateRef glue, GateRef jsType, GateRef attr, + void CheckUpdateSharedType(bool isDicMode, Variable *result, GateRef glue, GateRef receiver, GateRef attr, GateRef value, Label *executeSetProp, Label *exit); void MatchFieldType(Variable *result, GateRef glue, GateRef fieldType, GateRef value, Label *executeSetProp, Label *exit); @@ -512,8 +520,8 @@ public: void SetValueToTaggedArray(VariableType valType, GateRef glue, GateRef array, GateRef index, GateRef val); void UpdateValueAndAttributes(GateRef glue, GateRef elements, GateRef index, GateRef value, GateRef attr); GateRef IsSpecialIndexedObj(GateRef jsType); - GateRef IsJSSharedType(GateRef jsType); GateRef IsSpecialContainer(GateRef jsType); + GateRef IsSharedArray(GateRef jsType); GateRef IsAccessorInternal(GateRef value); template GateRef GetAttributesFromDictionary(GateRef elements, GateRef entry); @@ -586,6 +594,7 @@ public: GateRef ChangeInt32ToFloat64(GateRef x); GateRef ChangeUInt32ToFloat64(GateRef x); GateRef ChangeFloat64ToInt32(GateRef x); + GateRef TruncDoubleToFloat32(GateRef x); GateRef DeletePropertyOrThrow(GateRef glue, GateRef obj, GateRef value); GateRef ToObject(GateRef glue, GateRef obj); GateRef DeleteProperty(GateRef glue, GateRef obj, GateRef value); @@ -777,6 +786,8 @@ public: GateRef GetIhcFromAOTLiteralInfo(GateRef info); GateRef IsAotWithCallField(GateRef method); GateRef IsFastCall(GateRef method); + GateRef IsJitCompiledCode(GateRef method); + void ClearJitCompiledCodeFlags(GateRef glue, GateRef method); GateRef JudgeAotAndFastCall(GateRef jsFunc, CircuitBuilder::JudgeMethodType type); GateRef JudgeAotAndFastCallWithMethod(GateRef method, CircuitBuilder::JudgeMethodType type); GateRef GetInternalString(GateRef glue, GateRef key); @@ -802,7 +813,7 @@ public: GateRef GetIterator(GateRef glue, GateRef obj, ProfileOperation callback); GateRef JSCallDispatch(GateRef glue, GateRef func, GateRef actualNumArgs, GateRef jumpSize, GateRef hotnessCounter, JSCallMode mode, std::initializer_list args, - ProfileOperation callback = ProfileOperation()); + ProfileOperation callback = ProfileOperation(), bool checkIsCallable = true); GateRef IsFastTypeArray(GateRef jsType); GateRef GetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder, GateRef key, GateRef jsType); GateRef SetTypeArrayPropertyByName(GateRef glue, GateRef receiver, GateRef holder, GateRef key, GateRef value, @@ -837,10 +848,18 @@ public: GateRef AppendSkipHole(GateRef glue, GateRef first, GateRef second, GateRef copyLength); GateRef IntToEcmaString(GateRef glue, GateRef number); GateRef NumberToString(GateRef glue, GateRef number); + inline GateRef GetViewedArrayBuffer(GateRef dataView); + inline GateRef GetByteOffset(GateRef dataView); + inline GateRef GetByteLength(GateRef dataView); + inline GateRef GetArrayBufferData(GateRef buffer); + GateRef IsDetachedBuffer(GateRef buffer); + inline GateRef IsMarkerCellValid(GateRef cell); + inline GateRef GetAccessorHasChanged(GateRef obj); + inline GateRef ComputeTaggedTypedArraySize(GateRef elementSize, GateRef length); + GateRef ChangeTaggedPointerToInt64(GateRef x); private: using BinaryOperation = std::function; - GateRef ChangeTaggedPointerToInt64(GateRef x); template GateRef FastAddSubAndMul(GateRef glue, GateRef left, GateRef right, ProfileOperation callback); GateRef FastIntDiv(GateRef left, GateRef right, Label *bailout, ProfileOperation callback); @@ -856,6 +875,7 @@ private: void InitializeArguments(); void CheckDetectorName(GateRef glue, GateRef key, Label *fallthrough, Label *slow); bool IsCallModeSupportPGO(JSCallMode mode); + GateRef CanDoubleRepresentInt(GateRef exp, GateRef expBits, GateRef fractionBits); CallSignature *callSignature_ {nullptr}; Environment *env_; diff --git a/ecmascript/compiler/tests/combined_pass_visitor_test.cpp b/ecmascript/compiler/tests/combined_pass_visitor_test.cpp index 22543e25f7d56bc3201779ba7c946d0a83979f4d..3c8707afe075be5748f11748d54af6406d39f4ab 100644 --- a/ecmascript/compiler/tests/combined_pass_visitor_test.cpp +++ b/ecmascript/compiler/tests/combined_pass_visitor_test.cpp @@ -67,7 +67,7 @@ HWTEST_F_L0(CombinedPassVisitorTests, TSLoweringTestFramework) Chunk chunk(&allocator); CombinedPassVisitor visitor(&circuit, false, "combined pass visitor test", &chunk); DeadCodeElimination deadCodeElimination(&circuit, &visitor, &chunk); - EarlyElimination earlyElimination(&circuit, &visitor, &chunk); + EarlyElimination earlyElimination(&circuit, &visitor, &chunk, true); visitor.AddPass(&deadCodeElimination); visitor.AddPass(&earlyElimination); visitor.VisitGraph(); diff --git a/ecmascript/compiler/tests/loop_optimization_test.cpp b/ecmascript/compiler/tests/loop_optimization_test.cpp index 708135e6b508b668018a03829f0ceb37977e4d3b..7f203f6416614547b5b4637b505468b181690290 100644 --- a/ecmascript/compiler/tests/loop_optimization_test.cpp +++ b/ecmascript/compiler/tests/loop_optimization_test.cpp @@ -56,6 +56,7 @@ using ecmascript::kungfu::TypedBinOp; using ecmascript::kungfu::PGOTypeRef; using ecmascript::kungfu::PGOSampleType; using ecmascript::kungfu::GraphLinearizer; +using ecmascript::kungfu::ParamType; HWTEST_F_L0(LoopOptimizationTest, LoopInt32TypedArraySumOptimizationTest) { // construct a circuit @@ -79,26 +80,20 @@ HWTEST_F_L0(LoopOptimizationTest, LoopInt32TypedArraySumOptimizationTest) builder.LoopBegin(&loopHead); auto loopBegin = builder.GetState(); EXPECT_TRUE(acc.IsLoopHead(loopBegin)); - auto loadLength = builder.LoadTypedArrayLength(array, GateType::AnyType()); + auto loadLength = builder.LoadTypedArrayLength(array, ParamType::AnyType()); acc.SetMachineType(loadLength, MachineType::I32); acc.SetGateType(loadLength, GateType::NJSValue()); - auto cmp = builder.TypedBinaryOp( - *index, loadLength, GateType::IntType(), GateType::IntType(), - GateType::NJSValue(), PGOTypeRef::NoneType()); + auto cmp = builder.TypedBinaryOp(*index, loadLength, ParamType::IntType()); acc.SetMachineType(cmp, MachineType::I1); builder.Branch(cmp, &loopBody, &loopExit); builder.Bind(&loopBody); auto loadElement = builder.LoadElement(array, *index); acc.SetMachineType(loadElement, MachineType::I32); acc.SetGateType(loadElement, GateType::NJSValue()); - auto sumAdd = builder.TypedBinaryOp( - *sum, loadElement, GateType::IntType(), GateType::IntType(), - GateType::NJSValue(), PGOTypeRef::NoneType()); + auto sumAdd = builder.TypedBinaryOp(*sum, loadElement, ParamType::IntType()); acc.SetMachineType(sumAdd, MachineType::I32); sum = sumAdd; - auto indexInc = builder.TypedBinaryOp( - *index, builder.Int32(1), GateType::IntType(), GateType::IntType(), - GateType::NJSValue(), PGOTypeRef::NoneType()); + auto indexInc = builder.TypedBinaryOp(*index, builder.Int32(1), ParamType::IntType()); acc.SetMachineType(indexInc, MachineType::I32); index = indexInc; builder.LoopEnd(&loopHead); @@ -121,7 +116,7 @@ HWTEST_F_L0(LoopOptimizationTest, LoopInt32TypedArraySumOptimizationTest) LoopPeeling(nullptr, &circuit, false, "LoopInt32TypedArraySumOptimizationTest", &chunk, &beforeOpt).Peel(); EXPECT_TRUE(Verifier::Run(&circuit)); CombinedPassVisitor visitor(&circuit, false, "LoopInt32TypedArraySumOptimizationTest", &chunk); - EarlyElimination earlyElimination(&circuit, &visitor, &chunk); + EarlyElimination earlyElimination(&circuit, &visitor, &chunk, true); visitor.AddPass(&earlyElimination); visitor.VisitGraph(); analysis.CollectLoopBody(&afterOpt); diff --git a/ecmascript/compiler/tests/meta_data_equal_test.cpp b/ecmascript/compiler/tests/meta_data_equal_test.cpp index b3eba6c42352b08b3c4d17ab602f34d79403d32d..0c3d2404521984ff44163e050fdbe58ea690c499 100644 --- a/ecmascript/compiler/tests/meta_data_equal_test.cpp +++ b/ecmascript/compiler/tests/meta_data_equal_test.cpp @@ -42,6 +42,8 @@ using ecmascript::kungfu::PGOTypeRef; using ecmascript::kungfu::PGOSampleType; using ecmascript::kungfu::TypedBinOp; using ecmascript::kungfu::TypedCallTargetCheckOp; +using ecmascript::kungfu::ParamType; +using ecmascript::kungfu::TypedCallTargetCheckAccessor; HWTEST_F_L0(MetaDataEqualTests, StringMetaDataEqualTest) { @@ -194,31 +196,37 @@ HWTEST_F_L0(MetaDataEqualTests, MCRMetaDataEqualTest) // TypedCallTargetCheckMetaData auto callGate3 = - circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64, - {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + circuit.NewGate(circuit.TypedCallTargetCheckOp( + TypedCallTargetCheckAccessor::ToValue(TypedCallTargetCheckOp::JSCALLTHIS_FAST)), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, + GateType::AnyType()); auto callGate4 = - circuit.NewGate(circuit.TypedCallTargetCheckOp(0, 0, TypedCallTargetCheckOp::JSCALLTHIS_FAST), MachineType::I64, - {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, GateType::AnyType()); + circuit.NewGate(circuit.TypedCallTargetCheckOp( + TypedCallTargetCheckAccessor::ToValue(TypedCallTargetCheckOp::JSCALLTHIS_FAST)), MachineType::I64, + {Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate()}, + GateType::AnyType()); EXPECT_TRUE(acc.MetaDataValueEqu(callGate3, callGate4)); EXPECT_TRUE(acc.MetaDataValueEqu(callGate4, callGate3)); // TypedBinaryMetaData - PGOSampleType type5 = PGOSampleType::CreateProfileType(0, 1); + uint64_t valueForType5 = ecmascript::kungfu::TypedBinaryAccessor::ToValue(ParamType::IntType(), + TypedBinOp::TYPED_ADD); auto callGate5 = circuit.NewGate( - circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOTypeRef(static_cast(&type5))), + circuit.TypedBinaryOp(valueForType5), MachineType::I64, { Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate() }, GateType::AnyType()); // TypedBinaryMetaData - PGOSampleType type6 = PGOSampleType::CreateProfileType(0, 1); + uint64_t valueForType6 = ecmascript::kungfu::TypedBinaryAccessor::ToValue(ParamType::IntType(), + TypedBinOp::TYPED_ADD); auto callGate6 = circuit.NewGate( - circuit.TypedBinaryOp(0, TypedBinOp::TYPED_ADD, PGOTypeRef(static_cast(&type6))), + circuit.TypedBinaryOp(valueForType6), MachineType::I64, { Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate(), Circuit::NullGate() }, GateType::AnyType()); - EXPECT_FALSE(acc.MetaDataValueEqu(callGate5, callGate6)); - EXPECT_FALSE(acc.MetaDataValueEqu(callGate6, callGate5)); + EXPECT_TRUE(acc.MetaDataValueEqu(callGate5, callGate6)); + EXPECT_TRUE(acc.MetaDataValueEqu(callGate6, callGate5)); } diff --git a/ecmascript/compiler/tests/typed_array_lowering_test.cpp b/ecmascript/compiler/tests/typed_array_lowering_test.cpp index fbfeba768c288045b4d86c97b36b2a8c615e56e9..28bf3edf904b7769ffdfd1a417fa1d02dbe9f6ac 100644 --- a/ecmascript/compiler/tests/typed_array_lowering_test.cpp +++ b/ecmascript/compiler/tests/typed_array_lowering_test.cpp @@ -37,6 +37,8 @@ using ecmascript::kungfu::Environment; using ecmascript::kungfu::CombinedPassVisitor; using ecmascript::kungfu::TypedHCRLowering; using ecmascript::OnHeapMode; +using ecmascript::kungfu::ParamType; + HWTEST_F_L0(TypedArrayLoweringTests, LoadTypedArrayLength) { // construct a circuit @@ -49,7 +51,7 @@ HWTEST_F_L0(TypedArrayLoweringTests, LoadTypedArrayLength) // after number speculative runner builder.SetEnvironment(&env); auto array = builder.Arguments(1); - auto loadLength = builder.LoadTypedArrayLength(array, GateType::AnyType()); + auto loadLength = builder.LoadTypedArrayLength(array, ParamType::AnyType()); acc.SetMachineType(loadLength, MachineType::I32); acc.SetGateType(loadLength, GateType::NJSValue()); auto convert = builder.ConvertInt32ToTaggedInt(loadLength); diff --git a/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp b/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp index 6ebdef806a2bf5fe97796adaa17924f6f0b49d6a..c631423c0d082ca771fddb6815122344a4b57c2e 100644 --- a/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp +++ b/ecmascript/compiler/trampoline/aarch64/optimized_call.cpp @@ -460,18 +460,50 @@ void OptimizedCall::JSCallInternal(ExtendedAssembler *assembler, Register jsfunc __ Ldr(Register(X5), MemoryOperand(sp, 0)); // get number args __ Sub(Register(X5), Register(X5), Immediate(NUM_MANDATORY_JSFUNC_ARGS)); if (!isNew) { + Label lCall0; + Label lCall1; + Label lCall2; + Label lCall3; Label lTailCall; Register fp(X29); + __ Cmp(Register(X5), Immediate(0)); + __ B(Condition::EQ, &lCall0); + __ Cmp(Register(X5), Immediate(1)); + __ B(Condition::EQ, &lCall1); + __ Cmp(Register(X5), Immediate(2)); // 2: 2 args + __ B(Condition::EQ, &lCall2); + __ Cmp(Register(X5), Immediate(3)); // 3: 3 args + __ B(Condition::EQ, &lCall3); + + __ Bind(&lCall0); + { + __ Mov(Register(X6), Immediate(JSTaggedValue::VALUE_UNDEFINED)); + __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); + __ B(&lTailCall); + } + + __ Bind(&lCall1); + { + __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE)); + __ Mov(Register(X7), Immediate(JSTaggedValue::VALUE_UNDEFINED)); // reset x7 + __ B(&lTailCall); + } + + __ Bind(&lCall2); + { + __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE)); + __ B(&lTailCall); + } + + __ Bind(&lCall3); __ Ldp(Register(X6), Register(X7), MemoryOperand(sp, QUADRUPLE_SLOT_SIZE)); // get arg0 arg1 - __ Cmp(Register(X5), Immediate(3)); // 3: callarg3 - __ B(Condition::NE, &lTailCall); PushAsmBridgeFrame(assembler); { - // push arg3 and call + // push arg2 and call TempRegister2Scope scope2(assembler); - Register arg3 = __ TempRegister2(); - __ Ldr(arg3, MemoryOperand(fp, OCTUPLE_SLOT_SIZE)); // get arg2 - __ Stp(arg3, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX)); + Register arg2 = __ TempRegister2(); + __ Ldr(arg2, MemoryOperand(fp, OCTUPLE_SLOT_SIZE)); + __ Stp(arg2, Register(X8), MemoryOperand(sp, -DOUBLE_SLOT_SIZE, PREINDEX)); __ Blr(builtinStub); __ Add(sp, sp, Immediate(DOUBLE_SLOT_SIZE)); } diff --git a/ecmascript/compiler/trampoline/x64/optimized_call.cpp b/ecmascript/compiler/trampoline/x64/optimized_call.cpp index 6363a9fe346450400010823336182dd84d29ced2..6e87e1c96e48426daea6ee8799758ee198c6ba34 100644 --- a/ecmascript/compiler/trampoline/x64/optimized_call.cpp +++ b/ecmascript/compiler/trampoline/x64/optimized_call.cpp @@ -460,24 +460,28 @@ void OptimizedCall::GenJSCall(ExtendedAssembler *assembler, bool isNew) __ Bind(&lCall0); { - __ PushAlignBytes(); + __ Pushq(JSTaggedValue::VALUE_UNDEFINED); + __ Pushq(JSTaggedValue::VALUE_UNDEFINED); + __ Pushq(JSTaggedValue::VALUE_UNDEFINED); __ Callq(r10); - __ Addq(DOUBLE_SLOT_SIZE, rsp); + __ Addq(QUADRUPLE_SLOT_SIZE, rsp); __ Jmp(&lexit); } __ Bind(&lCall1); { + __ Pushq(JSTaggedValue::VALUE_UNDEFINED); + __ Pushq(JSTaggedValue::VALUE_UNDEFINED); __ Movq(Operand(argV, 0), r11); // arg0 __ Pushq(r11); __ Callq(r10); - __ Addq(DOUBLE_SLOT_SIZE, rsp); + __ Addq(QUADRUPLE_SLOT_SIZE, rsp); __ Jmp(&lexit); } __ Bind(&lCall2); { - __ PushAlignBytes(); + __ Pushq(JSTaggedValue::VALUE_UNDEFINED); __ Movq(Operand(argV, FRAME_SLOT_SIZE), r11); // arg1 __ Pushq(r11); __ Movq(Operand(argV, 0), r11); // arg0 diff --git a/ecmascript/compiler/ts_hcr_opt_pass.cpp b/ecmascript/compiler/ts_hcr_opt_pass.cpp index d6766be065b822213ed2941597122758e19da360..fd0f553e1c7486043cc27f507d3e904a7513f451 100644 --- a/ecmascript/compiler/ts_hcr_opt_pass.cpp +++ b/ecmascript/compiler/ts_hcr_opt_pass.cpp @@ -79,8 +79,8 @@ GateRef TSHCROptPass::ConvertStringEqualToConst(GateRef left, GateRef right) auto leftMethodOffset = acc_.TryGetMethodOffset(left); auto rightMethodOffset = acc_.TryGetMethodOffset(right); - JSHandle leftStr(thread_, GetStringFromCP(leftMethodOffset, leftId)); - JSHandle rightStr(thread_, GetStringFromCP(rightMethodOffset, rightId)); + JSHandle leftStr(thread_, GetStringFromConstantPool(leftMethodOffset, leftId)); + JSHandle rightStr(thread_, GetStringFromConstantPool(rightMethodOffset, rightId)); bool isEqual = EcmaStringAccessor::StringsAreEqual(thread_->GetEcmaVM(), leftStr, rightStr); if (isEqual) { return builder_.Boolean(true); @@ -93,7 +93,7 @@ bool TSHCROptPass::IsSingleCharString(GateRef gate) if (acc_.IsConstString(gate)) { uint32_t strId = acc_.GetStringIdFromLdaStrGate(gate); auto methodOffset = acc_.TryGetMethodOffset(gate); - JSTaggedValue str = GetStringFromCP(methodOffset, strId); + JSTaggedValue str = GetStringFromConstantPool(methodOffset, strId); return EcmaStringAccessor(str).GetLength() == 1; } return acc_.IsSingleCharGate(gate); @@ -117,7 +117,7 @@ GateRef TSHCROptPass::ConvertConstSingleCharToInt32(GateRef gate) ASSERT(acc_.IsConstString(gate)); uint32_t strId = acc_.GetStringIdFromLdaStrGate(gate); auto methodOffset = acc_.TryGetMethodOffset(gate); - JSTaggedValue str = tsManager_->GetStringFromConstantPool(methodOffset, strId); + JSTaggedValue str = GetStringFromConstantPool(methodOffset, strId); ASSERT(EcmaStringAccessor(str).GetLength() == 1); uint16_t strToInt = EcmaStringAccessor(str).Get(0); return builder_.Int32(strToInt); @@ -131,8 +131,7 @@ GateRef TSHCROptPass::ConvertToSingleCharComparison(GateRef left, GateRef right) } else if (acc_.IsConstString(right)) { right = ConvertConstSingleCharToInt32(right); } - return builder_.TypedBinaryOp(left, right, GateType::IntType(), - GateType::IntType(), GateType::BooleanType(), - PGOTypeRef::NoneType()); + // change string binary operator to int binary operator + return builder_.TypedBinaryOp(left, right, ParamType::IntType()); } } // namespace panda::ecmascript::kungfu diff --git a/ecmascript/compiler/ts_hcr_opt_pass.h b/ecmascript/compiler/ts_hcr_opt_pass.h index 1784711d35d62d63d9d843cd5fe9eb3aba2ac331..e59e36d86491d063155ace84434eff3ec034d5b5 100644 --- a/ecmascript/compiler/ts_hcr_opt_pass.h +++ b/ecmascript/compiler/ts_hcr_opt_pass.h @@ -27,7 +27,7 @@ public: PassContext *ctx, bool enableLog, const std::string &name) : PassVisitor(circuit, chunk, visitor), builder_(circuit, ctx->GetCompilerConfig()), - tsManager_(ctx->GetTSManager()), + ptManager_(ctx->GetPTManager()), thread_(ctx->GetEcmaVM()->GetJSThread()), enableLog_(enableLog), methodName_(name) {} @@ -47,9 +47,9 @@ private: return methodName_; } - JSTaggedValue GetStringFromCP(uint32_t methodOffset, uint32_t cpIdx) const + JSTaggedValue GetStringFromConstantPool(uint32_t methodOffset, uint32_t cpIdx) const { - return tsManager_->GetStringFromConstantPool(methodOffset, cpIdx); + return ptManager_->GetStringFromConstantPool(methodOffset, cpIdx); } GateRef VisitTypedBinaryOp(GateRef gate); @@ -63,7 +63,7 @@ private: GateRef ConvertToSingleCharComparison(GateRef left, GateRef right); CircuitBuilder builder_; - TSManager *tsManager_ {nullptr}; + PGOTypeManager *ptManager_ {nullptr}; const JSThread *thread_ {nullptr}; bool enableLog_ {false}; std::string methodName_; diff --git a/ecmascript/compiler/ts_inline_lowering.cpp b/ecmascript/compiler/ts_inline_lowering.cpp index 515eeb61a2f8b5167795192cdde94e380f818c91..55a19f9babf17848b045c437e9f258ecbcad7558 100644 --- a/ecmascript/compiler/ts_inline_lowering.cpp +++ b/ecmascript/compiler/ts_inline_lowering.cpp @@ -12,17 +12,13 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +#include "ecmascript/compiler/ts_inline_lowering.h" + #include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/bytecodes.h" #include "ecmascript/compiler/compiler_log.h" #include "ecmascript/compiler/pass.h" -#include "ecmascript/compiler/ts_inline_lowering.h" #include "ecmascript/compiler/type_info_accessors.h" -#include "ecmascript/ts_types/ts_manager.h" -#include "ecmascript/ts_types/ts_type.h" -#include "libpandabase/utils/utf.h" -#include "libpandafile/class_data_accessor-inl.h" -#include "ecmascript/ts_types/ts_type_accessor.h" namespace panda::ecmascript::kungfu { void TSInlineLowering::RunTSInlineLowering() @@ -54,18 +50,10 @@ void TSInlineLowering::CollectInlineInfo() void TSInlineLowering::GetInlinedMethodId(GateRef gate) { ASSERT(acc_.GetOpCode(gate) == OpCode::FRAME_ARGS); - GateRef func = acc_.GetValueIn(gate, static_cast(FrameArgIdx::FUNC)); uint32_t methodOffset = 0; - auto funcType = acc_.GetGateType(func); - if (tsManager_->IsFunctionTypeKind(funcType)) { - GlobalTSTypeRef gt = funcType.GetGTRef(); - methodOffset = tsManager_->GetFuncMethodOffset(gt); - } - if (methodOffset == 0) { - auto pgoType = acc_.TryGetPGOType(gate); - if (pgoType.IsValidCallMethodId()) { - methodOffset = pgoType.GetCallMethodId(); - } + auto pgoType = acc_.TryGetPGOType(gate); + if (pgoType.IsValidCallMethodId()) { + methodOffset = pgoType.GetCallMethodId(); } acc_.UpdateMethodOffset(gate, methodOffset); } @@ -136,7 +124,7 @@ void TSInlineLowering::TryInline(InlineTypeInfoAccessor &info, ChunkQueueFilterMethod(inlinedMethod, methodPcInfo)) { + if (info.IsNormalCall() && ctx_->FilterMethod(inlinedMethod, methodPcInfo)) { return; } GateRef frameState = GetFrameState(info); @@ -213,7 +201,6 @@ void TSInlineLowering::InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPC InlineTypeInfoAccessor &info) { const JSPandaFile *jsPandaFile = ctx_->GetJSPandaFile(); - TSManager *tsManager = ctx_->GetTSManager(); CompilerLog *log = ctx_->GetCompilerLog(); CString recordName = MethodLiteral::GetRecordName(jsPandaFile, method->GetMethodId()); bool hasTyps = jsPandaFile->HasTSTypes(recordName); @@ -223,10 +210,8 @@ void TSInlineLowering::InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPC circuit_->InitRoot(); BytecodeCircuitBuilder builder(jsPandaFile, method, methodPCInfo, - tsManager, circuit_, - ctx_->GetByteCodes(), true, IsLogEnabled(), - enableTypeLowering_, fullName, recordName, ctx_->GetPfDecoder(), true, - passOptions_->EnableOptTrackField()); + circuit_, ctx_->GetByteCodes(), IsLogEnabled(), + enableTypeLowering_, fullName, recordName, ctx_->GetPfDecoder(), true); { if (enableTypeLowering_) { BuildFrameStateChain(info, builder); @@ -239,14 +224,14 @@ void TSInlineLowering::InlineCall(MethodInfo &methodInfo, MethodPcInfo &methodPC PassData data(&builder, circuit_, ctx_, log, fullName, &methodInfo, hasTyps, recordName, - method, method->GetMethodId().GetOffset(), nativeAreaAllocator_, ctx_->GetPfDecoder(), passOptions_); + method, method->GetMethodId().GetOffset(), nullptr, CVector{}, + nativeAreaAllocator_, ctx_->GetPfDecoder(), passOptions_); PassRunner pipeline(&data); pipeline.RunPass(); if (builder.EnableLoopOptimization()) { pipeline.RunPass(); pipeline.RunPass(); } - pipeline.RunPass(); pipeline.RunPass(); } @@ -546,7 +531,7 @@ void TSInlineLowering::InlineAccessorCheck(const InlineTypeInfoAccessor &info) ASSERT(ptManager->QueryHClass(receiverType.first, receiverType.second).IsJSHClass()); bool noNeedCheckHeapObject = acc_.IsHeapObjectFromElementsKind(receiver); - builder_.ObjectTypeCheck(acc_.GetGateType(gate), noNeedCheckHeapObject, receiver, builder_.Int32(receiverHCIndex), + builder_.ObjectTypeCheck(noNeedCheckHeapObject, receiver, builder_.Int32(receiverHCIndex), acc_.GetFrameState(gate)); auto currentLabel = env.GetCurrentLabel(); auto callState = currentLabel->GetControl(); @@ -715,16 +700,14 @@ void TSInlineLowering::SetInitCallTargetAndConstPoolId(InlineTypeInfoAccessor &i if (initCallTarget_ == Circuit::NullGate()) { GateRef frameArgs = GetFrameArgs(info); initCallTarget_ = acc_.GetValueIn(frameArgs, 0); - const JSPandaFile *pf = ctx_->GetJSPandaFile(); - initConstantPoolId_ = tsManager_->GetConstantPoolIDByMethodOffset(pf, initMethodOffset_); + initConstantPoolId_ = ptManager_->GetConstantPoolIDByMethodOffset(initMethodOffset_); } } -int32_t TSInlineLowering::GetAccessorConstpoolId(InlineTypeInfoAccessor &info) +uint32_t TSInlineLowering::GetAccessorConstpoolId(InlineTypeInfoAccessor &info) { ASSERT(info.IsCallAccessor()); uint32_t inlineMethodOffset = info.GetCallMethodId(); - const JSPandaFile *pf = ctx_->GetJSPandaFile(); - return tsManager_->GetConstantPoolIDByMethodOffset(pf, inlineMethodOffset); + return ptManager_->GetConstantPoolIDByMethodOffset(inlineMethodOffset); } } // namespace panda::ecmascript diff --git a/ecmascript/compiler/ts_inline_lowering.h b/ecmascript/compiler/ts_inline_lowering.h index 8532777d66134e99db57e7dae69100845f94f9d8..fe4a1bf0a547223107fcd8cd78b5c7a56f93b575 100644 --- a/ecmascript/compiler/ts_inline_lowering.h +++ b/ecmascript/compiler/ts_inline_lowering.h @@ -17,13 +17,10 @@ #define ECMASCRIPT_COMPILER_TS_INLINE_LOWERING_H #include "ecmascript/compiler/argument_accessor.h" -#include "ecmascript/compiler/builtins/builtins_call_signature.h" #include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/bytecode_info_collector.h" -#include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/pass_manager.h" #include "ecmascript/compiler/type_info_accessors.h" -#include "ecmascript/jspandafile/js_pandafile.h" namespace panda::ecmascript::kungfu { class CircuitRootScope { @@ -53,7 +50,7 @@ public: acc_(circuit), glue_(acc_.GetGlueFromArgList()), builder_(circuit, ctx->GetCompilerConfig()), - tsManager_(ctx->GetTSManager()), + ptManager_(ctx->GetPTManager()), ctx_(ctx), passOptions_(options), enableLog_(enableLog), @@ -138,14 +135,14 @@ private: GateRef GetCallSetterValue(GateRef gate); GateRef GetFrameState(InlineTypeInfoAccessor &info); void SetInitCallTargetAndConstPoolId(InlineTypeInfoAccessor &info); - int32_t GetAccessorConstpoolId(InlineTypeInfoAccessor &info); + uint32_t GetAccessorConstpoolId(InlineTypeInfoAccessor &info); Circuit *circuit_ {nullptr}; JSThread *thread_ {nullptr}; GateAccessor acc_; GateRef glue_; CircuitBuilder builder_; - TSManager *tsManager_ {nullptr}; + PGOTypeManager *ptManager_ {nullptr}; PassContext *ctx_ {nullptr}; PassOptions *passOptions_ {nullptr}; bool enableLog_ {false}; @@ -161,7 +158,7 @@ private: size_t lastCallId_ {0}; ArgumentAccessor argAcc_; uint32_t initMethodOffset_ {0}; - int32_t initConstantPoolId_ {0}; + uint32_t initConstantPoolId_ {0}; GateRef initCallTarget_ {Circuit::NullGate()}; }; } // panda::ecmascript::kungfu diff --git a/ecmascript/compiler/type.h b/ecmascript/compiler/type.h index 071022ce659c2eb8990e843117493c20ba62c0f0..b3850da71f9cb7b0b1a33d7fdb29d553cf4499d5 100644 --- a/ecmascript/compiler/type.h +++ b/ecmascript/compiler/type.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_COMPILER_TYPE_H #define ECMASCRIPT_COMPILER_TYPE_H +#include "ecmascript/js_hclass.h" #include "ecmascript/ts_types/global_ts_type_ref.h" #define VALUE_TYPE_LIST(V) \ @@ -41,15 +42,102 @@ enum class ValueType : uint8_t { }; namespace panda::ecmascript::kungfu { +#define PRIMITIVE_TYPE_LIST(V) \ + V(ANY, AnyType) \ + V(NUMBER, NumberType) \ + V(BOOLEAN, BooleanType) \ + V(VOID_TYPE, VoidType) \ + V(STRING, StringType) \ + V(SYMBOL, SymbolType) \ + V(NULL_TYPE, NullType) \ + V(UNDEFINED, UndefinedType) \ + V(INT, IntType) \ + V(BIG_INT, BigIntType) \ + V(DOUBLE, DoubleType) \ + +// ParamType: Prediction type from PGO, bound to MetaData in GATE +#define PARAM_TYPE_LIST(V) \ + V(INT_OVERFLOW, IntOverflowType) \ + +class ParamType { +public: + explicit ParamType(uint32_t type = 0) : type_(type) {} + + explicit ParamType(JSType jsType) + { + type_ = BUILTIN_TYPE | static_cast(jsType); + } + +#define DEFINE_TYPE_CONSTRUCTOR(type, name) \ + static ParamType name() { return ParamType(static_cast(type)); } + + PRIMITIVE_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR) + PARAM_TYPE_LIST(DEFINE_TYPE_CONSTRUCTOR) +#undef DEFINE_TYPE_CONSTRUCTOR + +#define DEFINE_JUDGE_METHOD(type, name) \ + bool Is##name() const { return type_ == static_cast(type); } + + PRIMITIVE_TYPE_LIST(DEFINE_JUDGE_METHOD) + PARAM_TYPE_LIST(DEFINE_JUDGE_METHOD) +#undef DEFINE_JUDGE_METHOD + + uint32_t Value() const + { + return type_; + } + + bool HasNumberType() const + { + return IsNumberType() || IsIntType() || IsIntOverflowType() || IsDoubleType(); + } + + bool IsBuiltinType() const + { + return type_ & BUILTIN_TYPE; + } + + JSType GetBuiltinType() const + { + return static_cast(type_ & ~BUILTIN_TYPE); + } + + bool operator ==(const ParamType &other) const + { + return type_ == other.type_; + } + + bool operator !=(const ParamType &other) const + { + return !(*this == other); + } + +private: + enum : uint8_t { +#define DECLARE_TYPE(type, name) type, + PRIMITIVE_TYPE_LIST(DECLARE_TYPE) + PARAM_TYPE_LIST(DECLARE_TYPE) +#undef DECLARE_TYPE + }; + + static constexpr uint32_t BUILTIN_TYPE = (1 << 31); // 31 : the 31-th bit is set implies builtin type + + uint32_t type_ {0}; +}; +#undef PARAM_TYPE_LIST + +// GateType: Trusted type, directly bound to Gate class GateType { public: - constexpr explicit GateType(uint32_t type = 0) : type_(type) + constexpr explicit GateType(uint32_t type = 0) { + type_ |= type; } - explicit GateType(GlobalTSTypeRef gt) : type_(0) + explicit GateType([[maybe_unused]]GlobalTSTypeRef gt) { - type_ |= gt.GetType(); + // linxiang shoult remove in part3 + type_ = EMPTY; } ~GateType() = default; @@ -86,142 +174,113 @@ public: static GateType AnyType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::ANY)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::ANY)); } static GateType NumberType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::NUMBER)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::NUMBER)); } static GateType DoubleType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::DOUBLE)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::DOUBLE)); } static GateType BooleanType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::BOOLEAN)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::BOOLEAN)); } static GateType VoidType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::VOID_TYPE)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::VOID_TYPE)); } static GateType StringType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::STRING)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::STRING)); } static GateType SymbolType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::SYMBOL)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::SYMBOL)); } static GateType NullType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::NULL_TYPE)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::NULL_TYPE)); } static GateType UndefinedType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::UNDEFINED)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::UNDEFINED)); } static GateType IntType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::INT)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::INT)); } static GateType BigIntType() { - GlobalTSTypeRef r(0, static_cast(TSPrimitiveType::BIG_INT)); - return GateType(r); + return GateType(static_cast(TSPrimitiveType::BIG_INT)); } bool IsAnyType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::ANY)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::ANY); } bool IsNumberType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && ((l == static_cast(TSPrimitiveType::NUMBER)) || - (l == static_cast(TSPrimitiveType::INT)) || - (l == static_cast(TSPrimitiveType::DOUBLE))); + uint32_t type = GetType(); + return ((type == static_cast(TSPrimitiveType::NUMBER)) || + (type == static_cast(TSPrimitiveType::INT)) || + (type == static_cast(TSPrimitiveType::DOUBLE))); } bool IsIntType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::INT)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::INT); } bool IsDoubleType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::DOUBLE)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::DOUBLE); } bool IsStringType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::STRING)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::STRING); } bool IsNullType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::NULL_TYPE)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::NULL_TYPE); } bool IsUndefinedType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::UNDEFINED)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::UNDEFINED); } bool IsBooleanType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::BOOLEAN)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::BOOLEAN); } bool IsBigIntType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::BIG_INT)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::BIG_INT); } bool IsNJSValueType() const @@ -236,10 +295,8 @@ public: bool IsSymbolType() const { - GlobalTSTypeRef r = GetGTRef(); - uint32_t m = r.GetModuleId(); - uint32_t l = r.GetLocalId(); - return (m == 0) && (l == static_cast(TSPrimitiveType::SYMBOL)); + uint32_t type = GetType(); + return type == static_cast(TSPrimitiveType::SYMBOL); } // In addition to normal number types, null, undefined, boolean types will be converted to numeric types when doing @@ -289,10 +346,16 @@ public: return type_ >= other.type_; } + uint32_t GetType() const + { + return type_ & (~MIR_TYPE_MASK); + } + GlobalTSTypeRef GetGTRef() const { - uint32_t r = type_ & (~MIR_TYPE_MASK); - return GlobalTSTypeRef(r); + // linxiang shoult remove in part3 + GlobalTSTypeRef empty; + return empty; } private: diff --git a/ecmascript/compiler/type_inference/global_type_infer.cpp b/ecmascript/compiler/type_inference/global_type_infer.cpp deleted file mode 100644 index 3ba402877be5749b59b0ed308a8cfe3ba8dee18c..0000000000000000000000000000000000000000 --- a/ecmascript/compiler/type_inference/global_type_infer.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -#include "ecmascript/compiler/type_inference/global_type_infer.h" - -namespace panda::ecmascript::kungfu { -GlobalTypeInfer::GlobalTypeInfer(PassContext *ctx, const uint32_t methodOffset, const CString &recordName, - PGOProfilerDecoder *decoder, bool enableOptTrackField, bool enableLog, bool hasType) - : ctx_(ctx), jsPandaFile_(ctx_->GetJSPandaFile()), bcInfo_(ctx->GetBytecodeInfo()), methodOffset_(methodOffset), - recordName_(recordName), decoder_(decoder), enableOptTrackField_(enableOptTrackField), enableLog_(enableLog), - hasType_(hasType), enableGlobalTypeInfer_( - ctx_->GetTSManager()->GetEcmaVM()->GetJSOptions().IsEnableGlobalTypeInfer()) -{ - CollectNamespaceMethods(methodOffset); - for (const auto namespaceMethod : namespaceTypes_) { - NewTypeInfer(namespaceMethod); - } -} - -GlobalTypeInfer::~GlobalTypeInfer() -{ - for (auto it : typeInfers_) { - if (it.second != nullptr) { - delete it.second; - } - } - typeInfers_.clear(); - - for (auto it : builders_) { - if (it != nullptr) { - delete it; - } - } - builders_.clear(); - - for (auto it: circuits_) { - if (it != nullptr) { - delete it; - } - } - circuits_.clear(); -} - -void GlobalTypeInfer::NewTypeInfer(const uint32_t methodOffset) -{ - auto module = ctx_->GetAOTModule(); - auto &methodList = bcInfo_.GetMethodList(); - MethodInfo &methodInfo = methodList.at(methodOffset); - const auto &methodPcInfos = bcInfo_.GetMethodPcInfos(); - auto &methodPcInfo = methodPcInfos[methodInfo.GetMethodPcInfoIndex()]; - auto methodLiteral = jsPandaFile_->FindMethodLiteral(methodOffset); - std::string fullName = module->GetFuncName(methodLiteral, jsPandaFile_); - - Circuit *circuit = new Circuit(ctx_->GetNativeAreaAllocator(), module->GetDebugInfo(), - fullName.c_str(), ctx_->GetCompilerConfig()->Is64Bit(), - FrameType::OPTIMIZED_JS_FUNCTION_FRAME); - circuits_.emplace_back(circuit); - - BytecodeCircuitBuilder *builder = - new BytecodeCircuitBuilder(jsPandaFile_, methodLiteral, methodPcInfo, ctx_->GetTSManager(), circuit, - ctx_->GetByteCodes(), jsPandaFile_->HasTSTypes(recordName_), enableLog_, true, - fullName, recordName_, decoder_, false, enableOptTrackField_); - builder->BytecodeToCircuit(); - builders_.emplace_back(builder); - - MethodTypeInfer *typeInfer = new MethodTypeInfer(builder, circuit, ctx_, methodInfo.GetMethodInfoIndex(), - enableLog_, fullName, recordName_, &methodInfo, - methodLiteral, enableGlobalTypeInfer_, hasType_); - typeInfers_.insert(std::make_pair(methodOffset, typeInfer)); -} - -void GlobalTypeInfer::CollectNamespaceMethod(const uint32_t methodOffset) -{ - auto &methodList = bcInfo_.GetMethodList(); - MethodInfo &methodInfo = methodList.at(methodOffset); - auto &innerMethods = methodInfo.GetInnerMethods(); - uint32_t length = innerMethods.size(); - for (uint32_t i = 0; i < length; i++) { - MethodInfo &innerMethodInfo = methodList.at(innerMethods[i]); - if (innerMethodInfo.IsNamespace()) { - namespaceTypes_.insert(innerMethods[i]); - CollectNamespaceMethod(innerMethods[i]); - } - } -} - -void GlobalTypeInfer::CollectNamespaceMethods(const uint32_t methodOffset) -{ - if (!enableGlobalTypeInfer_) { - namespaceTypes_.clear(); - return; - } - CollectNamespaceMethod(methodOffset); - if (namespaceTypes_.size() > MAX_GLOBAL_INFER_ALLOWED) { - namespaceTypes_.clear(); - } -} - -void GlobalTypeInfer::ProcessTypeInference(BytecodeCircuitBuilder *builder, Circuit *circuit) -{ - auto &methodList = bcInfo_.GetMethodList(); - MethodInfo &methodInfo = methodList.at(methodOffset_); - MethodTypeInfer typeInfer(builder, circuit, ctx_, methodInfo.GetMethodInfoIndex(), enableLog_, - builder->GetMethodName(), recordName_, &methodInfo, - jsPandaFile_->FindMethodLiteral(methodOffset_), - enableGlobalTypeInfer_, hasType_); - - TSManager *tsManager = ctx_->GetTSManager(); - std::stack typeInferStack; - typeInferStack.push(&typeInfer); - // In TS, a namespace declaration is only allowed at the top level of a namespace or module and - // it can be thought of as a formalization of the IIFE pattern. Based on the function definition - // domain chain, there will be no loops containing namespace declarations. - // This shows that the following stack will definitely stop. - while (!typeInferStack.empty()) { - MethodTypeInfer *infer = typeInferStack.top(); - if (infer == nullptr) { - typeInferStack.pop(); - continue; - } - uint32_t methodId = 0; - GateType type; - std::tie(type, methodId) = infer->TraverseInfer(); - if (IsLegalMethod(methodId)) { - MethodTypeInfer *nextInfer = GetTypeInfer(methodId); - if (nextInfer != nullptr) { - nextInfer->SetNamespaceArgType(type); - tsManager->StoreNamespaceType(methodId, type); - typeInferStack.push(nextInfer); - continue; - } - } - typeInferStack.pop(); - } - - typeInfer.CheckAndPrint(); - RunTypeCheck(); -} - -void GlobalTypeInfer::RunTypeCheck() -{ - for (auto it : typeInfers_) { - if (it.second != nullptr) { - it.second->CheckAndPrint(); - } - } -} -} // namespace panda::ecmascript diff --git a/ecmascript/compiler/type_inference/global_type_infer.h b/ecmascript/compiler/type_inference/global_type_infer.h deleted file mode 100644 index 641ae3e6eb575e019189faf490a1f7aebb1e6fb9..0000000000000000000000000000000000000000 --- a/ecmascript/compiler/type_inference/global_type_infer.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2023 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. - */ - -#ifndef ECMASCRIPT_COMPILER_TYPE_INFERENCE_GLOBAL_TYPE_INFER_H -#define ECMASCRIPT_COMPILER_TYPE_INFERENCE_GLOBAL_TYPE_INFER_H - -#include "ecmascript/compiler/type_inference/method_type_infer.h" - -namespace panda::ecmascript::kungfu { -class GlobalTypeInfer { -public: - GlobalTypeInfer(PassContext *ctx, const uint32_t methodOffset, const CString &recordName, - PGOProfilerDecoder *decoder, bool enableOptTrackField, bool enableLog, bool hasType); - ~GlobalTypeInfer(); - - void ProcessTypeInference(BytecodeCircuitBuilder *builder, Circuit *circuit); - -private: - static constexpr size_t MAX_GLOBAL_INFER_ALLOWED = 2; - - inline MethodTypeInfer *GetTypeInfer(const uint32_t methodOffset) const - { - auto it = typeInfers_.find(methodOffset); - if (it != typeInfers_.end()) { - return it->second; - } - return nullptr; - } - - inline bool IsLegalMethod(const uint32_t methodOffset) const - { - return (methodOffset != 0); - } - - void NewTypeInfer(const uint32_t methodOffset); - void CollectNamespaceMethod(const uint32_t methodOffset); - void CollectNamespaceMethods(const uint32_t methodOffset); - void RunTypeCheck(); - - PassContext *ctx_ {nullptr}; - const JSPandaFile *jsPandaFile_ {nullptr}; - BCInfo &bcInfo_; - uint32_t methodOffset_ {0}; - const CString &recordName_; - PGOProfilerDecoder *decoder_ {nullptr}; - bool enableOptTrackField_ {false}; - bool enableLog_ {false}; - bool hasType_ {false}; - bool enableGlobalTypeInfer_ {false}; - std::set namespaceTypes_ {}; - std::vector builders_ {}; - std::vector circuits_ {}; - std::map typeInfers_ {}; -}; -} // namespace panda::ecmascript::kungfu -#endif // ECMASCRIPT_COMPILER_TYPE_INFERENCE_GLOBAL_TYPE_INFER_H diff --git a/ecmascript/compiler/type_inference/method_type_infer.cpp b/ecmascript/compiler/type_inference/method_type_infer.cpp deleted file mode 100644 index df664ca401e43940eda8fd32ea7db08798de8008..0000000000000000000000000000000000000000 --- a/ecmascript/compiler/type_inference/method_type_infer.cpp +++ /dev/null @@ -1,1621 +0,0 @@ -/* - * Copyright (c) 2022 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. - */ - -#include "ecmascript/compiler/type_inference/method_type_infer.h" -#include "ecmascript/jspandafile/js_pandafile_manager.h" -#include "ecmascript/ts_types/ts_type_accessor.h" -#include "ecmascript/ts_types/ts_type_parser.h" - -namespace panda::ecmascript::kungfu { -MethodTypeInfer::MethodTypeInfer(BytecodeCircuitBuilder *builder, Circuit *circuit, PassContext *ctx, size_t methodId, - bool enableLog, const std::string &name, const CString &recordName, - MethodInfo *methodInfo, const MethodLiteral *methodLiteral, - bool enableGlobalTypeInfer, bool hasType) - : builder_(builder), circuit_(circuit), gateAccessor_(circuit), tsManager_(ctx->GetTSManager()), ctx_(ctx), - lexEnvManager_(ctx->GetLexEnvManager()), methodId_(methodId), enableLog_(enableLog), methodName_(name), - recordName_(recordName), methodInfo_(methodInfo), methodLiteral_(methodLiteral), - inQueue_(circuit_->GetGateCount(), true), enableGlobalTypeInfer_(enableGlobalTypeInfer), hasType_(hasType) -{ - if (enableGlobalTypeInfer_ && methodInfo->IsNamespace()) { - uint32_t methodOffset = methodLiteral_->GetMethodId().GetOffset(); - if (tsManager_->HasInferredNamespaceType(methodOffset)) { - SetNamespaceArgType(tsManager_->GetNamespaceObjType(methodOffset)); - } - } - - std::vector gateList; - circuit_->GetAllGates(gateList); - for (auto gate : gateList) { - if (gateAccessor_.GetOpCode(gate) == OpCode::FRAME_ARGS) { - continue; - } - pendingQueue_.push(gate); - } - // init jsgateToBytecode - BytecodeIterator iterator(builder_, 0, builder_->GetLastBcIndex()); - iterator.GotoStart(); - while (!iterator.Done()) { - auto index = iterator.Index(); - auto gates = builder_->GetGatesByBcIndex(index); - for (auto gate : gates) { - jsgateToBytecode_[gate] = index; - } - ++iterator; - } -} - -void MethodTypeInfer::CheckAndPrint() -{ - VerifyTypePercent(); - - if (tsManager_->AssertTypes()) { - Verify(); - } - - if (IsLogEnabled()) { - PrintTypeAnnotation(); - PrintByteCodesWithTypes(); - PrintCircuitWithTypes(); - } -} - -void MethodTypeInfer::Enqueue(GateRef gate) -{ - auto gateId = gateAccessor_.GetId(gate); - if (!inQueue_[gateId]) { - inQueue_[gateId] = true; - pendingQueue_.push(gate); - } -} - -std::pair MethodTypeInfer::TraverseInfer() -{ - // main type infer for all gates - while (!pendingQueue_.empty()) { - auto curGate = pendingQueue_.front(); - inQueue_[gateAccessor_.GetId(curGate)] = false; - pendingQueue_.pop(); - auto uses = gateAccessor_.ConstUses(curGate); - for (auto useIt = uses.begin(); useIt != uses.end(); useIt++) { - if (Infer(*useIt)) { - Enqueue(*useIt); - } - if (enableGlobalTypeInfer_ && IsNamespace(*useIt)) { - return SetAndReturnNamespaceObjType(*useIt); - } - } - if (pendingQueue_.empty() && needUpdateForLoopPhi_) { - // only for loop begin phi - UpdateQueueForLoopPhi(); - needUpdateForLoopPhi_ = false; - } - } - return std::make_pair(GateType::AnyType(), 0); // 0: defaule value -} - -void MethodTypeInfer::UpdateQueueForLoopPhi() -{ - for (auto it = loopPhiState_.begin(); it != loopPhiState_.end(); it++) { - auto curGate = it->first; - auto loopType = gateAccessor_.GetGateType(curGate); - auto loopBackGate = gateAccessor_.GetValueIn(curGate, 1); - auto loopBackType = gateAccessor_.GetGateType(loopBackGate); - // if loopBack Gate is finally AnyType, loop-begin phi gate should be changed to any - if (!loopType.IsAnyType() && loopBackType.IsAnyType()) { - gateAccessor_.SetGateType(curGate, GateType::AnyType()); - loopPhiState_[curGate] = InferState::ANY_INFERED; - pendingQueue_.push(curGate); - inQueue_[gateAccessor_.GetId(curGate)] = true; - } - // if loopBack Gate is finally not same number Type, loop-begin phi gate should be promoted - if (loopType.IsNumberType() && loopBackType.IsNumberType() && loopType != loopBackType) { - gateAccessor_.SetGateType(curGate, GateType::NumberType()); - loopPhiState_[curGate] = InferState::NUMBER_INFERED; - pendingQueue_.push(curGate); - inQueue_[gateAccessor_.GetId(curGate)] = true; - } - } -} - -bool MethodTypeInfer::UpdateType(GateRef gate, const GateType type, bool savePreType) -{ - GateType preType = gateAccessor_.GetGateType(gate); - needInferGates_.insert(gate); - // When the type after type inference is any and you want to save previous type, it wolud not update. - if (savePreType && type.IsAnyType()) { - return false; - } - - if (type != preType) { - gateAccessor_.SetGateType(gate, HandleTypeCompatibility(preType, type)); - return true; - } - return false; -} - -bool MethodTypeInfer::UpdateType(GateRef gate, const GlobalTSTypeRef &typeRef, bool savePreType) -{ - auto type = GateType(typeRef); - return UpdateType(gate, type, savePreType); -} - -GateType MethodTypeInfer::HandleTypeCompatibility(const GateType preType, const GateType type) const -{ - if (tsManager_->IsArrayTypeKind(preType) && tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, type)) { - return preType; - } - return type; -} - -bool MethodTypeInfer::IsNewLexEnv(EcmaOpcode opcode) const -{ - switch (opcode) { - case EcmaOpcode::NEWLEXENV_IMM8: - case EcmaOpcode::NEWLEXENVWITHNAME_IMM8_ID16: - case EcmaOpcode::WIDE_NEWLEXENV_PREF_IMM16: - case EcmaOpcode::WIDE_NEWLEXENVWITHNAME_PREF_IMM16_ID16: - return true; - default: - return false; - } -} - -bool MethodTypeInfer::ShouldInfer(const GateRef gate) const -{ - auto opcode = gateAccessor_.GetOpCode(gate); - // handle phi gates - if ((opcode == OpCode::VALUE_SELECTOR) || - (opcode == OpCode::LOOP_EXIT_VALUE)) { - return true; - } - /* Handle constant gates (like ldnull and ldtrue), return gates and gates generated by ecma.* bytecodes (not - * including jump and newlexenv). Jump instructions are skipped because they have no intrinsic type information. - * And newlexenv instructions are used to create runtime lexical env objects which have no TS types associated. As - * for the type inference on lexical variables, their type information is recorded in objects of class - * panda::ecmascript::kungfu::LexEnv which are created during the building of IR. So in the type inference, - * newlexenv is ignored. - */ - if (opcode != OpCode::CONSTANT && - opcode != OpCode::RETURN && opcode != OpCode::JS_BYTECODE) { - return false; - } - if (jsgateToBytecode_.find(gate) == jsgateToBytecode_.end()) { - return false; - } - auto &bytecodeInfo = GetByteCodeInfo(gate); - return !bytecodeInfo.IsJump() && !IsNewLexEnv(bytecodeInfo.GetOpcode()); -} - -bool MethodTypeInfer::Infer(GateRef gate) -{ - if (!ShouldInfer(gate)) { - return false; - } - if (gateAccessor_.GetOpCode(gate) == OpCode::LOOP_EXIT_VALUE) { - return UpdateType(gate, gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate))); - } - if (gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR) { - return InferPhiGate(gate); - } - // infer ecma.* bytecode gates - auto &bytecodeInfo = GetByteCodeInfo(gate); - switch (bytecodeInfo.GetOpcode()) { - case EcmaOpcode::LDNAN: - case EcmaOpcode::LDINFINITY: - case EcmaOpcode::TONUMBER_IMM8: - case EcmaOpcode::NEG_IMM8: - case EcmaOpcode::EXP_IMM8_V8: - case EcmaOpcode::STARRAYSPREAD_V8_V8: - return SetNumberType(gate); - case EcmaOpcode::SHL2_IMM8_V8: - case EcmaOpcode::ASHR2_IMM8_V8: - case EcmaOpcode::SHR2_IMM8_V8: - case EcmaOpcode::NOT_IMM8: - case EcmaOpcode::AND2_IMM8_V8: - case EcmaOpcode::OR2_IMM8_V8: - case EcmaOpcode::XOR2_IMM8_V8: - return SetIntType(gate); - case EcmaOpcode::LDBIGINT_ID16: - return SetBigIntType(gate); - case EcmaOpcode::LDTRUE: - case EcmaOpcode::LDFALSE: - case EcmaOpcode::EQ_IMM8_V8: - case EcmaOpcode::NOTEQ_IMM8_V8: - case EcmaOpcode::LESS_IMM8_V8: - case EcmaOpcode::LESSEQ_IMM8_V8: - case EcmaOpcode::GREATER_IMM8_V8: - case EcmaOpcode::GREATEREQ_IMM8_V8: - case EcmaOpcode::ISIN_IMM8_V8: - case EcmaOpcode::INSTANCEOF_IMM8_V8: - case EcmaOpcode::STRICTNOTEQ_IMM8_V8: - case EcmaOpcode::STRICTEQ_IMM8_V8: - case EcmaOpcode::ISTRUE: - case EcmaOpcode::ISFALSE: - case EcmaOpcode::SETOBJECTWITHPROTO_IMM8_V8: - case EcmaOpcode::SETOBJECTWITHPROTO_IMM16_V8: - case EcmaOpcode::DELOBJPROP_V8: - return SetBooleanType(gate); - case EcmaOpcode::LDUNDEFINED: - return InferLdUndefined(gate); - case EcmaOpcode::LDNULL: - return InferLdNull(gate); - case EcmaOpcode::LDAI_IMM32: - return InferLdai(gate); - case EcmaOpcode::FLDAI_IMM64: - return InferFLdai(gate); - case EcmaOpcode::LDSYMBOL: - return InferLdSymbol(gate); - case EcmaOpcode::THROW_PREF_NONE: - return InferThrow(gate); - case EcmaOpcode::TYPEOF_IMM8: - case EcmaOpcode::TYPEOF_IMM16: - return InferTypeOf(gate); - case EcmaOpcode::ADD2_IMM8_V8: - return InferAdd2(gate); - case EcmaOpcode::SUB2_IMM8_V8: - return InferSub2(gate); - case EcmaOpcode::MUL2_IMM8_V8: - return InferMul2(gate); - case EcmaOpcode::MOD2_IMM8_V8: - return InferMod2(gate); - case EcmaOpcode::DIV2_IMM8_V8: - return InferDiv2(gate); - case EcmaOpcode::INC_IMM8: - case EcmaOpcode::DEC_IMM8: - return InferIncDec(gate); - case EcmaOpcode::LDOBJBYINDEX_IMM8_IMM16: - case EcmaOpcode::LDOBJBYINDEX_IMM16_IMM16: - case EcmaOpcode::WIDE_LDOBJBYINDEX_PREF_IMM32: - return InferLdObjByIndex(gate); - case EcmaOpcode::STGLOBALVAR_IMM16_ID16: - case EcmaOpcode::TRYSTGLOBALBYNAME_IMM8_ID16: - case EcmaOpcode::TRYSTGLOBALBYNAME_IMM16_ID16: - return SetStGlobalBcType(gate, true); - case EcmaOpcode::STTOGLOBALRECORD_IMM16_ID16: - case EcmaOpcode::STCONSTTOGLOBALRECORD_IMM16_ID16: - return SetStGlobalBcType(gate, false); - case EcmaOpcode::LDGLOBALVAR_IMM16_ID16: - return InferLdGlobalVar(gate); - case EcmaOpcode::RETURNUNDEFINED: - return InferReturnUndefined(gate); - case EcmaOpcode::RETURN: - return InferReturn(gate); - case EcmaOpcode::LDOBJBYNAME_IMM8_ID16: - case EcmaOpcode::LDOBJBYNAME_IMM16_ID16: - return InferLdObjByName(gate); - case EcmaOpcode::LDA_STR_ID16: - return InferLdStr(gate); - case EcmaOpcode::TONUMERIC_IMM8: - return InferToNumberic(gate); - case EcmaOpcode::CALLARG0_IMM8: - case EcmaOpcode::CALLARG1_IMM8_V8: - case EcmaOpcode::CALLARGS2_IMM8_V8_V8: - case EcmaOpcode::CALLARGS3_IMM8_V8_V8_V8: - case EcmaOpcode::CALLRANGE_IMM8_IMM8_V8: - case EcmaOpcode::WIDE_CALLRANGE_PREF_IMM16_V8: - case EcmaOpcode::APPLY_IMM8_V8_V8: - return InferCallFunction(gate); - case EcmaOpcode::CALLTHIS0_IMM8_V8: - case EcmaOpcode::CALLTHIS1_IMM8_V8_V8: - case EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8: - case EcmaOpcode::CALLTHIS3_IMM8_V8_V8_V8_V8: - case EcmaOpcode::CALLTHISRANGE_IMM8_IMM8_V8: - case EcmaOpcode::WIDE_CALLTHISRANGE_PREF_IMM16_V8: - case EcmaOpcode::CALLRUNTIME_CALLINIT_PREF_IMM8_V8: - return InferCallMethod(gate); - case EcmaOpcode::LDOBJBYVALUE_IMM8_V8: - case EcmaOpcode::LDOBJBYVALUE_IMM16_V8: - return InferLdObjByValue(gate); - case EcmaOpcode::GETNEXTPROPNAME_V8: - return InferGetNextPropName(gate); - case EcmaOpcode::DEFINEGETTERSETTERBYVALUE_V8_V8_V8_V8: - return InferDefineGetterSetterByValue(gate); - case EcmaOpcode::NEWOBJRANGE_IMM8_IMM8_V8: - case EcmaOpcode::NEWOBJRANGE_IMM16_IMM8_V8: - case EcmaOpcode::WIDE_NEWOBJRANGE_PREF_IMM16_V8: - case EcmaOpcode::NEWOBJAPPLY_IMM8_V8: - case EcmaOpcode::NEWOBJAPPLY_IMM16_V8: - return InferNewObject(gate); - case EcmaOpcode::SUPERCALLTHISRANGE_IMM8_IMM8_V8: - case EcmaOpcode::WIDE_SUPERCALLTHISRANGE_PREF_IMM16_V8: - case EcmaOpcode::SUPERCALLARROWRANGE_IMM8_IMM8_V8: - case EcmaOpcode::WIDE_SUPERCALLARROWRANGE_PREF_IMM16_V8: - case EcmaOpcode::SUPERCALLSPREAD_IMM8_V8: - return InferSuperCall(gate); - case EcmaOpcode::LDSUPERBYNAME_IMM8_ID16: - case EcmaOpcode::LDSUPERBYNAME_IMM16_ID16: - return InferSuperPropertyByName(gate); - case EcmaOpcode::LDSUPERBYVALUE_IMM8_V8: - case EcmaOpcode::LDSUPERBYVALUE_IMM16_V8: - return InferSuperPropertyByValue(gate); - case EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16: - case EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16: - return InferTryLdGlobalByName(gate); - case EcmaOpcode::LDLEXVAR_IMM4_IMM4: - case EcmaOpcode::LDLEXVAR_IMM8_IMM8: - case EcmaOpcode::WIDE_LDLEXVAR_PREF_IMM16_IMM16: - return InferLdLexVarDyn(gate); - case EcmaOpcode::STLEXVAR_IMM4_IMM4: - case EcmaOpcode::STLEXVAR_IMM8_IMM8: - case EcmaOpcode::WIDE_STLEXVAR_PREF_IMM16_IMM16: - return InferStLexVarDyn(gate); - case EcmaOpcode::GETITERATOR_IMM8: - case EcmaOpcode::GETITERATOR_IMM16: - return InferGetIterator(gate); - case EcmaOpcode::STMODULEVAR_IMM8: - case EcmaOpcode::WIDE_STMODULEVAR_PREF_IMM16: - return InferStModuleVar(gate); - case EcmaOpcode::LDLOCALMODULEVAR_IMM8: - case EcmaOpcode::WIDE_LDLOCALMODULEVAR_PREF_IMM16: - return InferLdLocalModuleVar(gate); - case EcmaOpcode::LDEXTERNALMODULEVAR_IMM8: - case EcmaOpcode::WIDE_LDEXTERNALMODULEVAR_PREF_IMM16: - return InferLdExternalModuleVar(gate); - case EcmaOpcode::STOBJBYNAME_IMM8_ID16_V8: - case EcmaOpcode::STOBJBYNAME_IMM16_ID16_V8: - case EcmaOpcode::DEFINEFIELDBYNAME_IMM8_ID16_V8: - return InferStObjByName(gate); - default: - break; - } - return false; -} - -bool MethodTypeInfer::InferPhiGate(GateRef gate) -{ - ASSERT(gateAccessor_.GetOpCode(gate) == OpCode::VALUE_SELECTOR); - CVector typeList; - std::set numberTypeSet; - auto ins = gateAccessor_.ConstIns(gate); - for (auto it = ins.begin(); it != ins.end(); it++) { - // assuming that VALUE_SELECTOR is NO_DEPEND and NO_ROOT - if (gateAccessor_.GetOpCode(*it) == OpCode::MERGE) { - continue; - } - if (gateAccessor_.GetOpCode(*it) == OpCode::LOOP_BEGIN) { - return InferLoopBeginPhiGate(gate); - } - auto valueInType = gateAccessor_.GetGateType(*it); - if (valueInType.IsAnyType()) { - return UpdateType(gate, valueInType, false); - } - if (valueInType.IsNumberType()) { - numberTypeSet.insert(valueInType.GetGTRef()); - } else { - typeList.emplace_back(valueInType.GetGTRef()); - } - } - // deduplicate - std::sort(typeList.begin(), typeList.end()); - auto deduplicateIndex = std::unique(typeList.begin(), typeList.end()); - typeList.erase(deduplicateIndex, typeList.end()); - if (numberTypeSet.size() == 1) { - typeList.emplace_back(*(numberTypeSet.begin())); - } else if (numberTypeSet.size() > 1) { - typeList.emplace_back(GateType::NumberType().GetGTRef()); - } - if (typeList.size() > 1) { - auto unionType = tsManager_->GetOrCreateUnionType(typeList); - return UpdateType(gate, unionType, false); - } - auto type = typeList.at(0); - return UpdateType(gate, type, false); -} - -bool MethodTypeInfer::SetIntType(GateRef gate) -{ - auto intType = GateType::IntType(); - return UpdateType(gate, intType); -} - -bool MethodTypeInfer::SetNumberType(GateRef gate) -{ - auto numberType = GateType::NumberType(); - return UpdateType(gate, numberType); -} - -bool MethodTypeInfer::SetBigIntType(GateRef gate) -{ - auto bigIntType = GateType::BigIntType(); - return UpdateType(gate, bigIntType); -} - -bool MethodTypeInfer::SetBooleanType(GateRef gate) -{ - auto booleanType = GateType::BooleanType(); - return UpdateType(gate, booleanType); -} - -bool MethodTypeInfer::InferLdUndefined(GateRef gate) -{ - auto undefinedType = GateType::UndefinedType(); - return UpdateType(gate, undefinedType); -} - -bool MethodTypeInfer::InferLdNull(GateRef gate) -{ - auto nullType = GateType::NullType(); - return UpdateType(gate, nullType); -} - -bool MethodTypeInfer::InferLdai(GateRef gate) -{ - auto intType = GateType::IntType(); - return UpdateType(gate, intType); -} - -bool MethodTypeInfer::InferFLdai(GateRef gate) -{ - auto doubleType = GateType::DoubleType(); - return UpdateType(gate, doubleType); -} - -bool MethodTypeInfer::InferLdSymbol(GateRef gate) -{ - auto symbolType = GateType::SymbolType(); - return UpdateType(gate, symbolType); -} - -bool MethodTypeInfer::InferThrow(GateRef gate) -{ - ASSERT(gateAccessor_.GetNumValueIn(gate) == 1); - auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - return UpdateType(gate, gateType); -} - -bool MethodTypeInfer::InferTypeOf(GateRef gate) -{ - ASSERT(gateAccessor_.GetNumValueIn(gate) == 1); - auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - return UpdateType(gate, gateType); -} - -/* - * Type Infer rule(satisfy commutative law): - * number + number = number - * int + number = number - * double + number = double - * int + int = int - * int + double = double - * double + double = double - * string + string = string - */ -bool MethodTypeInfer::InferAdd2(GateRef gate) -{ - // 2: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); - auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - if (firInType.IsStringType() || secInType.IsStringType()) { - return UpdateType(gate, GateType::StringType()); - } - if ((firInType.IsNumberType() && secInType.IsDoubleType()) || - (firInType.IsDoubleType() && secInType.IsNumberType())) { - return UpdateType(gate, GateType::DoubleType()); - } - if ((firInType.IsIntType() && secInType.IsIntType())) { - return UpdateType(gate, GateType::IntType()); - } - if (firInType.IsNumberType() && secInType.IsNumberType()) { - return UpdateType(gate, GateType::NumberType()); - } - return UpdateType(gate, GateType::AnyType()); -} - -/* - * Type Infer rule(satisfy commutative law): - * number - number = number - * int - number = number - * double - number = double - * int - int = int - * int - double = double - * double - double = double - */ -bool MethodTypeInfer::InferSub2(GateRef gate) -{ - // 2: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); - auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - if ((firInType.IsNumberType() && secInType.IsDoubleType()) || - (firInType.IsDoubleType() && secInType.IsNumberType())) { - return UpdateType(gate, GateType::DoubleType()); - } - if ((firInType.IsIntType() && secInType.IsIntType())) { - return UpdateType(gate, GateType::IntType()); - } - if (firInType.IsNumberType() && secInType.IsNumberType()) { - return UpdateType(gate, GateType::NumberType()); - } - return UpdateType(gate, GateType::AnyType()); -} - -/* - * Type Infer rule(satisfy commutative law): - * number * number = number - * int * number = number - * double * number = double - * int * int = int - * int * double = double - * double * double = double - */ -bool MethodTypeInfer::InferMul2(GateRef gate) -{ - // 2: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); - auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - if ((firInType.IsNumberType() && secInType.IsDoubleType()) || - (firInType.IsDoubleType() && secInType.IsNumberType())) { - return UpdateType(gate, GateType::DoubleType()); - } - if ((firInType.IsIntType() && secInType.IsIntType())) { - return UpdateType(gate, GateType::IntType()); - } - return UpdateType(gate, GateType::NumberType()); -} - -/* - * Type Infer rule(satisfy commutative law): - * number % number = number - * int % number = number - * double % number = double - * int % int = int - * int % double = double - * double % double = double - */ -bool MethodTypeInfer::InferMod2(GateRef gate) -{ - // 2: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); - auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - if ((firInType.IsNumberType() && secInType.IsDoubleType()) || - (firInType.IsDoubleType() && secInType.IsNumberType())) { - return UpdateType(gate, GateType::DoubleType()); - } - if ((firInType.IsIntType() && secInType.IsIntType())) { - return UpdateType(gate, GateType::IntType()); - } - return UpdateType(gate, GateType::NumberType()); -} - -/* - * Type Infer rule(satisfy commutative law): - * in type lowering, both elements will be changed to float64 firstly. - * number / number = double - * int / number = double - * double / number = double - * int / int = double - * int / double = double - * double / double = double - * any / any = number - * any / number = number - * number / any = number - */ -bool MethodTypeInfer::InferDiv2(GateRef gate) -{ - // 2: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); - auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - auto secInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - if (firInType.IsNumberType() && secInType.IsNumberType()) { - return UpdateType(gate, GateType::DoubleType()); - } - return UpdateType(gate, GateType::NumberType()); -} - -/* - * Type Infer rule: - * number++ = number - * number-- = number - * int++ = int - * int-- = int - * double++ = double - * double-- = double - */ -bool MethodTypeInfer::InferIncDec(GateRef gate) -{ - ASSERT(gateAccessor_.GetNumValueIn(gate) == 1); - auto firInType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - if (firInType.IsDoubleType()) { - return UpdateType(gate, GateType::DoubleType()); - } - if (firInType.IsIntType()) { - return UpdateType(gate, GateType::IntType()); - } - if (firInType.IsNumberType()) { - return UpdateType(gate, GateType::NumberType()); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferToNumberic(GateRef gate) -{ - GateRef src = gateAccessor_.GetValueIn(gate, 0); - GateType srcType = gateAccessor_.GetGateType(src); - if (srcType.IsNumberType()) { - return UpdateType(gate, srcType); - } - return UpdateType(gate, GateType::NumberType()); -} - -bool MethodTypeInfer::InferLdObjByIndex(GateRef gate) -{ - // 2: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); - auto inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - inValueType = tsManager_->TryNarrowUnionType(inValueType); - if (tsManager_->IsArrayTypeKind(inValueType)) { - auto type = tsManager_->GetArrayParameterTypeGT(inValueType); - return UpdateType(gate, type); - } - - if (tsManager_->IsIntTypedArrayType(inValueType)) { - return UpdateType(gate, GateType::IntType()); - } - - if (tsManager_->IsDoubleTypedArrayType(inValueType)) { - return UpdateType(gate, GateType::DoubleType()); - } - - if (tsManager_->IsTypedArrayType(inValueType)) { - return UpdateType(gate, GateType::NumberType()); - } - - if (ShouldInferWithLdObjByValue(inValueType)) { - uint64_t key = gateAccessor_.GetConstantValue((gateAccessor_.GetValueIn(gate, 0))); // 0: index of key - auto type = GetPropType(inValueType, key); - return UpdateType(gate, type); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::SetStGlobalBcType(GateRef gate, bool hasIC) -{ - auto &byteCodeInfo = GetByteCodeInfo(gate); - uint16_t stringId = 0; - GateType inValueType; - if (hasIC) { - // 2: number of value inputs - ASSERT(byteCodeInfo.inputs.size() == 2); - stringId = std::get(byteCodeInfo.inputs[1]).GetId(); - // 3: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 3); - // 2: value input - inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2)); - } else { - ASSERT(byteCodeInfo.inputs.size() == 1); - stringId = std::get(byteCodeInfo.inputs[0]).GetId(); - // 2: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 2); - inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - } - if (!hasType_ && inValueType.IsUndefinedType()) { - inValueType = GateType::AnyType(); - } - if (stringIdToGateType_.find(stringId) != stringIdToGateType_.end()) { - stringIdToGateType_[stringId] = inValueType; - } else { - stringIdToGateType_.emplace(stringId, inValueType); - } - return UpdateType(gate, inValueType); -} - -bool MethodTypeInfer::InferLdGlobalVar(GateRef gate) -{ - auto &byteCodeInfo = GetByteCodeInfo(gate); - ASSERT(byteCodeInfo.inputs.size() == 2); // 2: number of value inputs - auto stringId = std::get(byteCodeInfo.inputs[1]).GetId(); - auto iter = stringIdToGateType_.find(stringId); - if (iter != stringIdToGateType_.end()) { - return UpdateType(gate, iter->second); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferReturnUndefined(GateRef gate) -{ - auto undefinedType = GateType::UndefinedType(); - return UpdateType(gate, undefinedType); -} - -bool MethodTypeInfer::InferReturn(GateRef gate) -{ - ASSERT(gateAccessor_.GetNumValueIn(gate) == 1); - auto gateType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - return UpdateType(gate, gateType); -} - -bool MethodTypeInfer::InferLdObjByName(GateRef gate) -{ - // 3: number of value inputs - ASSERT(gateAccessor_.GetNumValueIn(gate) == 3); - auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 2)); // 2: the third parameter is receiver - if (objType.IsAnyType()) { - return UpdateType(gate, GateType::AnyType()); - } - objType = tsManager_->TryNarrowUnionType(objType); - if (ShouldConvertToBuiltinArray(objType)) { - GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType); - auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt); - objType = GateType(builtinInstanceType); - } - if (tsManager_->IsPrimitiveTypeKind(objType)) { - GlobalTSTypeRef builtinGt = ConvertPrimitiveToBuiltin(objType); - if (builtinGt.IsBuiltinModule()) { - auto builtinInstanceType = tsManager_->CreateClassInstanceType(builtinGt); - objType = GateType(builtinInstanceType); - } - } - // If this object has no gt type, we cannot get its internal property type - if (ShouldInferWithLdObjByName(objType)) { - uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1)); - return GetObjPropWithName(gate, objType, index); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferStObjByName(GateRef gate) -{ - GateRef value = gateAccessor_.GetValueIn(gate, 3); // 3: index of value - GateType valueType = gateAccessor_.GetGateType(value); - if (valueType.IsAnyType()) { - return false; - } - - GateRef receiver = gateAccessor_.GetValueIn(gate, 2); // 2: index of receiver - GateType receiverType = gateAccessor_.GetGateType(receiver); - - uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1)); // 1: index of key - auto methodOffset = gateAccessor_.TryGetMethodOffset(gate); - JSTaggedValue propKey = tsManager_->GetStringFromConstantPool(methodOffset, index); - if (tsManager_->IsNamespaceTypeKind(receiverType)) { - if (tsManager_->AddNamespacePropType(receiverType, propKey, valueType)) { - Enqueue(receiver); - } - return true; - } - - if (valueType.IsNumberType()) { - valueType = GateType::NumberType(); - } - - if (tsManager_->IsClassTypeKind(receiverType)) { - TSTypeAccessor typeAccessor(tsManager_, receiverType); - typeAccessor.UpdateStaticProp(propKey, valueType.GetGTRef()); - return true; - } - return false; -} - -bool MethodTypeInfer::InferNewObject(GateRef gate) -{ - auto objType = gateAccessor_.GetGateType(gate); - if (!tsManager_->IsClassInstanceTypeKind(objType) && !tsManager_->IsArrayTypeKind(objType)) { - ASSERT(gateAccessor_.GetNumValueIn(gate) > 0); - auto classType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - if (tsManager_->IsClassTypeKind(classType)) { - auto classInstanceType = tsManager_->CreateClassInstanceType(classType); - return UpdateType(gate, classInstanceType); - } - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferLdStr(GateRef gate) -{ - auto stringType = GateType::StringType(); - return UpdateType(gate, stringType); -} - -bool MethodTypeInfer::GetObjPropWithName(GateRef gate, GateType objType, uint64_t index) -{ - auto methodOffset = gateAccessor_.TryGetMethodOffset(gate); - JSTaggedValue name = tsManager_->GetStringFromConstantPool(methodOffset, index); - if (tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, objType) || tsManager_->IsTypedArrayType(objType)) { - auto thread = tsManager_->GetThread(); - JSTaggedValue lengthKey = thread->GlobalConstants()->GetLengthString(); - if (JSTaggedValue::SameValue(name, lengthKey)) { - return SetIntType(gate); - } - if (tsManager_->IsTypedArrayType(objType)) { - uint32_t eleIdx = 0; - if (EcmaStringAccessor(name).ToElementIndex(&eleIdx)) { - return UpdateType(gate, GateType::NumberType()); - } - } - } - auto type = GetPropType(objType, name); - if (tsManager_->IsGetterSetterFunc(type)) { - auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type); - return UpdateType(gate, returnGt); - } - return UpdateType(gate, type); -} - -bool MethodTypeInfer::InferCallMethod(GateRef gate) -{ - // 1: last one elem is function - size_t funcIndex = gateAccessor_.GetNumValueIn(gate) - 1; - auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex)); - if (tsManager_->IsFunctionTypeKind(funcType)) { - // forEach CallBack - TSTypeAccessor typeAccessor(tsManager_, funcType); - if (typeAccessor.GetFunctionName() == "forEach") { - auto funcGate = gateAccessor_.GetValueIn(gate, funcIndex); - auto &bytecodeInfo = GetByteCodeInfo(funcGate); - if (bytecodeInfo.GetOpcode() == EcmaOpcode::LDOBJBYNAME_IMM8_ID16 || - bytecodeInfo.GetOpcode() == EcmaOpcode::LDOBJBYNAME_IMM16_ID16) { - // 2: the third parameter is receiver - auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(funcGate, 2)); - // get callBack function type - auto callBackType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - TSTypeAccessor newTypeAccessor(tsManager_, callBackType); - newTypeAccessor.UpdateForEachCBPara(objType); - } - } - - // normal Call - auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType); - GateRef thisObj = gateAccessor_.GetValueIn(gate, 0); // 0: index of thisObject - auto thisObjType = gateAccessor_.GetGateType(thisObj); - return UpdateType(gate, HandleTypeCompatibility(thisObjType, GateType(returnType))); - } else if (tsManager_->IsIteratorInstanceTypeKind(funcType)) { - GlobalTSTypeRef elementGT = tsManager_->GetIteratorInstanceElementGt(funcType); - GlobalTSTypeRef iteratorResultInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType( - TSRuntimeType::ITERATOR_RESULT, elementGT); - return UpdateType(gate, iteratorResultInstanceType); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferCallFunction(GateRef gate) -{ - // 1: last one elem is function - size_t funcIndex = gateAccessor_.GetNumValueIn(gate) - 1; - auto funcType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, funcIndex)); - if (tsManager_->IsFunctionTypeKind(funcType)) { - auto returnType = tsManager_->GetFuncReturnValueTypeGT(funcType); - return UpdateType(gate, returnType); - } - /* According to the ECMAScript specification, user-defined classes can only be instantiated by constructing (with - * new keyword). However, a few builtin types can be called like a function. Upon the results of calling and - * constructing, there are 4 categories of builtin types: - * - * Category 1: non-callable, objects of such a type can only be created by constructing. - * Category 2: non-constructable, such types can only be called. - * Category 3: simple, calling and constructing are equivalent. - * Category 4: complex, a type can be called and constructed, but the results differ. - * - * Constructing a builtin type always create objects of the type if supported. So in this function, we focus on the - * builtin types which are callable. While the majority of the callable builtin types have the same calling behavior - * as constructing, here are some special cases: - * - * | Type | Call | Category | - * | ------- | ----------------- | -------- | - * | BigInt | primitive bigint | 2 | - * | Boolean | primitive boolean | 4 | - * | Date | primitive string | 4 | - * | Number | primitive number | 4 | - * | String | primitive string | 4 | - * - * See the list of builtin types' constructors at: - * https://tc39.es/ecma262/2021/#sec-constructor-properties-of-the-global-object - */ - if (tsManager_->IsBuiltinObjectType(funcType)) { - // For simplicity, calling and constructing are considered equivalent. - if (tsManager_->IsBuiltinClassType(BuiltinTypeId::ARRAY, funcType)) { - return UpdateType(gate, tsManager_->CreateArrayType()); - } - return UpdateType(gate, tsManager_->CreateClassInstanceType(funcType)); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferLdObjByValue(GateRef gate) -{ - auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 1)); - objType = tsManager_->TryNarrowUnionType(objType); - // handle array - if (tsManager_->IsArrayTypeKind(objType)) { - auto elementType = tsManager_->GetArrayParameterTypeGT(objType); - return UpdateType(gate, elementType); - } - if (tsManager_->IsIntTypedArrayType(objType)) { - return UpdateType(gate, GateType::IntType()); - } - if (tsManager_->IsDoubleTypedArrayType(objType)) { - return UpdateType(gate, GateType::DoubleType()); - } - // handle object - if (ShouldInferWithLdObjByValue(objType)) { - auto valueGate = gateAccessor_.GetValueIn(gate, 2); // 2: value input slot - if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) { - if (tsManager_->IsTypedArrayType(objType)) { - return UpdateType(gate, GateType::NumberType()); - } - uint64_t value = gateAccessor_.GetConstantValue(valueGate); - auto type = GetPropType(objType, value); - return UpdateType(gate, type); - } - if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) { - auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(valueGate, 0)); - return GetObjPropWithName(gate, objType, index); - } - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferGetNextPropName(GateRef gate) -{ - auto stringType = GateType::StringType(); - return UpdateType(gate, stringType); -} - -bool MethodTypeInfer::InferDefineGetterSetterByValue(GateRef gate) -{ - // 0 : the index of obj - auto objType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - return UpdateType(gate, objType); -} - -bool MethodTypeInfer::InferSuperCall(GateRef gate) -{ - ArgumentAccessor argAcc(circuit_); - auto newTarget = argAcc.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET); - auto classType = gateAccessor_.GetGateType(newTarget); - if (tsManager_->IsClassTypeKind(classType)) { - auto classInstanceType = tsManager_->CreateClassInstanceType(classType); - return UpdateType(gate, classInstanceType); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferSuperPropertyByName(GateRef gate) -{ - uint16_t index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0)); - return GetSuperProp(gate, index); -} - -bool MethodTypeInfer::InferSuperPropertyByValue(GateRef gate) -{ - auto valueGate = gateAccessor_.GetValueIn(gate, 1); - if (IsByteCodeGate(valueGate) && GetByteCodeInfo(valueGate).IsBc(EcmaOpcode::LDA_STR_ID16)) { - auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(valueGate, 0)); - return GetSuperProp(gate, index); - } - if (gateAccessor_.GetOpCode(valueGate) == OpCode::CONSTANT) { - auto index = gateAccessor_.GetConstantValue(valueGate); - - return GetSuperProp(gate, index, false); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::GetSuperProp(GateRef gate, uint64_t index, bool isString) -{ - ArgumentAccessor argAcc(circuit_); - auto func = argAcc.GetFrameArgsIn(gate, FrameArgIdx::FUNC); - auto newTarget = argAcc.GetFrameArgsIn(gate, FrameArgIdx::NEW_TARGET); - auto funcType = gateAccessor_.GetGateType(func); - auto classType = gateAccessor_.GetGateType(newTarget); - if (funcType.IsAnyType() || classType.IsAnyType() || classType.IsUndefinedType()) { - return UpdateType(gate, GateType::AnyType()); - } - - bool isStatic = tsManager_->IsStaticFunc(funcType.GetGTRef()); - auto propType = isStatic ? PropertyType::STATIC : PropertyType::NORMAL; - auto methodOffset = gateAccessor_.TryGetMethodOffset(gate); - GlobalTSTypeRef type = isString ? - tsManager_->GetSuperPropType(classType.GetGTRef(), - tsManager_->GetStringFromConstantPool(methodOffset, index), propType) : - tsManager_->GetSuperPropType(classType.GetGTRef(), index, propType); - if (tsManager_->IsGetterSetterFunc(type)) { - auto returnGt = tsManager_->GetFuncReturnValueTypeGT(type); - return UpdateType(gate, returnGt); - } - return UpdateType(gate, type); -} - -bool MethodTypeInfer::InferGetIterator(GateRef gate) -{ - ASSERT(gateAccessor_.GetNumValueIn(gate) == 1); - GateType inValueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 0)); - - GlobalTSTypeRef elementGt = GlobalTSTypeRef::Default(); - if (tsManager_->IsArrayTypeKind(inValueType)) { - elementGt = tsManager_->GetArrayParameterTypeGT(inValueType); - } else if (inValueType.IsStringType()) { - elementGt.SetType(GateType::StringType().Value()); - } else { - return UpdateType(gate, GateType::AnyType()); - } - GlobalTSTypeRef iteratorInstanceType = tsManager_->GetOrCreateTSIteratorInstanceType( - TSRuntimeType::ITERATOR, elementGt); - return UpdateType(gate, iteratorInstanceType); -} - -bool MethodTypeInfer::InferTryLdGlobalByName(GateRef gate) -{ - // todo by hongtao, should consider function of .d.ts - auto &byteCodeInfo = GetByteCodeInfo(gate); - ASSERT(byteCodeInfo.inputs.size() == 2); // 2: number of parameter - auto stringId = std::get(byteCodeInfo.inputs[1]).GetId(); - auto iter = stringIdToGateType_.find(stringId); - if (iter != stringIdToGateType_.end()) { - return UpdateType(gate, iter->second); - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferLdLexVarDyn(GateRef gate) -{ - auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0)); - auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1)); - auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot); - if (!hasType_ && type.IsUndefinedType()) { - type = GateType::AnyType(); - } - return UpdateType(gate, type); -} - -bool MethodTypeInfer::InferStLexVarDyn(GateRef gate) -{ - auto level = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0)); - auto slot = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 1)); - auto type = lexEnvManager_->GetLexEnvElementType(methodId_, level, slot); - if (type.IsAnyType() || type.IsUndefinedType()) { - auto valueType = gateAccessor_.GetGateType(gateAccessor_.GetValueIn(gate, 3)); - if (!valueType.IsAnyType()) { - lexEnvManager_->SetLexEnvElementType(methodId_, level, slot, valueType); - return true; - } - } - return false; -} - -bool MethodTypeInfer::InferStModuleVar(GateRef gate) -{ - auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0)); - const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile(); - auto defineGate = gateAccessor_.GetValueIn(gate, 1); - auto defineType = gateAccessor_.GetGateType(defineGate); - if (!defineType.IsAnyType()) { - tsManager_->AddTypeToModuleVarGtMap(jsPandaFile, recordName_, index, defineType.GetGTRef()); - return true; - } - return false; -} - -bool MethodTypeInfer::InferLdLocalModuleVar(GateRef gate) -{ - auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0)); - const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile(); - if (!tsManager_->HasExportGT(jsPandaFile, recordName_, index)) { - return UpdateType(gate, GateType::AnyType()); - } - auto type = tsManager_->GetGTFromModuleMap(jsPandaFile, recordName_, index); - return UpdateType(gate, type); -} - -bool MethodTypeInfer::InferLdExternalModuleVar(GateRef gate) -{ - auto index = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(gate, 0)); - auto loadType = gateAccessor_.GetGateType(gate); - auto bcInfoCollector = tsManager_->GetBytecodeInfoCollector(); - ASSERT(bcInfoCollector != nullptr); - const auto &bcInfo = bcInfoCollector->GetBytecodeInfo(); - const auto &importRecordsInfos = bcInfo.GetImportRecordsInfos(); - auto iter = importRecordsInfos.find(recordName_); - const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile(); - CString resolvedRecord = ""; - uint32_t resolvedIndex = 0; - if (loadType.IsAnyType() && iter != importRecordsInfos.end()) { - const auto &importIdToExportRecord = iter->second.GetImportIdToExportRecord(); - if (importIdToExportRecord.find(index) != importIdToExportRecord.end()) { - std::tie(resolvedRecord, resolvedIndex) = importIdToExportRecord.at(index); - if (tsManager_->HasExportGT(jsPandaFile, resolvedRecord, resolvedIndex)) { - return UpdateType(gate, tsManager_->GetGTFromModuleMap(jsPandaFile, resolvedRecord, resolvedIndex)); - } - } - } - // if we can't find type in exportRecords, we will try to find type using resolved index binding directly. - // However, this compilation order is not guaranteed, so the export type may not have been infered. - if (UNLIKELY(loadType.IsAnyType())) { - auto thread = tsManager_->GetEcmaVM()->GetJSThread(); - ModuleManager *moduleManager = thread->GetCurrentEcmaContext()->GetModuleManager(); - [[maybe_unused]] EcmaHandleScope scope(thread); - JSHandle currentModule = moduleManager->HostGetImportedModule(recordName_); - JSTaggedValue moduleEnvironment = currentModule->GetEnvironment(); - if (moduleEnvironment.IsUndefined()) { - return UpdateType(gate, GateType::AnyType()); - } - ASSERT(moduleEnvironment.IsTaggedArray()); - JSHandle moduleArray(thread, moduleEnvironment); - JSTaggedValue resolvedBinding = moduleArray->Get(index); - // if resolvedBinding.IsHole(), means that importname is * or it belongs to empty Aot module. - if (!resolvedBinding.IsResolvedIndexBinding()) { - return UpdateType(gate, GateType::AnyType()); - } - ResolvedIndexBinding *binding = ResolvedIndexBinding::Cast(resolvedBinding.GetTaggedObject()); - resolvedRecord = ModuleManager::GetRecordName(binding->GetModule()); - resolvedIndex = static_cast(binding->GetIndex()); - if (tsManager_->HasExportGT(jsPandaFile, resolvedRecord, resolvedIndex)) { - return UpdateType(gate, tsManager_->GetGTFromModuleMap(jsPandaFile, resolvedRecord, resolvedIndex)); - } - } - return UpdateType(gate, GateType::AnyType()); -} - -bool MethodTypeInfer::InferLoopBeginPhiGate(GateRef gate) -{ - // loop-begin phi gate has 3 ins: loop_begin(stateWire), loopInGate(valueWire), loopBackGate(valueWire) - auto loopInGate = gateAccessor_.GetValueIn(gate); - auto loopInType = gateAccessor_.GetGateType(loopInGate); - // loop-begin phi will be initialized as loopInTytpe - // type of loop-back phi should be infered correctly only after loop-begin has actual type - // if loop-in phi is actual any type, loop-begin phi must be any - if (loopPhiState_.find(gate) == loopPhiState_.end()) { - if (!loopInType.IsAnyType()) { - loopPhiState_[gate] = InferState::NORMAL_INFERED; - } - return UpdateType(gate, loopInType, false); - } - // if loop phi has been marked as ANY_INFERED, it's in the second round infer for loop - if (loopPhiState_[gate] == InferState::ANY_INFERED) { - return UpdateType(gate, GateType::AnyType(), false); - } - // if loopInType and loopBackType both have non-any type, we need special treatment for the situation - // in which loopInType and loopBackType both are numberType(int/double/number). - // However, we should avoid excessive type promotion which may cause endless loop in few IR situations. - if (loopPhiState_[gate] == InferState::NUMBER_INFERED) { - return UpdateType(gate, GateType::NumberType(), false); - } - return UpdateType(gate, loopInType, false); -} - -GlobalTSTypeRef MethodTypeInfer::ConvertPrimitiveToBuiltin(const GateType &gateType) -{ - GlobalTSTypeRef builtinGt = GlobalTSTypeRef::Default(); - if (!tsManager_->IsBuiltinsDTSEnabled()) { - return builtinGt; - } - - const JSPandaFile *builtinjsPandaFile = tsManager_->GetBuiltinPandaFile(); - if (builtinjsPandaFile == nullptr) { - LOG_COMPILER(FATAL) << "load lib_ark_builtins.d.ts failed"; - } - const CString &builtinsRecordName = tsManager_->GetBuiltinRecordName(); - TSTypeParser typeParser(tsManager_); - - if (tsManager_->IsArrayTypeKind(gateType)) { - return typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName, - static_cast(BuiltinTypeId::ARRAY)); - } - - const GlobalTSTypeRef gt = GlobalTSTypeRef(gateType.Value()); - uint32_t l = gt.GetLocalId(); - switch (l) { - case static_cast(TSPrimitiveType::SYMBOL): - builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName, - static_cast(BuiltinTypeId::SYMBOL)); - break; - case static_cast(TSPrimitiveType::INT): - case static_cast(TSPrimitiveType::DOUBLE): - case static_cast(TSPrimitiveType::NUMBER): - builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName, - static_cast(BuiltinTypeId::NUMBER)); - break; - case static_cast(TSPrimitiveType::BOOLEAN): - builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName, - static_cast(BuiltinTypeId::BOOLEAN)); - break; - case static_cast(TSPrimitiveType::STRING): - builtinGt = typeParser.CreateGT(builtinjsPandaFile, builtinsRecordName, - static_cast(BuiltinTypeId::STRING)); - break; - default: - builtinGt = GlobalTSTypeRef::Default(); - } - return builtinGt; -} - -GlobalTSTypeRef MethodTypeInfer::GetPropType(const GateType type, const JSTaggedValue propertyName) const -{ - GlobalTSTypeRef objGT(type.Value()); - GlobalTSTypeRef propGT = tsManager_->GetPropType(objGT, propertyName); - if (!propGT.IsDefault()) { - return propGT; - } - return tsManager_->GetIndexSignType(objGT, GateType::StringType()); -} - -GlobalTSTypeRef MethodTypeInfer::GetPropType(const GateType type, const uint64_t key) const -{ - GlobalTSTypeRef objGT(type.Value()); - GlobalTSTypeRef propGT = tsManager_->GetPropType(objGT, key); - if (!propGT.IsDefault()) { - return propGT; - } - return tsManager_->GetIndexSignType(objGT, GateType::NumberType()); -} - -// In TS, a namespace can be thought of as a formalization of the IIFE pattern. -// The function has only one parameter, which corresponds to the namespace object. -void MethodTypeInfer::SetNamespaceArgType(GateType type) -{ - ArgumentAccessor argAcc(circuit_, methodLiteral_); - // the last position is where the only parameter of the function are placed - auto gate = argAcc.ArgsAt(argAcc.ArgsCount() - 1); - gateAccessor_.SetGateType(gate, type); -} - -// When a IIFE which corresponds to namespaces declaration being called, -// A namespace type will be set to the namespace object. -std::pair MethodTypeInfer::SetAndReturnNamespaceObjType(GateRef gate) -{ - GateRef func = gateAccessor_.GetValueIn(gate, 1); // 1: index of func - uint16_t id = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(func, 0)); // 0: index of methodId - GateRef obj = gateAccessor_.GetValueIn(gate, 0); // 0: index of obj - // the obj must be phi gate due to the conversion of syntax sugar of namespace - ASSERT(gateAccessor_.IsValueSelector(obj)); - GlobalTSTypeRef gt = TryGetNamespaceType(obj); - - uint32_t methodId = ctx_->GetJSPandaFile()->ResolveMethodIndex(methodLiteral_->GetMethodId(), id).GetOffset(); - uint32_t length = gateAccessor_.GetNumValueIn(obj); - for (uint32_t i = 0; i < length; i++) { - GateRef namespaceObj = gateAccessor_.GetValueIn(obj, i); - if (!IsByteCodeGate(namespaceObj)) { - continue; - } - auto &bytecodeInfo = GetByteCodeInfo(namespaceObj); - if (!bytecodeInfo.IsBc(EcmaOpcode::CREATEEMPTYOBJECT)) { - continue; - } - - if (gt.IsDefault()) { - gt = tsManager_->CreateNamespaceType(); - } - gateAccessor_.SetGateType(namespaceObj, GateType(gt)); - return std::make_pair(GateType(gt), methodId); - } - - return std::make_pair((GateType(gt)), methodId); -} - -GlobalTSTypeRef MethodTypeInfer::TryGetNamespaceType(GateRef gate) const -{ - ASSERT(gateAccessor_.IsValueSelector(gate)); - uint32_t length = gateAccessor_.GetNumValueIn(gate); - for (uint32_t i = 0; i < length; i++) { - GateRef namespaceObj = gateAccessor_.GetValueIn(gate, i); - GateType type = gateAccessor_.GetGateType(namespaceObj); - GlobalTSTypeRef namespaceGT(type.Value()); - if (tsManager_->IsNamespaceTypeKind(namespaceGT)) { - return namespaceGT; - } - } - return GlobalTSTypeRef::Default(); -} - -bool MethodTypeInfer::IsNamespace(GateRef gate) const -{ - if (IsByteCodeGate(gate)) { - auto &bytecodeInfo = GetByteCodeInfo(gate); - if (bytecodeInfo.IsBc(EcmaOpcode::CALLARG1_IMM8_V8)) { - GateRef obj = gateAccessor_.GetValueIn(gate, 0); // 0: index of obj - GateRef func = gateAccessor_.GetValueIn(gate, 1); // 1: index of func - return CheckNamespaceFunc(func) && gateAccessor_.IsValueSelector(obj); - } - } - return false; -} - -bool MethodTypeInfer::CheckNamespaceFunc(GateRef func) const -{ - if (IsByteCodeGate(func)) { - auto &bytecodeInfo = GetByteCodeInfo(func); - if (bytecodeInfo.IsBc(EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8) || - bytecodeInfo.IsBc(EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) { - uint16_t id = gateAccessor_.GetConstantValue(gateAccessor_.GetValueIn(func, 0)); // 0: index of methodId - uint32_t methodId = - ctx_->GetJSPandaFile()->ResolveMethodIndex(methodLiteral_->GetMethodId(), id).GetOffset(); - auto &bcInfo = ctx_->GetBytecodeInfo(); - auto &methodLists = bcInfo.GetMethodList(); - auto &methodInfo = methodLists.at(methodId); - return methodInfo.IsNamespace(); - } - } - return false; -} - -void MethodTypeInfer::PrintTypeAnnotation() const -{ - const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile(); - panda_file::File::EntityId fieldId = methodLiteral_->GetMethodId(); - TypeAnnotationExtractor annoExtractor(jsPandaFile, fieldId.GetOffset()); - annoExtractor.Print(); -} - -void MethodTypeInfer::PrintByteCodesWithTypes() const -{ - std::vector gateList; - circuit_->GetAllGates(gateList); - - const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile(); - const MethodLiteral *methodLiteral = builder_->GetMethod(); - auto methodId = methodLiteral->GetMethodId(); - const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId); - - const uint32_t adjustment = 6; - LOG_COMPILER(INFO) << "===================================================================="; - LOG_COMPILER(INFO) << "print bytecode types:"; - LOG_COMPILER(INFO) << ".recordName " + recordName_; - LOG_COMPILER(INFO) << ".function " + functionName + "() {"; - uint32_t lastBcIndex = builder_->GetLastBcIndex(); - DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); - for (uint32_t bcIndex = 0; bcIndex < lastBcIndex; bcIndex++) { // ignore last element - const uint8_t *pc = builder_->GetPCByIndex(bcIndex); - BytecodeInstruction inst(pc); - int32_t lineNumber = 0; - auto callbackLineFunc = [&lineNumber](int32_t line) -> bool { - lineNumber = line + 1; - return true; - }; - int32_t columnNumber = 0; - auto callbackColumnFunc = [&columnNumber](int32_t column) -> bool { - columnNumber += column + 1; - return true; - }; - auto offset = builder_->GetPcOffset(bcIndex); - debugExtractor->MatchLineWithOffset(callbackLineFunc, methodId, offset); - debugExtractor->MatchColumnWithOffset(callbackColumnFunc, methodId, offset); - - auto gates = builder_->GetGatesByBcIndex(bcIndex); - if (gates.empty()) { - LOG_COMPILER(INFO) << std::setw(adjustment) << std::to_string(bcIndex) << " " << inst << ", " - << "at line: " + std::to_string(lineNumber) + " column: " + std::to_string(columnNumber) - << ", pcOffset: " + std::to_string(offset); - } - - for (const auto gate : gates) { - if (gate == Circuit::NullGate()) { - continue; - } - - GateType type = gateAccessor_.GetGateType(gate); - GlobalTSTypeRef gt = type.GetGTRef(); - LOG_COMPILER(INFO) << std::setw(adjustment) << std::to_string(bcIndex) << " " << inst << ", " - << "[type: " + tsManager_->GetTypeStr(type) + ", " - << "moduleId: " + std::to_string(gt.GetModuleId()) + ", " - << "localId: " + std::to_string(gt.GetLocalId()) + "], " - << "at line: " + std::to_string(lineNumber) + " column: " + std::to_string(columnNumber) - << ", pcOffset: " + std::to_string(offset); - } - } - LOG_COMPILER(INFO) << "}"; -} - -void MethodTypeInfer::PrintCircuitWithTypes() const -{ - LOG_COMPILER(INFO) << "\033[34m" - << "====================" - << " After ts type infer " - << "[" << GetMethodName() << "]" - << "====================" - << "\033[0m"; - circuit_->PrintAllGatesWithBytecode(); - LOG_COMPILER(INFO) << "\033[34m" << "========================= End ==========================" << "\033[0m"; - LOG_COMPILER(INFO) << ""; -} - -void MethodTypeInfer::Verify() const -{ - std::vector gateList; - circuit_->GetAllGates(gateList); - for (const auto &gate : gateList) { - if (IsByteCodeGate(gate)) { - TypeCheck(gate); - PGOTypeCheck(gate); - } - } -} - -/* - * Let v be a variable in one ts-file and t be a type. To check whether the type of v is t after - * type inferenece, one should declare a function named "AssertType(value:any, type:string):void" - * in ts-file and call it with arguments v and t, where t is the expected type string. - * The following interface performs such a check at compile time. - */ -void MethodTypeInfer::TypeCheck(GateRef gate) const -{ - auto &info = GetByteCodeInfo(gate); - if (!info.IsBc(EcmaOpcode::CALLARGS2_IMM8_V8_V8)) { - return; - } - auto func = gateAccessor_.GetValueIn(gate, 2); // 2: acc - auto &funcInfo = GetByteCodeInfo(func); - if (!funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16) && - !funcInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16)) { - return; - } - auto funcName = gateAccessor_.GetValueIn(func, 1); - uint16_t funcNameStrId = gateAccessor_.GetConstantValue(funcName); - auto methodOffset = gateAccessor_.TryGetMethodOffset(gate); - auto funcNameString = tsManager_->GetStdStringFromConstantPool(methodOffset, funcNameStrId); - if (funcNameString == "AssertType") { - GateRef expectedGate = gateAccessor_.GetValueIn(gate, 1); - GateRef constId = gateAccessor_.GetValueIn(expectedGate, 0); - uint16_t strId = gateAccessor_.GetConstantValue(constId); - auto expectedTypeStr = tsManager_->GetStdStringFromConstantPool(methodOffset, strId); - GateRef valueGate = gateAccessor_.GetValueIn(gate, 0); - auto type = gateAccessor_.GetGateType(valueGate); - if (expectedTypeStr != tsManager_->GetTypeStr(type)) { - const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile(); - EntityId methodId = builder_->GetMethod()->GetMethodId(); - DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); - const std::string &sourceFileName = debugExtractor->GetSourceFile(methodId); - const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId); - - std::string log = CollectGateTypeLogInfo(valueGate, debugExtractor, "[TypeAssertion] ", false); - log += "[TypeAssertion] but expected type: " + expectedTypeStr + "\n"; - - LOG_COMPILER(ERROR) << "[TypeAssertion] [" << sourceFileName << ":" << functionName << "] begin:"; - LOG_COMPILER(FATAL) << log << "[compiler] [TypeAssertion] end"; - } - } -} - -void MethodTypeInfer::PGOTypeCheck(GateRef gate) const -{ - auto &info = GetByteCodeInfo(gate); - if (!info.IsBc(EcmaOpcode::CALLTHIS2_IMM8_V8_V8_V8)) { // ArkTools.pgoAssertType - return ; - } - // 1. thisObj - auto thisObj = gateAccessor_.GetValueIn(gate, 0); - if (!IsByteCodeGate(thisObj)) { - return ; - } - auto &thisObjInfo = GetByteCodeInfo(thisObj); - if (!thisObjInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM8_ID16) && - !thisObjInfo.IsBc(EcmaOpcode::TRYLDGLOBALBYNAME_IMM16_ID16)) { - return; - } - auto thisObjName = gateAccessor_.GetValueIn(thisObj, 1); - uint16_t thisObjNameStrId = gateAccessor_.GetConstantValue(thisObjName); - auto methodOffset = gateAccessor_.TryGetMethodOffset(gate); - auto thisObjNameString = tsManager_->GetStdStringFromConstantPool(methodOffset, - thisObjNameStrId); - // 2. funcName - auto func = gateAccessor_.GetValueIn(gate, 3); - if (!IsByteCodeGate(func)) { - return ; - } - auto &funcInfo = GetByteCodeInfo(func); - if (!funcInfo.IsBc(EcmaOpcode::LDOBJBYNAME_IMM8_ID16)) { - return; - } - auto funcName = gateAccessor_.GetValueIn(func, 1); - uint16_t funcNameStrId = gateAccessor_.GetConstantValue(funcName); - auto funcNameString = tsManager_->GetStdStringFromConstantPool(methodOffset, funcNameStrId); - // 3. check whether it is ArkTools.pgoAssertType() - if (thisObjNameString == "ArkTools" && funcNameString == "pgoAssertType") { - // 4. expected type - GateRef expectedGate = gateAccessor_.GetValueIn(gate, 2); - GateRef constId = gateAccessor_.GetValueIn(expectedGate, 0); - uint16_t strId = gateAccessor_.GetConstantValue(constId); - auto expectedTypeStr = tsManager_->GetStdStringFromConstantPool(methodOffset, strId); - // 5. pgo type - GateRef valueGate = gateAccessor_.GetValueIn(gate, 1); - auto pgoType = gateAccessor_.TryGetPGOType(valueGate); // pgo type - auto pgoTypeStr = pgoType.GetPGOSampleType()->ToString(); - // 6. compare expected type and pgo type - if (expectedTypeStr != pgoTypeStr) { - const JSPandaFile *jsPandaFile = builder_->GetJSPandaFile(); - EntityId methodId = builder_->GetMethod()->GetMethodId(); - DebugInfoExtractor *debugExtractor = JSPandaFileManager::GetInstance()->GetJSPtExtractor(jsPandaFile); - const std::string &sourceFileName = debugExtractor->GetSourceFile(methodId); - const std::string functionName = MethodLiteral::ParseFunctionName(jsPandaFile, methodId); - - std::string log = CollectGateTypeLogInfo(valueGate, debugExtractor, "[PGOTypeAssertion] ", true); - log += "[PGOTypeAssertion] but expected type: " + expectedTypeStr + "\n"; - - LOG_COMPILER(ERROR) << "[PGOTypeAssertion] [" << sourceFileName << ":" << functionName << "] begin:"; - LOG_COMPILER(FATAL) << log << "[compiler] [PGOTypeAssertion] end"; - } - } -} - -std::string MethodTypeInfer::CollectGateTypeLogInfo(GateRef gate, DebugInfoExtractor *debugExtractor, - const std::string &logPreFix, bool isPGO) const -{ - std::string log(logPreFix); - log += "gate id: "+ std::to_string(gateAccessor_.GetId(gate)) + ", "; - OpCode op = gateAccessor_.GetOpCode(gate); - log += "op: " + GateMetaData::Str(op) + ", "; - if (op == OpCode::ARG) { - log += "arg gate, "; - } else if (op != OpCode::VALUE_SELECTOR) { - auto &bytecodeInfo = GetByteCodeInfo(gate); - // handle ByteCode gate: print gate id, bytecode and line number in source code. - log += "bytecode: " + GetEcmaOpcodeStr(bytecodeInfo.GetOpcode()) + ", "; - - int32_t lineNumber = 0; - auto callbackLineFunc = [&lineNumber](int32_t line) -> bool { - lineNumber = line + 1; - return true; - }; - - const auto bcIndex = jsgateToBytecode_.at(gate); - auto offset = builder_->GetPcOffset(bcIndex); - const MethodLiteral *methodLiteral = builder_->GetMethod(); - debugExtractor->MatchLineWithOffset(callbackLineFunc, methodLiteral->GetMethodId(), offset); - - log += "at line: " + std::to_string(lineNumber) + ", "; - } else { - // handle phi gate: print gate id and input gates id list. - log += "phi gate, ins: "; - auto ins = gateAccessor_.ConstIns(gate); - for (auto it = ins.begin(); it != ins.end(); it++) { - log += std::to_string(gateAccessor_.GetId(*it)) + " "; - } - } - - if (!isPGO) { - GateType type = gateAccessor_.GetGateType(gate); - log += "type: " + tsManager_->GetTypeStr(type) + ", "; - if (!tsManager_->IsPrimitiveTypeKind(type)) { - GlobalTSTypeRef gt = type.GetGTRef(); - log += "[moduleId: " + std::to_string(gt.GetModuleId()) + ", "; - log += "localId: " + std::to_string(gt.GetLocalId()) + "], "; - } - } else { - auto pgoType = gateAccessor_.TryGetPGOType(gate); // pgo type - log += "pgoType: " + pgoType.GetPGOSampleType()->ToString() + ", "; - } - - log += "\n[compiler] "; - return log; -} - -void MethodTypeInfer::VerifyTypePercent() -{ - shouldInferNum_ = needInferGates_.size(); - for (auto gate : needInferGates_) { - if (!gateAccessor_.GetGateType(gate).IsAnyType()) { - normalInferNum_++; - } - } - double rate = needInferGates_.empty() ? 0.0 : (double)normalInferNum_ / (double)shouldInferNum_; - auto typeThreshold = tsManager_->GetTypeThreshold(); - if (rate <= typeThreshold) { - methodInfo_->SetTypeInferAbort(true); - } - if (IsLogEnabled()) { - LOG_COMPILER(INFO) << "===================================================================="; - LOG_COMPILER(INFO) << "[TypeCoverage] print method type coverage: \n" - << "[compiler] [TypeCoverage] [ShouldInferedGate]: " << shouldInferNum_ - << " || [NormalInferedGate]: " << normalInferNum_ << "\n" - << "[compiler] [TypeCoverage] [TypeCoverage Percentage]: " - << std::fixed << std::setprecision(PERCENT_LENS) << rate * HUNDRED_TIME << "%"; - if (rate <= typeThreshold) { - LOG_COMPILER(INFO) << "[TypeCoverage] TypeCoverage Percentage is lower than threshold: [" - << typeThreshold << "]"; - } - } -} -} // namespace panda::ecmascript diff --git a/ecmascript/compiler/type_inference/method_type_infer.h b/ecmascript/compiler/type_inference/method_type_infer.h deleted file mode 100644 index 020e0417c4a94bd6d0f16ac718cd9f4e8c2fd64b..0000000000000000000000000000000000000000 --- a/ecmascript/compiler/type_inference/method_type_infer.h +++ /dev/null @@ -1,197 +0,0 @@ -/* - * Copyright (c) 2022 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. - */ - -#ifndef ECMASCRIPT_COMPILER_TYPE_INFERENCE_METHOD_TYPE_INFER_H -#define ECMASCRIPT_COMPILER_TYPE_INFERENCE_METHOD_TYPE_INFER_H - -#include "ecmascript/compiler/argument_accessor.h" -#include "ecmascript/compiler/bytecode_circuit_builder.h" -#include "ecmascript/compiler/compiler_log.h" -#include "ecmascript/compiler/circuit.h" -#include "ecmascript/compiler/gate_accessor.h" -#include "ecmascript/compiler/pass_manager.h" -#include "ecmascript/ts_types/ts_manager.h" - -namespace panda::ecmascript::kungfu { -enum InferState : uint8_t { - // loop-begin gate has been infered to non-any type - NORMAL_INFERED = 0, - // loop-begin gate has been fixed to any type manually and it should not be infered to other types - ANY_INFERED, - // the number-types of loop-begin gate under this state should be promoted to number type - NUMBER_INFERED, -}; - -class MethodTypeInfer { -public: - MethodTypeInfer(BytecodeCircuitBuilder *builder, Circuit *circuit, - PassContext *ctx, size_t methodId, bool enableLog, - const std::string &name, const CString &recordName, - MethodInfo *methodInfo, const MethodLiteral *methodLiteral, - bool enableGlobalTypeInfer, bool hasType); - ~MethodTypeInfer() = default; - - NO_COPY_SEMANTIC(MethodTypeInfer); - NO_MOVE_SEMANTIC(MethodTypeInfer); - - std::pair TraverseInfer(); - void CheckAndPrint(); - void SetNamespaceArgType(GateType type); - - bool IsLogEnabled() const - { - return enableLog_; - } - -private: - static constexpr int PERCENT_LENS = 2; - static constexpr int HUNDRED_TIME = 100; - - const std::string &GetMethodName() const - { - return methodName_; - } - - // savePreType: save the previous type, which is true by default - bool UpdateType(GateRef gate, const GateType type, bool savePreType = true); - bool UpdateType(GateRef gate, const GlobalTSTypeRef &typeRef, bool savePreType = true); - GateType HandleTypeCompatibility(const GateType preType, const GateType type) const; - bool ShouldInfer(const GateRef gate) const; - bool Infer(GateRef gate); - bool InferPhiGate(GateRef gate); - bool SetIntType(GateRef gate); - bool SetNumberType(GateRef gate); - bool SetBigIntType(GateRef gate); - bool SetBooleanType(GateRef gate); - bool InferLdUndefined(GateRef gate); - bool InferLdNull(GateRef gate); - bool InferLdai(GateRef gate); - bool InferFLdai(GateRef gate); - bool InferLdSymbol(GateRef gate); - bool InferThrow(GateRef gate); - bool InferTypeOf(GateRef gate); - bool InferAdd2(GateRef gate); - bool InferSub2(GateRef gate); - bool InferMul2(GateRef gate); - bool InferMod2(GateRef gate); - bool InferDiv2(GateRef gate); - bool InferIncDec(GateRef gate); - bool InferToNumberic(GateRef gate); - bool InferLdObjByIndex(GateRef gate); - bool InferLdGlobalVar(GateRef gate); - bool InferReturnUndefined(GateRef gate); - bool InferReturn(GateRef gate); - bool InferLdObjByName(GateRef gate); - bool InferNewObject(GateRef gate); - bool SetStGlobalBcType(GateRef gate, bool hasIC = false); - bool InferLdStr(GateRef gate); - bool InferCallFunction(GateRef gate); - bool InferCallMethod(GateRef gate); - bool InferLdObjByValue(GateRef gate); - bool InferGetNextPropName(GateRef gate); - bool InferDefineGetterSetterByValue(GateRef gate); - bool InferSuperCall(GateRef gate); - bool InferSuperPropertyByName(GateRef gate); - bool InferSuperPropertyByValue(GateRef gate); - bool InferTryLdGlobalByName(GateRef gate); - bool InferLdLexVarDyn(GateRef gate); - bool InferStLexVarDyn(GateRef gate); - bool InferStModuleVar(GateRef gate); - bool InferLdLocalModuleVar(GateRef gate); - bool InferLdExternalModuleVar(GateRef gate); - bool InferStObjByName(GateRef gate); - bool IsNewLexEnv(EcmaOpcode opcode) const; - bool InferGetIterator(GateRef gate); - bool InferLoopBeginPhiGate(GateRef gate); - bool GetObjPropWithName(GateRef gate, GateType objType, uint64_t index); - bool GetSuperProp(GateRef gate, uint64_t index, bool isString = true); - GlobalTSTypeRef ConvertPrimitiveToBuiltin(const GateType &gateType); - GlobalTSTypeRef GetPropType(const GateType type, const JSTaggedValue propertyName) const; - GlobalTSTypeRef GetPropType(const GateType type, const uint64_t key) const; - void UpdateQueueForLoopPhi(); - - inline bool ShouldInferWithLdObjByValue(const GateType &type) const - { - auto flag = tsManager_->IsObjectTypeKind(type) || - tsManager_->IsClassTypeKind(type) || - tsManager_->IsClassInstanceTypeKind(type); - return flag; - } - - inline bool ShouldInferWithLdObjByName(const GateType &type) const - { - return ShouldInferWithLdObjByValue(type) || tsManager_->IsIteratorInstanceTypeKind(type) || - tsManager_->IsInterfaceTypeKind(type) || tsManager_->IsNamespaceTypeKind(type); - } - - inline bool ShouldConvertToBuiltinArray(const GateType &type) const - { - return tsManager_->IsArrayTypeKind(type) && tsManager_->IsBuiltinsDTSEnabled(); - } - - void PrintTypeAnnotation() const; - void PrintByteCodesWithTypes() const; - void PrintCircuitWithTypes() const; - void Verify() const; - void VerifyTypePercent(); - void TypeCheck(GateRef gate) const; - void PGOTypeCheck(GateRef gate) const; - void Enqueue(GateRef gate); - - std::string CollectGateTypeLogInfo(GateRef gate, DebugInfoExtractor *debugExtractor, - const std::string &logPreFix, bool isPGO) const; - - const BytecodeInfo &GetByteCodeInfo(const GateRef gate) const - { - const auto bcIndex = jsgateToBytecode_.at(gate); - return builder_->GetBytecodeInfo(bcIndex); - } - - std::pair SetAndReturnNamespaceObjType(GateRef gate); - GlobalTSTypeRef TryGetNamespaceType(GateRef gate) const; - bool IsNamespace(GateRef gate) const; - bool CheckNamespaceFunc(GateRef func) const; - - bool IsByteCodeGate(const GateRef gate) const - { - return jsgateToBytecode_.find(gate) != jsgateToBytecode_.end(); - } - - BytecodeCircuitBuilder *builder_ {nullptr}; - Circuit *circuit_ {nullptr}; - GateAccessor gateAccessor_; - TSManager *tsManager_ {nullptr}; - PassContext *ctx_ {nullptr}; - LexEnvManager *lexEnvManager_ {nullptr}; - size_t methodId_ {0}; - bool enableLog_ {false}; - std::string methodName_; - std::map stringIdToGateType_; - std::unordered_map jsgateToBytecode_ {}; - std::map loopPhiState_ {}; - const CString &recordName_; - size_t shouldInferNum_ {0}; - size_t normalInferNum_ {0}; - MethodInfo *methodInfo_ {nullptr}; - const MethodLiteral *methodLiteral_ {nullptr}; - std::vector inQueue_; - std::unordered_set needInferGates_ {}; - std::queue pendingQueue_ {}; - bool needUpdateForLoopPhi_ {true}; - bool enableGlobalTypeInfer_ {false}; - bool hasType_ {false}; -}; -} // namespace panda::ecmascript::kungfu -#endif // ECMASCRIPT_COMPILER_TYPE_INFERENCE_METHOD_TYPE_INFER_H diff --git a/ecmascript/compiler/type_inference/pgo_type_infer.cpp b/ecmascript/compiler/type_inference/pgo_type_infer.cpp index 396dea7f36630e5f83460ec699279dee0b20637d..18ebf39bd9e0e4e89de4bfe3ce177111b84da50c 100644 --- a/ecmascript/compiler/type_inference/pgo_type_infer.cpp +++ b/ecmascript/compiler/type_inference/pgo_type_infer.cpp @@ -262,7 +262,7 @@ void PGOTypeInfer::UpdateTypeForRWOp(GateRef gate, GateRef receiver, uint32_t pr JSTaggedValue prop = JSTaggedValue::Undefined(); if (propIndex != INVALID_INDEX) { auto methodOffset = acc_.TryGetMethodOffset(gate); - prop = tsManager_->GetStringFromConstantPool(methodOffset, propIndex); + prop = ptManager_->GetStringFromConstantPool(methodOffset, propIndex); } ChunkSet inferTypes = helper_.GetInferTypes(chunk_, types, prop); AddProfiler(gate, tsType, *pgoRwTypes, inferTypes); diff --git a/ecmascript/compiler/type_inference/pgo_type_infer.h b/ecmascript/compiler/type_inference/pgo_type_infer.h index 86e3308bdb7378379fc99bc4d0902c267b713089..e99d2f4c434c182e04234688539cd68080756749 100644 --- a/ecmascript/compiler/type_inference/pgo_type_infer.h +++ b/ecmascript/compiler/type_inference/pgo_type_infer.h @@ -25,10 +25,11 @@ namespace panda::ecmascript::kungfu { struct CollectedType; class PGOTypeInfer { public: - PGOTypeInfer(Circuit *circuit, TSManager *tsManager, BytecodeCircuitBuilder *builder, + PGOTypeInfer(Circuit *circuit, TSManager *tsManager, PGOTypeManager *ptManager, BytecodeCircuitBuilder *builder, const std::string &name, Chunk *chunk, bool enableLog) - : circuit_(circuit), acc_(circuit), argAcc_(circuit), tsManager_(tsManager), helper_(tsManager), - builder_(builder), methodName_(name), chunk_(chunk), enableLog_(enableLog), profiler_(chunk) {} + : circuit_(circuit), acc_(circuit), argAcc_(circuit), tsManager_(tsManager), + ptManager_(ptManager), helper_(tsManager), builder_(builder), methodName_(name), chunk_(chunk), + enableLog_(enableLog), profiler_(chunk) {} ~PGOTypeInfer() = default; void Run(); @@ -88,6 +89,7 @@ private: GateAccessor acc_; ArgumentAccessor argAcc_; TSManager *tsManager_ {nullptr}; + PGOTypeManager *ptManager_ {nullptr}; PGOTypeInferHelper helper_; BytecodeCircuitBuilder *builder_ {nullptr}; const std::string &methodName_; diff --git a/ecmascript/compiler/type_info_accessors.cpp b/ecmascript/compiler/type_info_accessors.cpp index ba4304ab1aa492c300c73c320c5fb6cba7b9e30c..c55eb484fff2c992971da14f2bc05e9482fad4cf 100644 --- a/ecmascript/compiler/type_info_accessors.cpp +++ b/ecmascript/compiler/type_info_accessors.cpp @@ -19,41 +19,84 @@ #include "ecmascript/compiler/circuit.h" #include "ecmascript/global_env.h" #include "ecmascript/global_env_fields.h" -#include "ecmascript/js_hclass-inl.h" -#include "ecmascript/jspandafile/js_pandafile.h" #include "ecmascript/jspandafile/program_object.h" #include "ecmascript/ts_types/ts_type_accessor.h" namespace panda::ecmascript::kungfu { JSTaggedValue TypeInfoAccessor::GetStringFromConstantPool(const JSThread *thread, uint32_t methodId, uint32_t index) { - return thread->GetCurrentEcmaContext()->GetTSManager()->GetStringFromConstantPool(methodId, index); + return thread->GetCurrentEcmaContext()->GetPTManager()->GetStringFromConstantPool(methodId, index); +} + +ParamType TypeInfoAccessor::PGOSampleTypeToParamType() const +{ + if (pgoType_.IsPGOSampleType()) { + auto sample = pgoType_.GetPGOSampleType(); + if (sample->IsInt()) { + return ParamType::IntType(); + } else if (sample->IsIntOverFlow()) { + return ParamType::IntOverflowType(); + } else if (sample->IsDouble()) { + return ParamType::DoubleType(); + } else if (sample->IsString()) { + return ParamType::StringType(); + } else if (sample->IsBigInt()) { + return ParamType::BigIntType(); + } else if (sample->IsBoolean()) { + return ParamType::BooleanType(); + } else if (sample->IsNumber()) { + return ParamType::NumberType(); + } + } + return ParamType::AnyType(); +} + +ParamType TypeInfoAccessor::PGOBuiltinTypeToParamType(ProfileType pgoType) +{ + if (pgoType.IsBuiltinsType()) { + return ParamType(pgoType.GetBuiltinsType()); + } + return ParamType::AnyType(); } // TypeTrusted means the type of gate is already PrimitiveTypeCheck-passed, // or the gate is constant and no need to check. -bool TypeInfoAccessor::IsTrustedType(GateAccessor acc, GateRef gate) +bool TypeInfoAccessor::IsTrustedBooleanType(GateAccessor acc, GateRef gate) { - if (acc.IsConstant(gate)) { + if (acc.IsConstant(gate) && acc.GetGateType(gate).IsBooleanType()) { return true; } auto op = acc.GetOpCode(gate); - if (acc.IsTypedOperator(gate)) { - if (op == OpCode::TYPED_BINARY_OP) { - return !acc.GetGateType(gate).IsIntType(); - } else { - return true; + if (op == OpCode::TYPED_BINARY_OP) { + TypedBinaryAccessor accessor(acc.TryGetValue(gate)); + TypedBinOp binOp = accessor.GetTypedBinOp(); + switch (binOp) { + case TypedBinOp::TYPED_EQ: + case TypedBinOp::TYPED_LESS: + case TypedBinOp::TYPED_NOTEQ: + case TypedBinOp::TYPED_LESSEQ: + case TypedBinOp::TYPED_GREATER: + case TypedBinOp::TYPED_STRICTEQ: + case TypedBinOp::TYPED_GREATEREQ: + case TypedBinOp::TYPED_STRICTNOTEQ: + return true; + default: + return false; + } + } else if (op == OpCode::TYPED_UNARY_OP) { + TypedUnaryAccessor accessor(acc.TryGetValue(gate)); + TypedUnOp unOp = accessor.GetTypedUnOp(); + switch (unOp) { + case TypedUnOp::TYPED_ISTRUE: + case TypedUnOp::TYPED_ISFALSE: + return true; + default: + return false; } } if (op == OpCode::JS_BYTECODE) { EcmaOpcode ecmaOpcode = acc.GetByteCodeOpcode(gate); switch (ecmaOpcode) { - case EcmaOpcode::ADD2_IMM8_V8: - case EcmaOpcode::SUB2_IMM8_V8: - case EcmaOpcode::MUL2_IMM8_V8: - return !acc.GetGateType(gate).IsIntType(); - case EcmaOpcode::INC_IMM8: - case EcmaOpcode::DEC_IMM8: case EcmaOpcode::LESS_IMM8_V8: case EcmaOpcode::LESSEQ_IMM8_V8: case EcmaOpcode::GREATER_IMM8_V8: @@ -72,6 +115,90 @@ bool TypeInfoAccessor::IsTrustedType(GateAccessor acc, GateRef gate) return false; } +bool TypeInfoAccessor::IsTrustedNumberType(GateAccessor acc, GateRef gate) +{ + if (acc.IsConstant(gate) && acc.GetGateType(gate).IsNumberType()) { + return true; + } + auto op = acc.GetOpCode(gate); + if (op == OpCode::TYPED_BINARY_OP) { + TypedBinaryAccessor accessor(acc.TryGetValue(gate)); + TypedBinOp binOp = accessor.GetTypedBinOp(); + switch (binOp) { + case TypedBinOp::TYPED_ADD: + case TypedBinOp::TYPED_SUB: + case TypedBinOp::TYPED_MUL: + case TypedBinOp::TYPED_DIV: + case TypedBinOp::TYPED_MOD: + case TypedBinOp::TYPED_SHL: + case TypedBinOp::TYPED_SHR: + case TypedBinOp::TYPED_ASHR: + case TypedBinOp::TYPED_AND: + case TypedBinOp::TYPED_OR: + case TypedBinOp::TYPED_XOR: + return accessor.GetParamType().HasNumberType(); + default: + return false; + } + } else if (op == OpCode::TYPED_UNARY_OP) { + TypedUnaryAccessor accessor(acc.TryGetValue(gate)); + TypedUnOp unOp = accessor.GetTypedUnOp(); + switch (unOp) { + case TypedUnOp::TYPED_DEC: + case TypedUnOp::TYPED_INC: + case TypedUnOp::TYPED_NEG: + case TypedUnOp::TYPED_NOT: + return accessor.GetParamType().HasNumberType(); + default: + return false; + } + } else if (op == OpCode::TYPE_CONVERT) { + // typeconvert only use in tomumeric + return true; + } else if (op == OpCode::LOAD_ELEMENT) { + auto loadOp = acc.GetTypedLoadOp(gate); + switch (loadOp) { + case TypedLoadOp::INT8ARRAY_LOAD_ELEMENT: + case TypedLoadOp::UINT8ARRAY_LOAD_ELEMENT: + case TypedLoadOp::UINT8CLAMPEDARRAY_LOAD_ELEMENT: + case TypedLoadOp::INT16ARRAY_LOAD_ELEMENT: + case TypedLoadOp::UINT16ARRAY_LOAD_ELEMENT: + case TypedLoadOp::INT32ARRAY_LOAD_ELEMENT: + case TypedLoadOp::UINT32ARRAY_LOAD_ELEMENT: + case TypedLoadOp::FLOAT32ARRAY_LOAD_ELEMENT: + case TypedLoadOp::FLOAT64ARRAY_LOAD_ELEMENT: + return true; + default: + return false; + } + } + + if (op == OpCode::JS_BYTECODE) { + EcmaOpcode ecmaOpcode = acc.GetByteCodeOpcode(gate); + switch (ecmaOpcode) { + case EcmaOpcode::ADD2_IMM8_V8: + case EcmaOpcode::SUB2_IMM8_V8: + case EcmaOpcode::MUL2_IMM8_V8: + case EcmaOpcode::DIV2_IMM8_V8: + case EcmaOpcode::MOD2_IMM8_V8: + case EcmaOpcode::SHL2_IMM8_V8: + case EcmaOpcode::SHR2_IMM8_V8: + case EcmaOpcode::ASHR2_IMM8_V8: + case EcmaOpcode::AND2_IMM8_V8: + case EcmaOpcode::OR2_IMM8_V8: + case EcmaOpcode::XOR2_IMM8_V8: + case EcmaOpcode::INC_IMM8: + case EcmaOpcode::DEC_IMM8: + case EcmaOpcode::NEG_IMM8: + case EcmaOpcode::NOT_IMM8: + return acc.TryGetPGOType(gate).GetPGOSampleType()->HasNumber(); + default: + break; + } + } + return false; +} + bool TypeInfoAccessor::IsTrustedStringType( const JSThread *thread, Circuit *circuit, Chunk *chunk, GateAccessor acc, GateRef gate) { @@ -102,71 +229,6 @@ bool TypeInfoAccessor::IsTrustedStringType( return false; } -BinOpTypeInfoAccessor::BinOpTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate, bool convertNumberType) - : TypeInfoAccessor(thread, circuit, gate), convertNumberType_(convertNumberType) -{ - left_ = acc_.GetValueIn(gate, 0); // 0: left - right_ = acc_.GetValueIn(gate, 1); // 1: right -} - -bool BinOpTypeInfoAccessor::HasNumberType() const -{ - GateType leftType = acc_.GetGateType(left_); - GateType rightType = acc_.GetGateType(right_); - - const PGOSampleType *sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); - if (sampleType->IsNumber()) { - return true; - } else if (convertNumberType_ && sampleType->IsNone() && leftType.IsPrimitiveNumberType() && - rightType.IsPrimitiveNumberType()) { - return true; - } else if (!convertNumberType_ && sampleType->IsNone() && leftType.IsNumberType() && rightType.IsNumberType()) { - return true; - } else { - return false; - } - return false; -} - -bool BinOpTypeInfoAccessor::HasStringType() const -{ - const PGOSampleType *sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); - return sampleType->IsString(); -} - -UnOpTypeInfoAccessor::UnOpTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : TypeInfoAccessor(thread, circuit, gate) -{ - value_ = acc_.GetValueIn(gate, 0); // 0: value -} - -bool UnOpTypeInfoAccessor::ValueIsNumberType() const -{ - const PGOSampleType *sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); - if (sampleType->IsNumber()) { - return true; - } - return false; -} - -GateType UnOpTypeInfoAccessor::FetchNumberType() const -{ - const PGOSampleType *sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); - if (sampleType->IsNumber()) { - if (sampleType->IsInt()) { - return GateType::IntType(); - } else if (sampleType->IsDouble()) { - return GateType::DoubleType(); - } else { - return GateType::NumberType(); - } - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } -} - bool NewObjRangeTypeInfoAccessor::FindHClass() { auto sampleType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); @@ -183,15 +245,7 @@ bool NewObjRangeTypeInfoAccessor::FindHClass() bool TypeOfTypeInfoAccessor::IsIllegalType() const { - GateType valueType = GetValueGateType(); - if (!valueType.IsDigitablePrimitiveType() && !valueType.IsStringType() && !valueType.IsSymbolType()) { - if (!tsManager_->IsFunctionTypeKind(valueType) && !tsManager_->IsObjectTypeKind(valueType) && - !tsManager_->IsClassTypeKind(valueType) && !tsManager_->IsClassInstanceTypeKind(valueType) && - !tsManager_->IsArrayTypeKind(valueType)) { - return true; - } - } - return false; + return true; } SuperCallTypeInfoAccessor::SuperCallTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) @@ -200,7 +254,7 @@ SuperCallTypeInfoAccessor::SuperCallTypeInfoAccessor(const JSThread *thread, Cir ctor_ = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); } -BuiltinsStubCSigns::ID CallTypeInfoAccessor::TryGetPGOBuiltinId() const +BuiltinsStubCSigns::ID CallTypeInfoAccessor::TryGetPGOBuiltinMethodId() const { PGOTypeRef sampleType = acc_.TryGetPGOType(gate_); if (sampleType.GetPGOSampleType()->IsNone()) { @@ -212,55 +266,56 @@ BuiltinsStubCSigns::ID CallTypeInfoAccessor::TryGetPGOBuiltinId() const return BuiltinsStubCSigns::ID::NONE; } -BuiltinsStubCSigns::ID CallTypeInfoAccessor::TryGetBuiltinId(BuiltinTypeId id) const -{ - GateType funcType = acc_.GetGateType(func_); - if (!tsManager_->IsBuiltinObjectMethod(id, funcType)) { - return BuiltinsStubCSigns::ID::NONE; - } - std::string name = tsManager_->GetFuncName(funcType); - BuiltinsStubCSigns::ID stubId = BuiltinsStubCSigns::GetBuiltinId(name); - return stubId; -} - -GetIteratorTypeInfoAccessor::GetIteratorTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallTypeInfoAccessor(thread, circuit, gate) +GetIteratorTypeInfoAccessor::GetIteratorTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 0; // 0: number of argc func_ = acc_.GetValueIn(gate, 0); // 1: func } -CallArg0TypeInfoAccessor::CallArg0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallTypeInfoAccessor(thread, circuit, gate) +CallArg0TypeInfoAccessor::CallArg0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 0; // 0: number of argc func_ = acc_.GetValueIn(gate, 0); // 0: func } -CallArg1TypeInfoAccessor::CallArg1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallTypeInfoAccessor(thread, circuit, gate) +CallArg1TypeInfoAccessor::CallArg1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 1; // 1: number of argc value_ = acc_.GetValueIn(gate, 0); // 0: value func_ = acc_.GetValueIn(gate, 1); // 1: func } -CallArg2TypeInfoAccessor::CallArg2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallTypeInfoAccessor(thread, circuit, gate) +CallArg2TypeInfoAccessor::CallArg2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 2; // 2: number of argc func_ = acc_.GetValueIn(gate, 2); // 2: func } -CallArg3TypeInfoAccessor::CallArg3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallTypeInfoAccessor(thread, circuit, gate) +CallArg3TypeInfoAccessor::CallArg3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 3; // 3: number of argc func_ = acc_.GetValueIn(gate, 3); // 3: func } -CallRangeTypeInfoAccessor::CallRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallTypeInfoAccessor(thread, circuit, gate) +CallRangeTypeInfoAccessor::CallRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { size_t numArgs = acc_.GetNumValueIn(gate); constexpr size_t callTargetIndex = 1; // acc @@ -270,51 +325,64 @@ CallRangeTypeInfoAccessor::CallRangeTypeInfoAccessor(const JSThread *thread, Cir bool CallThisTypeInfoAccessor::CanOptimizeAsFastCall() { - GateType funcType = acc_.GetGateType(func_); - if (!tsManager_->IsFunctionTypeKind(funcType)) { - return false; - } + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); auto op = acc_.GetOpCode(func_); - if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func_)) { + if (!IsValidCallMethodId()) { return false; } - return true; + if (!profileType->IsNone()) { + if (profileType->IsProfileTypeNone() || op != OpCode::LOAD_PROPERTY) { + return false; + } + return true; + } + return false; } -CallThis0TypeInfoAccessor::CallThis0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallThisTypeInfoAccessor(thread, circuit, gate) +CallThis0TypeInfoAccessor::CallThis0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallThisTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 0; // 0: number of argc func_ = acc_.GetValueIn(gate, 1); // 1: func } -CallThis1TypeInfoAccessor::CallThis1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallThisTypeInfoAccessor(thread, circuit, gate) +CallThis1TypeInfoAccessor::CallThis1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallThisTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 1; // 1: number of argc func_ = acc_.GetValueIn(gate, 2); // 2: func a0_ = acc_.GetValueIn(gate, 1); // 1: arg0 } -CallThis2TypeInfoAccessor::CallThis2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallThisTypeInfoAccessor(thread, circuit, gate) +CallThis2TypeInfoAccessor::CallThis2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallThisTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 2; // 2: number of argc func_ = acc_.GetValueIn(gate, 3); // 3: func } -CallThis3TypeInfoAccessor::CallThis3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallThisTypeInfoAccessor(thread, circuit, gate) +CallThis3TypeInfoAccessor::CallThis3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallThisTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { argc_ = 3; // 3: number of argc - func_ = acc_.GetValueIn(gate, 3); // 3: func + func_ = acc_.GetValueIn(gate, 4); // 4: func a0_ = acc_.GetValueIn(gate, 1); // 1: arg0 a1_ = acc_.GetValueIn(gate, 2); // 2: arg1 a2_ = acc_.GetValueIn(gate, 3); // 3: arg2 } -CallThisRangeTypeInfoAccessor::CallThisRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate) - : CallThisTypeInfoAccessor(thread, circuit, gate) +CallThisRangeTypeInfoAccessor::CallThisRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, GateRef gate, + const JSPandaFile *jsPandaFile, + const CallMethodFlagMap *callMethodFlagMap) + : CallThisTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { constexpr size_t fixedInputsNum = 1; constexpr size_t callTargetIndex = 1; // 1: acc @@ -353,7 +421,7 @@ PropertyLookupResult InlineTypeInfoAccessor::GetAccessorPlr() const GateRef constData = acc_.GetValueIn(gate_, 1); uint16_t propIndex = acc_.GetConstantValue(constData); auto methodOffset = acc_.TryGetMethodOffset(gate_); - auto prop = tsManager_->GetStringFromConstantPool(methodOffset, propIndex); + auto prop = ptManager_->GetStringFromConstantPool(methodOffset, propIndex); // PGO currently does not support call, so GT is still used to support inline operations. // However, the original GT solution cannot support accessing the property of prototype, so it is filtered here if (EcmaStringAccessor(prop).ToStdString() == "prototype") { @@ -398,13 +466,11 @@ uint32_t InlineTypeInfoAccessor::GetCallMethodId() const return methodOffset; } } - if (methodOffset == 0) { - if (IsFunctionTypeKind()) { - auto funcGT = GetReceiverGT().GetGTRef(); - methodOffset = tsManager_->GetFuncMethodOffset(funcGT); - } else if (IsClassInstanceTypeKind()) { - auto funcGT = GetAccessorFuncGT(); - methodOffset = tsManager_->GetFuncMethodOffset(funcGT); + if (IsCallAccessor()) { + const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType(); + auto pgoType = pgoTypes->GetObjectInfo(0); + if (pgoType.GetAccessorMethod().GetProfileType().IsValidCallMethodId()) { + return pgoType.GetAccessorMethod().GetProfileType().GetCallMethodId(); } } return methodOffset; @@ -687,13 +753,13 @@ LoadBulitinObjTypeInfoAccessor::LoadBulitinObjTypeInfoAccessor(const JSThread *t FetchBuiltinsTypes(); } -bool AccBuiltinObjTypeInfoAccessor::IsAllString() const +bool AccBuiltinObjTypeInfoAccessor::IsMonoBuiltins() const { - if (types_.empty()) { + if (types_.size() == 0) { return false; } - for (auto type : types_) { - if (!type.IsBuiltinsString()) { + for (size_t i = 0; i < types_.size(); i++) { + if (!types_[0].IsBuiltinsType()) { return false; } } @@ -771,8 +837,8 @@ void CreateObjWithBufferTypeInfoAccessor::Init() { auto imm = acc_.GetConstantValue(index_); auto methodOffset = acc_.TryGetMethodOffset(GetGate()); - JSTaggedValue cp = tsManager_->GetConstantPool(methodOffset); - JSTaggedValue unsharedCp = thread_->GetCurrentEcmaContext()->FindUnsharedConstpool(cp); + JSTaggedValue cp = ptManager_->GetConstantPoolByMethodOffset(methodOffset); + JSTaggedValue unsharedCp = thread_->GetCurrentEcmaContext()->FindOrCreateUnsharedConstpool(cp); JSTaggedValue obj = ConstantPool::GetLiteralFromCache( tsManager_->GetEcmaVM()->GetJSThread(), unsharedCp, imm, recordName_); objHandle_ = JSHandle(thread_, obj); diff --git a/ecmascript/compiler/type_info_accessors.h b/ecmascript/compiler/type_info_accessors.h index 0bdf83cd3463f5716af2a6bcf1497627e8142b20..a424068439dd11978ae6d3394fea8ddf0afc19df 100644 --- a/ecmascript/compiler/type_info_accessors.h +++ b/ecmascript/compiler/type_info_accessors.h @@ -16,10 +16,14 @@ #ifndef ECMASCRIPT_COMPILER_TYPE_INFO_ACCESSORS_H #define ECMASCRIPT_COMPILER_TYPE_INFO_ACCESSORS_H +#include "ecmascript/compiler/aot_compiler_preprocessor.h" #include "ecmascript/compiler/argument_accessor.h" #include "ecmascript/compiler/pgo_type/pgo_type_manager.h" #include "ecmascript/enum_conversion.h" +#include "ecmascript/global_index.h" +#include "ecmascript/jspandafile/program_object.h" #include "ecmascript/ts_types/ts_manager.h" +#include "libpandafile/index_accessor.h" namespace panda::ecmascript::kungfu { class TypeInfoAccessor { @@ -30,21 +34,20 @@ public: argAcc_(circuit), gate_(gate) { + pgoType_ = acc_.TryGetPGOType(gate); + // NOTICE-PGO: wx delete in part3 tsManager_ = thread_->GetCurrentEcmaContext()->GetTSManager(); ptManager_ = thread_->GetCurrentEcmaContext()->GetPTManager(); } - GateRef GetGate() const + inline GateRef GetGate() const { return gate_; } - PGOTypeRef GetPGOType() const - { - return acc_.TryGetPGOType(GetGate()); - } + static bool IsTrustedBooleanType(GateAccessor acc, GateRef gate); - static bool IsTrustedType(GateAccessor acc, GateRef gate); + static bool IsTrustedNumberType(GateAccessor acc, GateRef gate); static bool IsTrustedStringType( const JSThread *thread, Circuit *circuit, Chunk *chunk, GateAccessor acc, GateRef gate); @@ -52,10 +55,15 @@ public: static JSTaggedValue GetStringFromConstantPool(const JSThread *thread, uint32_t methodId, uint32_t index); protected: + ParamType PGOSampleTypeToParamType() const; + static ParamType PGOBuiltinTypeToParamType(ProfileType pgoType); + const JSThread *thread_ {nullptr}; GateAccessor acc_; ArgumentAccessor argAcc_; GateRef gate_; + PGOTypeRef pgoType_; + // NOTICE-PGO: wx delete in part3 TSManager *tsManager_ {nullptr}; PGOTypeManager *ptManager_ {nullptr}; }; @@ -64,22 +72,46 @@ class BinOpTypeInfoAccessor final : public TypeInfoAccessor { public: BinOpTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate, - bool convertNumberType = false); + GateRef gate) + : TypeInfoAccessor(thread, circuit, gate) + { + left_ = acc_.GetValueIn(gate, 0); // 0: left + right_ = acc_.GetValueIn(gate, 1); // 1: right + } NO_COPY_SEMANTIC(BinOpTypeInfoAccessor); NO_MOVE_SEMANTIC(BinOpTypeInfoAccessor); - bool HasNumberType() const; + inline GateRef GetLeftGate() const + { + return left_; + } + + inline GateRef GetReightGate() const + { + return right_; + } + + inline bool HasNumberType() const + { + return pgoType_.HasNumber(); + } - bool HasStringType() const; + inline bool IsStringType() const + { + return pgoType_.IsString(); + } - bool LeftOrRightIsUndefinedOrNullOrHole() const + inline bool LeftOrRightIsUndefinedOrNull() const { return acc_.IsUndefinedOrNullOrHole(left_) || acc_.IsUndefinedOrNullOrHole(right_); } + inline ParamType GetParamType() const + { + return PGOSampleTypeToParamType(); + } + private: - bool convertNumberType_; GateRef left_; GateRef right_; }; @@ -88,27 +120,32 @@ class UnOpTypeInfoAccessor : public TypeInfoAccessor { public: UnOpTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate) + : TypeInfoAccessor(thread, circuit, gate) + { + value_ = acc_.GetValueIn(gate, 0); // 0: value + } NO_COPY_SEMANTIC(UnOpTypeInfoAccessor); NO_MOVE_SEMANTIC(UnOpTypeInfoAccessor); - bool ValueIsNumberType() const; - - GateType FetchNumberType() const; + inline GateRef GetValue() const + { + return value_; + } - bool ValueIsPrimitiveNumberType() const + inline bool HasNumberType() const { - return GetValueGateType().IsPrimitiveNumberType(); + return pgoType_.HasNumber(); } - bool ValueIsBooleanType() const + inline bool IsBooleanType() const { - return GetValueGateType().IsBooleanType(); + return pgoType_.IsBoolean(); } - GateRef GetValue() const + inline ParamType GetParamType() const { - return value_; + return PGOSampleTypeToParamType(); } GateType GetValueGateType() const @@ -206,9 +243,9 @@ public: return tsManager_->IsClassTypeKind(acc_.GetGateType(ctor_)); } - bool IsFunctionTypeKind() const + bool IsValidCallMethodId() const { - return tsManager_->IsFunctionTypeKind(acc_.GetGateType(ctor_)); + return pgoType_.IsValidCallMethodId(); } GateRef GetCtor() const @@ -224,10 +261,14 @@ class CallTypeInfoAccessor : public TypeInfoAccessor { public: CallTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate) + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr) : TypeInfoAccessor(thread, circuit, gate), argc_(0), - func_(Circuit::NullGate()) + func_(Circuit::NullGate()), + jsPandaFile_(jsPandaFile), + callMethodFlagMap_(callMethodFlagMap) {} size_t GetArgc() const @@ -245,70 +286,128 @@ public: return acc_.GetGateType(func_); } - bool IsFunctionTypeKind() const + bool IsValidCallMethodId() const { - return tsManager_->IsFunctionTypeKind(acc_.GetGateType(func_)); + return pgoType_.IsValidCallMethodId(); } bool IsHotnessFunc() const { - return tsManager_->IsHotnessFunc(GetFunctionGT()); + if (jsPandaFile_ == nullptr || callMethodFlagMap_ == nullptr) { + return false; + } + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); + bool haveProfileType = !profileType->IsNone(); + if (haveProfileType) { + CString fileDesc = jsPandaFile_->GetNormalizedFileDesc(); + uint32_t methodId = profileType->GetProfileType().GetId(); + return callMethodFlagMap_->IsAotCompile(fileDesc, methodId); + } + return false; } uint32_t GetFunctionTypeLength() const { - return tsManager_->GetFunctionTypeLength(GetFunctionGT()); + if (jsPandaFile_ == nullptr || callMethodFlagMap_ == nullptr) { + return false; + } + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); + bool haveProfileType = !profileType->IsNone(); + if (haveProfileType) { + uint32_t methodId = profileType->GetProfileType().GetId(); + MethodLiteral *targetMethodLiteral = jsPandaFile_->FindMethodLiteral(methodId); + return targetMethodLiteral->GetNumArgsWithCallField(); + } + return 0; } bool IsNoGC() const { - return tsManager_->IsNoGC(GetFunctionGT()); - } - - bool FastCallFlagIsVaild() const - { - return tsManager_->FastCallFlagIsVaild(GetFunctionGT()); + if (jsPandaFile_ == nullptr || callMethodFlagMap_ == nullptr) { + return false; + } + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); + bool haveProfileType = !profileType->IsNone(); + if (haveProfileType) { + uint32_t methodId = profileType->GetProfileType().GetId(); + MethodLiteral *targetMethodLiteral = jsPandaFile_->FindMethodLiteral(methodId); + return targetMethodLiteral->IsNoGC(); + } + return false; } int GetMethodIndex() const { - return tsManager_->GetMethodIndex(GetFunctionGT()); + if (jsPandaFile_ == nullptr || callMethodFlagMap_ == nullptr) { + return false; + } + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); + bool haveProfileType = !profileType->IsNone(); + if (haveProfileType) { + uint32_t methodId = profileType->GetProfileType().GetId(); + panda_file::IndexAccessor indexAccessor(*(jsPandaFile_->GetPandaFile()), + panda_file::File::EntityId(methodId)); + uint32_t cpId = static_cast(indexAccessor.GetHeaderIndex()); + JSHandle constpoolHandle(thread_, + thread_->GetCurrentEcmaContext()->FindConstpool(jsPandaFile_, cpId)); + return constpoolHandle->GetMethodIndexByEntityId(panda_file::File::EntityId(methodId)); + } + return 0; } bool MethodOffsetIsVaild() const { - return tsManager_->MethodOffsetIsVaild(GetFunctionGT()); + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); + return !profileType->IsNone(); } bool CanFastCall() const { - return tsManager_->CanFastCall(GetFunctionGT()); + if (jsPandaFile_ == nullptr || callMethodFlagMap_ == nullptr) { + return false; + } + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); + bool haveProfileType = !profileType->IsNone(); + if (haveProfileType) { + CString fileDesc = jsPandaFile_->GetNormalizedFileDesc(); + uint32_t methodId = profileType->GetProfileType().GetId(); + return callMethodFlagMap_->IsAotCompile(fileDesc, methodId) && + callMethodFlagMap_->IsFastCall(fileDesc, methodId); + } + return false; } uint32_t GetFuncMethodOffset() const { - return tsManager_->GetFuncMethodOffset(GetFunctionGT()); + if (jsPandaFile_ == nullptr || callMethodFlagMap_ == nullptr) { + return false; + } + auto profileType = acc_.TryGetPGOType(gate_).GetPGOSampleType(); + bool haveProfileType = !profileType->IsNone(); + if (haveProfileType) { + uint32_t methodId = profileType->GetProfileType().GetId(); + MethodLiteral *targetMethodLiteral = jsPandaFile_->FindMethodLiteral(methodId); + return targetMethodLiteral->GetMethodId().GetOffset(); + } + return 0; } - BuiltinsStubCSigns::ID TryGetPGOBuiltinId() const; - - BuiltinsStubCSigns::ID TryGetBuiltinId(BuiltinTypeId id) const; + BuiltinsStubCSigns::ID TryGetPGOBuiltinMethodId() const; protected: - GlobalTSTypeRef GetFunctionGT() const - { - return acc_.GetGateType(func_).GetGTRef(); - } - size_t argc_; GateRef func_; + const JSPandaFile *jsPandaFile_; + const CallMethodFlagMap *callMethodFlagMap_; }; class GetIteratorTypeInfoAccessor final : public CallTypeInfoAccessor { public: GetIteratorTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(GetIteratorTypeInfoAccessor); NO_MOVE_SEMANTIC(GetIteratorTypeInfoAccessor); @@ -322,7 +421,9 @@ class CallArg0TypeInfoAccessor final : public CallTypeInfoAccessor { public: CallArg0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallArg0TypeInfoAccessor); NO_MOVE_SEMANTIC(CallArg0TypeInfoAccessor); }; @@ -331,7 +432,9 @@ class CallArg1TypeInfoAccessor final : public CallTypeInfoAccessor { public: CallArg1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallArg1TypeInfoAccessor); NO_MOVE_SEMANTIC(CallArg1TypeInfoAccessor); @@ -353,7 +456,9 @@ class CallArg2TypeInfoAccessor final : public CallTypeInfoAccessor { public: CallArg2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallArg2TypeInfoAccessor); NO_MOVE_SEMANTIC(CallArg2TypeInfoAccessor); }; @@ -362,7 +467,9 @@ class CallArg3TypeInfoAccessor final : public CallTypeInfoAccessor { public: CallArg3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallArg3TypeInfoAccessor); NO_MOVE_SEMANTIC(CallArg3TypeInfoAccessor); }; @@ -371,7 +478,9 @@ class CallRangeTypeInfoAccessor final : public CallTypeInfoAccessor { public: CallRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallRangeTypeInfoAccessor); NO_MOVE_SEMANTIC(CallRangeTypeInfoAccessor); }; @@ -380,8 +489,10 @@ class CallThisTypeInfoAccessor : public CallTypeInfoAccessor { public: CallThisTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate) - : CallTypeInfoAccessor(thread, circuit, gate) + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr) + : CallTypeInfoAccessor(thread, circuit, gate, jsPandaFile, callMethodFlagMap) { thisObj_ = acc_.GetValueIn(gate, 0); } @@ -402,7 +513,9 @@ class CallThis0TypeInfoAccessor final : public CallThisTypeInfoAccessor { public: CallThis0TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallThis0TypeInfoAccessor); NO_MOVE_SEMANTIC(CallThis0TypeInfoAccessor); }; @@ -411,7 +524,9 @@ class CallThis1TypeInfoAccessor final : public CallThisTypeInfoAccessor { public: CallThis1TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallThis1TypeInfoAccessor); NO_MOVE_SEMANTIC(CallThis1TypeInfoAccessor); @@ -433,7 +548,9 @@ class CallThis2TypeInfoAccessor final : public CallThisTypeInfoAccessor { public: CallThis2TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallThis2TypeInfoAccessor); NO_MOVE_SEMANTIC(CallThis2TypeInfoAccessor); }; @@ -442,7 +559,9 @@ class CallThis3TypeInfoAccessor final : public CallThisTypeInfoAccessor { public: CallThis3TypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallThis3TypeInfoAccessor); NO_MOVE_SEMANTIC(CallThis3TypeInfoAccessor); @@ -461,7 +580,9 @@ class CallThisRangeTypeInfoAccessor final : public CallThisTypeInfoAccessor { public: CallThisRangeTypeInfoAccessor(const JSThread *thread, Circuit *circuit, - GateRef gate); + GateRef gate, + const JSPandaFile *jsPandaFile = nullptr, + const CallMethodFlagMap *callMethodFlagMap = nullptr); NO_COPY_SEMANTIC(CallThisRangeTypeInfoAccessor); NO_MOVE_SEMANTIC(CallThisRangeTypeInfoAccessor); }; @@ -485,25 +606,21 @@ public: bool IsEnableNormalInline() const { - return IsFunctionTypeKind() || IsValidCallMethodId(); + return IsValidCallMethodId(); } bool IsEnableAccessorInline() const { - if (plr_.IsAccessor() && IsClassInstanceTypeKind()) { - GlobalTSTypeRef gt = GetAccessorFuncGT(); - if (!gt.IsDefault()) { + if (plr_.IsAccessor()) { + const PGORWOpType *pgoTypes = acc_.TryGetPGOType(gate_).GetPGORWOpType(); + auto pgoType = pgoTypes->GetObjectInfo(0); + if (pgoType.GetAccessorMethod().GetProfileType().IsValidCallMethodId()) { return true; } } return false; } - bool IsFunctionTypeKind() const - { - return tsManager_->IsFunctionTypeKind(acc_.GetGateType(receiver_)); - } - bool IsClassInstanceTypeKind() const { return tsManager_->IsClassInstanceTypeKind(acc_.GetGateType(receiver_)); @@ -511,13 +628,13 @@ public: bool IsValidCallMethodId() const { - return GetPGOType().IsValidCallMethodId(); + return pgoType_.IsValidCallMethodId(); } uint32_t GetFuncMethodOffsetFromPGO() const { - if (GetPGOType().IsValidCallMethodId()) { - return GetPGOType().GetCallMethodId(); + if (IsValidCallMethodId()) { + return pgoType_.GetCallMethodId(); } return 0; } @@ -566,16 +683,7 @@ public: uint32_t GetType() const { - uint32_t type = 0; - if (IsFunctionTypeKind()) { - type = GetReceiverGT().Value(); - } - if (type == 0) { - if (IsNormalCall() && IsValidCallMethodId()) { - type = GetPGOType().GetValue(); - } - } - return type; + return GetFuncMethodOffsetFromPGO(); } PropertyLookupResult GetPlr() const @@ -851,8 +959,7 @@ public: bool IsMono() const { - return types_.size() == 1 || - IsAllString(); + return types_.size() == 1 || IsMonoBuiltins(); } size_t GetTypeCount() @@ -870,6 +977,25 @@ public: return types_[0].IsBuiltinsArray(); } + bool IsBuiltinsTypeArray() const + { + return types_[0].IsBuiltinsTypeArray(); + } + + JSType GetBuiltinsJSType() const + { + if (types_[0].IsBuiltinsType()) { + return types_[0].GetBuiltinsType(); + } + return JSType::INVALID; + } + + ParamType GetParamType() const + { + ASSERT(IsMono()); + return TypeInfoAccessor::PGOBuiltinTypeToParamType(types_[0]); + } + bool IsPolyBuiltinsArray() const { if (types_.size() == 0) { @@ -907,11 +1033,14 @@ public: std::optional GetBuiltinsTypeId() const { + if (!IsMono()) { + return std::nullopt; + } auto type = types_[0].GetBuiltinsType(); return ToBuiltinsTypeId(type); } - std::optional GetGlobalsId() const + std::optional GetGlobalsId() const { return types_[0].GetGlobalsId(); } @@ -931,38 +1060,23 @@ public: return static_cast(acc_.GetConstantValue(GetKey())); } - bool KeyIsNumberType() const - { - return acc_.GetGateType(key_).IsNumberType(); - } - - bool IsArrayTypeKind() const - { - return tsManager_->IsArrayTypeKind(GetReceiverGateType()); - } - // Default get is elementsKind before possible transition ElementsKind TryGetArrayElementsKind() const { - [[maybe_unused]] bool condition = IsArrayTypeKind() || (IsMono() && IsBuiltinsArray()); + [[maybe_unused]] bool condition = (IsMono() && IsBuiltinsArray()); ASSERT(condition); return acc_.TryGetArrayElementsKind(gate_); } ElementsKind TryGetArrayElementsKindAfterTransition() const { - [[maybe_unused]] bool condition = IsArrayTypeKind() || (IsMono() && IsBuiltinsArray()); + [[maybe_unused]] bool condition = (IsMono() && IsBuiltinsArray()); ASSERT(condition); return acc_.TryGetArrayElementsKindAfterTransition(gate_); } - bool IsValidTypedArrayType() const - { - return tsManager_->IsValidTypedArrayType(GetReceiverGateType()); - } - protected: - bool IsAllString() const; + bool IsMonoBuiltins() const; void FetchBuiltinsTypes(); bool CheckDuplicatedBuiltinType(ProfileType newType) const; @@ -977,24 +1091,6 @@ public: Chunk *chunk); NO_COPY_SEMANTIC(LoadBulitinObjTypeInfoAccessor); NO_MOVE_SEMANTIC(LoadBulitinObjTypeInfoAccessor); - - bool IsStringType() const - { - return GetReceiverGateType().IsStringType(); - } - - bool IsArrayType() const - { - GateType temp = GetReceiverGateType(); - return tsManager_->IsArrayTypeKind(temp) || - tsManager_->IsBuiltinInstanceType(BuiltinTypeId::ARRAY, temp); - } - - BuiltinTypeId GetTypedArrayBuiltinId() const - { - ASSERT(IsValidTypedArrayType()); - return tsManager_->GetTypedArrayBuiltinId(GetReceiverGateType()); - } }; class StoreBulitinObjTypeInfoAccessor final : public AccBuiltinObjTypeInfoAccessor { diff --git a/ecmascript/compiler/typed_bytecode_lowering.cpp b/ecmascript/compiler/typed_bytecode_lowering.cpp index 1e28e7e7c7ecba412797cab4f91aaa4c0d604f5c..adb0bfeb3ef5666d6f606c988b68e6a1f3bc0480 100644 --- a/ecmascript/compiler/typed_bytecode_lowering.cpp +++ b/ecmascript/compiler/typed_bytecode_lowering.cpp @@ -19,17 +19,18 @@ #include "ecmascript/compiler/circuit_builder.h" #include "ecmascript/compiler/typed_bytecode_lowering.h" + +#include "ecmascript/base/string_helper.h" #include "ecmascript/builtin_entries.h" -#include "ecmascript/compiler/builtins_lowering.h" #include "ecmascript/compiler/bytecodes.h" #include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/type_info_accessors.h" #include "ecmascript/dfx/vmstat/opt_code_profiler.h" #include "ecmascript/enum_conversion.h" #include "ecmascript/js_tagged_value.h" +#include "ecmascript/jspandafile/js_pandafile.h" +#include "ecmascript/jspandafile/js_pandafile_manager.h" #include "ecmascript/jspandafile/program_object.h" -#include "ecmascript/stackmap/llvm/llvm_stackmap_parser.h" -#include "ecmascript/base/string_helper.h" namespace panda::ecmascript::kungfu { bool TypedBytecodeLowering::RunTypedBytecodeLowering() @@ -355,13 +356,13 @@ int32_t TypedBytecodeLowering::GetEcmaOpCodeListIndex(EcmaOpcode ecmaOpCode) } template -void TypedBytecodeLowering::LowerTypedBinOp(GateRef gate, bool convertNumberType) +void TypedBytecodeLowering::LowerTypedBinOp(GateRef gate) { - BinOpTypeInfoAccessor tacc(thread_, circuit_, gate, convertNumberType); + BinOpTypeInfoAccessor tacc(thread_, circuit_, gate); if (tacc.HasNumberType()) { - SpeculateNumbers(gate); - } else if (tacc.HasStringType()) { - SpeculateStrings(gate); + SpeculateNumbers(tacc); + } else if (tacc.IsStringType()) { + SpeculateStrings(tacc); } } @@ -369,7 +370,8 @@ template void TypedBytecodeLowering::LowerTypedUnOp(GateRef gate) { UnOpTypeInfoAccessor tacc(thread_, circuit_, gate); - if (tacc.ValueIsNumberType()) { + // NOTICE-PGO: wx add support for PrimitiveNumberType + if (tacc.HasNumberType()) { SpeculateNumber(tacc); } } @@ -377,75 +379,45 @@ void TypedBytecodeLowering::LowerTypedUnOp(GateRef gate) template void TypedBytecodeLowering::LowerTypedEqOrNotEq(GateRef gate) { - GateRef left = acc_.GetValueIn(gate, 0); - GateRef right = acc_.GetValueIn(gate, 1); - GateType leftType = acc_.GetGateType(left); - GateType rightType = acc_.GetGateType(right); - GateType gateType = acc_.GetGateType(gate); - PGOTypeRef pgoType = acc_.TryGetPGOType(gate); - BinOpTypeInfoAccessor tacc(thread_, circuit_, gate); - if (tacc.LeftOrRightIsUndefinedOrNullOrHole() || tacc.HasNumberType()) { + if (tacc.LeftOrRightIsUndefinedOrNull()) { AddProfiling(gate); - GateRef result = builder_.TypedBinaryOp( - left, right, leftType, rightType, gateType, pgoType); + GateRef left = tacc.GetLeftGate(); + GateRef right = tacc.GetReightGate(); + GateRef result = builder_.TypedBinaryOp(left, right, tacc.GetParamType()); acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); - } else if (tacc.HasStringType()) { - SpeculateStrings(gate); + } else { + LowerTypedBinOp(gate); } } template -void TypedBytecodeLowering::SpeculateStrings(GateRef gate) +void TypedBytecodeLowering::SpeculateStrings(const BinOpTypeInfoAccessor &tacc) { if (Op == TypedBinOp::TYPED_EQ || Op == TypedBinOp::TYPED_ADD) { - GateRef left = acc_.GetValueIn(gate, 0); - GateRef right = acc_.GetValueIn(gate, 1); - GateType leftType = acc_.GetGateType(left); - GateType rightType = acc_.GetGateType(right); - // Only support type is "number" or "string" - if ((!leftType.IsNumberType() && !leftType.IsStringType()) || - (!rightType.IsNumberType() && !rightType.IsStringType())) { - return ; - } - if (leftType.IsNumberType()) { - left = builder_.NumberToString(left); - leftType = acc_.GetGateType(left); - acc_.ReplaceValueIn(gate, left, 0); - } else if (rightType.IsNumberType()) { - right = builder_.NumberToString(right); - rightType = acc_.GetGateType(right); - acc_.ReplaceValueIn(gate, right, 1); - } - AddProfiling(gate); + AddProfiling(tacc.GetGate()); + GateRef left = tacc.GetLeftGate(); + GateRef right = tacc.GetReightGate(); if (!TypeInfoAccessor::IsTrustedStringType(thread_, circuit_, chunk_, acc_, left)) { builder_.EcmaStringCheck(left); } if (!TypeInfoAccessor::IsTrustedStringType(thread_, circuit_, chunk_, acc_, right)) { builder_.EcmaStringCheck(right); } - GateType gateType = acc_.GetGateType(gate); - PGOTypeRef pgoType = acc_.TryGetPGOType(gate); - pgoTypeLog_.CollectGateTypeLogInfo(gate, true); - GateRef result = builder_.TypedBinaryOp(left, right, leftType, rightType, gateType, pgoType); - acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); + GateRef result = builder_.TypedBinaryOp(left, right, tacc.GetParamType()); + acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result); } } template -void TypedBytecodeLowering::SpeculateNumbers(GateRef gate) +void TypedBytecodeLowering::SpeculateNumbers(const BinOpTypeInfoAccessor &tacc) { - AddProfiling(gate); - GateRef left = acc_.GetValueIn(gate, 0); - GateRef right = acc_.GetValueIn(gate, 1); - GateType leftType = acc_.GetGateType(left); - GateType rightType = acc_.GetGateType(right); - GateType gateType = acc_.GetGateType(gate); - PGOTypeRef pgoType = acc_.TryGetPGOType(gate); - pgoTypeLog_.CollectGateTypeLogInfo(gate, true); - - GateRef result = builder_.TypedBinaryOp(left, right, leftType, rightType, gateType, pgoType); - acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); + AddProfiling(tacc.GetGate()); + pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), true); + GateRef left = tacc.GetLeftGate(); + GateRef right = tacc.GetReightGate(); + GateRef result = builder_.TypedBinaryOp(left, right, tacc.GetParamType()); + acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result); } template @@ -453,16 +425,14 @@ void TypedBytecodeLowering::SpeculateNumber(const UnOpTypeInfoAccessor &tacc) { AddProfiling(tacc.GetGate()); pgoTypeLog_.CollectGateTypeLogInfo(tacc.GetGate(), false); - GateRef value = tacc.GetValue(); - GateType valueType = tacc.FetchNumberType(); - GateRef result = builder_.TypedUnaryOp(value, valueType, valueType); + GateRef result = builder_.TypedUnaryOp(tacc.GetValue(), tacc.GetParamType()); acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result); } void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate) { UnOpTypeInfoAccessor tacc(thread_, circuit_, gate); - if (tacc.ValueIsNumberType()) { + if (tacc.HasNumberType()) { AddProfiling(gate); LowerPrimitiveTypeToNumber(tacc); } @@ -470,18 +440,14 @@ void TypedBytecodeLowering::LowerTypeToNumeric(GateRef gate) void TypedBytecodeLowering::LowerPrimitiveTypeToNumber(const UnOpTypeInfoAccessor &tacc) { - GateRef value = tacc.GetValue(); - GateType valueType = tacc.FetchNumberType(); - acc_.SetGateType(value, valueType); - GateRef result = builder_.PrimitiveToNumber(value, - VariableType(MachineType::I64, valueType)); + GateRef result = builder_.PrimitiveToNumber(tacc.GetValue(), tacc.GetParamType()); acc_.ReplaceHirAndDeleteIfException(tacc.GetGate(), builder_.GetStateDepend(), result); } void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag) { ConditionJumpTypeInfoAccessor tacc(thread_, circuit_, gate); - if (tacc.ValueIsBooleanType() && TypeInfoAccessor::IsTrustedType(acc_, tacc.GetValue())) { + if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue())) { AddProfiling(gate); SpeculateConditionJump(tacc, flag); } @@ -490,13 +456,13 @@ void TypedBytecodeLowering::LowerConditionJump(GateRef gate, bool flag) void TypedBytecodeLowering::SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag) { GateRef value = tacc.GetValue(); - GateType valueType = tacc.GetValueGateType(); + ParamType paramType = ParamType::BooleanType(); uint32_t weight = tacc.GetBranchWeight(); GateRef jump = Circuit::NullGate(); if (flag) { - jump = builder_.TypedConditionJump(value, valueType, weight); + jump = builder_.TypedConditionJump(value, paramType, weight); } else { - jump = builder_.TypedConditionJump(value, valueType, weight); + jump = builder_.TypedConditionJump(value, paramType, weight); } acc_.ReplaceGate(tacc.GetGate(), jump, jump, Circuit::NullGate()); } @@ -538,7 +504,7 @@ void TypedBytecodeLowering::LowerTypedLdObjByName(GateRef gate) GateRef frameState = acc_.GetFrameState(gate); if (tacc.IsMono()) { GateRef receiver = tacc.GetReceiver(); - builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver, + builder_.ObjectTypeCheck(true, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState); if (tacc.IsReceiverEqHolder(0)) { result = BuildNamedPropertyAccess(gate, receiver, receiver, tacc.GetAccessInfo(0).Plr()); @@ -646,7 +612,7 @@ void TypedBytecodeLowering::LowerTypedStObjByName(GateRef gate) if (tacc.IsMono()) { GateRef receiver = tacc.GetReceiver(); - builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, receiver, + builder_.ObjectTypeCheck(true, receiver, builder_.Int32(tacc.GetExpectedHClassIndex(0)), frameState); if (tacc.IsReceiverNoEqNewHolder(0)) { builder_.ProtoChangeMarkerCheck(tacc.GetReceiver(), frameState); @@ -810,15 +776,6 @@ GateRef TypedBytecodeLowering::BuildNamedPropertyAccess( return result; } -bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltinsId(const LoadBulitinObjTypeInfoAccessor &tacc, - BuiltinTypeId type) -{ - if (TryLowerTypedLdObjByNameForBuiltin(tacc, type)) { - return true; - } - return TryLowerTypedLdObjByNameForBuiltinMethod(tacc, type); -} - bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate) { LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_); @@ -827,7 +784,10 @@ bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate) if (tacc.IsBuiltinsType()) { auto builtinsId = tacc.GetBuiltinsTypeId(); if (builtinsId.has_value()) { - return TryLowerTypedLdObjByNameForBuiltinsId(tacc, builtinsId.value()); + if (TryLowerTypedLdObjByNameForBuiltin(tacc)) { + return true; + } + return TryLowerTypedLdObjByNameForBuiltinMethod(tacc, builtinsId.value()); } } else if (tacc.IsGlobalsType()) { auto globalsId = tacc.GetGlobalsId(); @@ -835,50 +795,30 @@ bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(GateRef gate) return TryLowerTypedLdObjByNameForGlobalsId(tacc, globalsId.value()); } } - } - - // String: primitive string type only - /* e.g. let s1 = "ABC"; -> OK - * e.g. let s2 = new String("DEF"); -> Not included, whose type is JSType::JS_PRIMITIVE_REF */ - if (tacc.IsStringType()) { - return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::STRING); - } - // Array: created via either array literal or new Array(...) - /* e.g. let a1 = [1, 2, 3]; -> OK - * e.g. let a2 = new Array(1, 2, 3); -> OK */ - if (tacc.IsArrayType()) { - return TryLowerTypedLdObjByNameForBuiltin(tacc, BuiltinTypeId::ARRAY); - } - // Other valid types: let x = new X(...); - const auto hclassEntries = thread_->GetBuiltinHClassEntries(); - for (BuiltinTypeId type: BuiltinHClassEntries::BUILTIN_TYPES) { - if (type == BuiltinTypeId::ARRAY || type == BuiltinTypeId::STRING || !hclassEntries.EntryIsValid(type)) { - continue; // Checked before or invalid - } - if (!tacc.IsBuiltinInstanceType(type)) { - continue; // Type mismatch + } else if (tacc.GetTypeCount() > 0) { + auto builtinsId = tacc.GetBuiltinsTypeId(); + if (builtinsId.has_value()) { + return TryLowerTypedLdObjByNameForBuiltin(tacc); } - return TryLowerTypedLdObjByNameForBuiltin(tacc, type); } return false; // No lowering performed } -bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc, - BuiltinTypeId type) +bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc) { EcmaString *propString = EcmaString::Cast(tacc.GetKeyTaggedValue().GetTaggedObject()); // (1) get length EcmaString *lengthString = EcmaString::Cast(thread_->GlobalConstants()->GetLengthString().GetTaggedObject()); if (propString == lengthString) { - if (type == BuiltinTypeId::ARRAY) { + if (tacc.IsBuiltinsArray()) { LowerTypedLdArrayLength(tacc); return true; } - if (type == BuiltinTypeId::STRING) { + if (tacc.IsBuiltinsString()) { LowerTypedLdStringLength(tacc); return true; } - if (IsTypedArrayType(type)) { + if (tacc.IsBuiltinsTypeArray()) { LowerTypedLdTypedArrayLength(tacc); return true; } @@ -888,23 +828,25 @@ bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForBuiltin(const LoadBulitin } bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForGlobalsId(const LoadBulitinObjTypeInfoAccessor &tacc, - ConstantIndex globalsId) + GlobalIndex globalsId) { - if (globalsId == ConstantIndex::ITERATOR_RESULT_CLASS) { - GateRef receiver = tacc.GetReceiver(); - GateRef gate = tacc.GetGate(); - JSHClass *hclass = JSHClass::Cast(thread_->GlobalConstants()->GetIteratorResultClass().GetTaggedObject()); - JSTaggedValue key = tacc.GetKeyTaggedValue(); + GateRef receiver = tacc.GetReceiver(); + GateRef gate = tacc.GetGate(); + JSTaggedValue key = tacc.GetKeyTaggedValue(); + GateRef frameState = acc_.FindNearestFrameState(gate); + if (globalsId.IsGlobalConstId()) { + ConstantIndex index = static_cast(globalsId.GetGlobalConstId()); + JSHClass *hclass = JSHClass::Cast(thread_->GlobalConstants()->GetGlobalConstantObject( + static_cast(index)).GetTaggedObject()); PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(thread_, hclass, key); if (!plr.IsFound() || plr.IsAccessor()) { return false; } AddProfiling(gate); // 1. check hclass - GateRef frameState = acc_.FindNearestFrameState(gate); builder_.HeapObjectCheck(receiver, frameState); GateRef receiverHClass = builder_.LoadHClassByConstOffset(receiver); - GateRef expectedHClass = builder_.GetGlobalConstantValue(globalsId); + GateRef expectedHClass = builder_.GetGlobalConstantValue(index); builder_.DeoptCheck(builder_.Equal(receiverHClass, expectedHClass), frameState, DeoptType::INCONSISTENTHCLASS11); // 2. load property @@ -913,6 +855,26 @@ bool TypedBytecodeLowering::TryLowerTypedLdObjByNameForGlobalsId(const LoadBulit acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); DeleteConstDataIfNoUser(tacc.GetKey()); return true; + } else if (globalsId.IsGlobalEnvId()) { // ctor Hclass + GlobalEnvField index = static_cast(globalsId.GetGlobalEnvId()); + JSHClass *hclass = JSHClass::Cast(thread_->GetGlobalEnv()->GetGlobalEnvObjectByIndex( + static_cast(index))->GetTaggedObject()->GetClass()); + PropertyLookupResult plr = JSHClass::LookupPropertyInBuiltinHClass(thread_, hclass, key); + if (!plr.IsFound() || plr.IsAccessor()) { + return false; + } + AddProfiling(gate); + // 1. check hclass + builder_.HeapObjectCheck(receiver, frameState); + GateRef globalEnvObj = builder_.GetGlobalEnvObj(builder_.GetGlobalEnv(), static_cast(index)); + builder_.DeoptCheck(builder_.Equal(receiver, globalEnvObj), frameState, + DeoptType::INCONSISTENTHCLASS12); + // 2. load property + GateRef plrGate = builder_.Int32(plr.GetData()); + GateRef result = builder_.LoadProperty(receiver, plrGate, plr.IsFunction()); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); + DeleteConstDataIfNoUser(tacc.GetKey()); + return true; } return false; } @@ -966,7 +928,7 @@ void TypedBytecodeLowering::LowerTypedLdTypedArrayLength(const LoadBulitinObjTyp GateRef gate = tacc.GetGate(); GateRef array = tacc.GetReceiver(); AddProfiling(gate); - GateType arrayType = tacc.GetReceiverGateType(); + ParamType arrayType = tacc.GetParamType(); OnHeapMode onHeap = acc_.TryGetOnHeapMode(gate); if (!Uncheck()) { builder_.TypedArrayCheck(array, arrayType, TypedArrayMetaDateAccessor::Mode::LOAD_LENGTH, onHeap); @@ -1047,11 +1009,14 @@ bool TypedBytecodeLowering::TryLowerTypedLdObjByIndexForBuiltin(GateRef gate) { LoadBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_); GateRef result = Circuit::NullGate(); - if (tacc.IsValidTypedArrayType()) { - AddProfiling(gate); - result = LoadTypedArrayByIndex(tacc); - acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); - return true; + // Just supported mono. + if (tacc.IsMono()) { + if (tacc.IsBuiltinsTypeArray()) { // pgo need dump profile type + AddProfiling(gate); + result = LoadTypedArrayByIndex(tacc); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); + return true; + } } return false; } @@ -1066,13 +1031,12 @@ void TypedBytecodeLowering::LowerTypedLdObjByIndex(GateRef gate) bool TypedBytecodeLowering::TryLowerTypedStObjByIndexForBuiltin(GateRef gate) { StoreBulitinObjTypeInfoAccessor tacc(thread_, circuit_, gate, chunk_); - if (!tacc.IsBuiltinInstanceType(BuiltinTypeId::FLOAT32_ARRAY) || - !tacc.ValueIsNumberType()) { + if (tacc.GetBuiltinsJSType() != JSType::JS_FLOAT32_ARRAY) { return false; } AddProfiling(gate); GateRef receiver = tacc.GetReceiver(); - GateType receiverType = tacc.GetReceiverGateType(); + ParamType receiverType = tacc.GetParamType(); if (!Uncheck()) { OnHeapMode onHeap = tacc.TryGetHeapMode(); builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap); @@ -1112,18 +1076,13 @@ bool TypedBytecodeLowering::TryLowerTypedLdObjByValueForBuiltin(GateRef gate) result = LoadJSArrayByIndex(tacc); acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); return true; + } else if (tacc.IsBuiltinsTypeArray()) { + AddProfiling(gate); + result = LoadTypedArrayByIndex(tacc); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); + return true; } } - - if (!tacc.KeyIsNumberType()) { - return false; - } - if (tacc.IsValidTypedArrayType()) { - AddProfiling(gate); - result = LoadTypedArrayByIndex(tacc); - acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); - return true; - } return false; } @@ -1182,33 +1141,33 @@ GateRef TypedBytecodeLowering::LoadJSArrayByIndex(const LoadBulitinObjTypeInfoAc GateRef TypedBytecodeLowering::LoadTypedArrayByIndex(const LoadBulitinObjTypeInfoAccessor &tacc) { GateRef receiver = tacc.GetReceiver(); - GateType receiverType = tacc.GetReceiverGateType(); + ParamType receiverType = tacc.GetParamType(); GateRef propKey = tacc.GetKey(); OnHeapMode onHeap = tacc.TryGetHeapMode(); - BuiltinTypeId builtinTypeId = tacc.GetTypedArrayBuiltinId(); + JSType builtinsType = tacc.GetBuiltinsJSType(); if (!Uncheck()) { builder_.TypedArrayCheck(receiver, receiverType, TypedArrayMetaDateAccessor::Mode::ACCESS_ELEMENT, onHeap); GateRef length = builder_.LoadTypedArrayLength(receiver, receiverType, onHeap); propKey = builder_.IndexCheck(length, propKey); } - switch (builtinTypeId) { - case BuiltinTypeId::INT8_ARRAY: + switch (builtinsType) { + case JSType::JS_INT8_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::UINT8_ARRAY: + case JSType::JS_UINT8_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::UINT8_CLAMPED_ARRAY: + case JSType::JS_UINT8_CLAMPED_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::INT16_ARRAY: + case JSType::JS_INT16_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::UINT16_ARRAY: + case JSType::JS_UINT16_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::INT32_ARRAY: + case JSType::JS_INT32_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::UINT32_ARRAY: + case JSType::JS_UINT32_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::FLOAT32_ARRAY: + case JSType::JS_FLOAT32_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); - case BuiltinTypeId::FLOAT64_ARRAY: + case JSType::JS_FLOAT64_ARRAY: return builder_.LoadElement(receiver, propKey, onHeap); default: LOG_ECMA(FATAL) << "this branch is unreachable"; @@ -1243,7 +1202,7 @@ void TypedBytecodeLowering::StoreJSArrayByIndex(const StoreBulitinObjTypeInfoAcc void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBulitinObjTypeInfoAccessor &tacc) { GateRef receiver = tacc.GetReceiver(); - GateType receiverType = tacc.GetReceiverGateType(); + ParamType receiverType = tacc.GetParamType(); GateRef propKey = tacc.GetKey(); GateRef value = tacc.GetValue(); OnHeapMode onHeap = tacc.TryGetHeapMode(); @@ -1253,33 +1212,33 @@ void TypedBytecodeLowering::StoreTypedArrayByIndex(const StoreBulitinObjTypeInfo propKey = builder_.IndexCheck(length, propKey); } - auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(receiverType); - switch (builtinTypeId) { - case BuiltinTypeId::INT8_ARRAY: + JSType builtinsType = tacc.GetBuiltinsJSType(); + switch (builtinsType) { + case JSType::JS_INT8_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::UINT8_ARRAY: + case JSType::JS_UINT8_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::UINT8_CLAMPED_ARRAY: + case JSType::JS_UINT8_CLAMPED_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::INT16_ARRAY: + case JSType::JS_INT16_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::UINT16_ARRAY: + case JSType::JS_UINT16_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::INT32_ARRAY: + case JSType::JS_INT32_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::UINT32_ARRAY: + case JSType::JS_UINT32_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::FLOAT32_ARRAY: + case JSType::JS_FLOAT32_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; - case BuiltinTypeId::FLOAT64_ARRAY: + case JSType::JS_FLOAT64_ARRAY: builder_.StoreElement(receiver, propKey, value, onHeap); break; default: @@ -1298,20 +1257,14 @@ bool TypedBytecodeLowering::TryLowerTypedStObjByValueForBuiltin(GateRef gate) StoreJSArrayByIndex(tacc); acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate()); return true; + } else if (tacc.IsBuiltinsTypeArray()) { + AddProfiling(gate); + StoreTypedArrayByIndex(tacc); + acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate()); + return true; } } - if (!tacc.KeyIsNumberType()) { - return false; - } - - if (tacc.IsValidTypedArrayType()) { - AddProfiling(gate); - StoreTypedArrayByIndex(tacc); - acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), Circuit::NullGate()); - return true; - } - return false; } @@ -1325,17 +1278,20 @@ void TypedBytecodeLowering::LowerTypedStObjByValue(GateRef gate) void TypedBytecodeLowering::LowerTypedIsTrueOrFalse(GateRef gate, bool flag) { UnOpTypeInfoAccessor tacc(thread_, circuit_, gate); - if (!tacc.ValueIsPrimitiveNumberType() && !tacc.ValueIsBooleanType()) { + ParamType paramType; + if (TypeInfoAccessor::IsTrustedBooleanType(acc_, tacc.GetValue())) { + paramType = ParamType::BooleanType(); + } else if (TypeInfoAccessor::IsTrustedNumberType(acc_, tacc.GetValue())) { + paramType = ParamType::NumberType(); + } else { return; } AddProfiling(gate); - GateRef value = tacc.GetValue(); - GateType valueType = tacc.GetValueGateType(); GateRef result; if (!flag) { - result = builder_.TypedUnaryOp(value, valueType, GateType::TaggedValue()); + result = builder_.TypedUnaryOp(tacc.GetValue(), paramType); } else { - result = builder_.TypedUnaryOp(value, valueType, GateType::TaggedValue()); + result = builder_.TypedUnaryOp(tacc.GetValue(), paramType); } acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); @@ -1403,7 +1359,7 @@ bool TypedBytecodeLowering::TryLowerNewBuiltinConstructor(GateRef gate) void TypedBytecodeLowering::LowerTypedSuperCall(GateRef gate) { SuperCallTypeInfoAccessor tacc(thread_, circuit_, gate); - if (!tacc.IsClassTypeKind() && !tacc.IsFunctionTypeKind()) { + if (!tacc.IsClassTypeKind() && !tacc.IsValidCallMethodId()) { return; } AddProfiling(gate); @@ -1474,14 +1430,12 @@ void TypedBytecodeLowering::CheckFastCallThisCallTarget(const TypeAccessor &tacc } GateRef func = tacc.GetFunc(); GateRef gate = tacc.GetGate(); - GateType funcType = tacc.GetFuncGateType(); if (tacc.IsNoGC()) { uint32_t methodOffset = tacc.GetFuncMethodOffset(); - builder_.JSNoGCCallThisTargetTypeCheck(funcType, + builder_.JSNoGCCallThisTargetTypeCheck( func, builder_.IntPtr(methodOffset), gate); } else { - builder_.JSCallThisTargetTypeCheck(funcType, - func, gate); + builder_.JSCallThisTargetTypeCheck(func, gate); } } @@ -1493,14 +1447,12 @@ void TypedBytecodeLowering::CheckCallThisCallTarget(const TypeAccessor &tacc) } GateRef func = tacc.GetFunc(); GateRef gate = tacc.GetGate(); - GateType funcType = tacc.GetFuncGateType(); if (tacc.IsNoGC()) { auto methodOffset = tacc.GetFuncMethodOffset(); - builder_.JSNoGCCallThisTargetTypeCheck(funcType, + builder_.JSNoGCCallThisTargetTypeCheck( func, builder_.IntPtr(methodOffset), gate); } else { - builder_.JSCallThisTargetTypeCheck(funcType, - func, gate); + builder_.JSCallThisTargetTypeCheck(func, gate); } } @@ -1508,9 +1460,6 @@ template void TypedBytecodeLowering::CheckThisCallTargetAndLowerCall(const TypeAccessor &tacc, const std::vector &args, const std::vector &argsFastCall) { - if (!tacc.FastCallFlagIsVaild()) { - return; - } GateRef func = tacc.GetFunc(); GateRef gate = tacc.GetGate(); bool isNoGC = tacc.IsNoGC(); @@ -1529,9 +1478,8 @@ void TypedBytecodeLowering::CheckCallTargetFromDefineFuncAndLowerCall(const Type { GateRef func = tacc.GetFunc(); GateRef gate = tacc.GetGate(); - GateType funcType = tacc.GetFuncGateType(); if (!Uncheck()) { - builder_.JSCallTargetFromDefineFuncCheck(funcType, func, gate); + builder_.JSCallTargetFromDefineFuncCheck(func, gate); } if (tacc.CanFastCall()) { LowerFastCall(gate, func, argsFastCall, isNoGC); @@ -1550,9 +1498,6 @@ void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc } else { bool isNoGC = tacc.IsNoGC(); auto op = acc_.GetOpCode(func); - if (!tacc.FastCallFlagIsVaild()) { - return; - } if (op == OpCode::JS_BYTECODE && (acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM8_ID16_IMM8 || acc_.GetByteCodeOpcode(func) == EcmaOpcode::DEFINEFUNC_IMM16_ID16_IMM8)) { CheckCallTargetFromDefineFuncAndLowerCall(tacc, args, argsFastCall, isNoGC); @@ -1564,17 +1509,16 @@ void TypedBytecodeLowering::CheckCallTargetAndLowerCall(const TypeAccessor &tacc } GateRef gate = tacc.GetGate(); - GateType funcType = tacc.GetFuncGateType(); if (tacc.CanFastCall()) { if (!Uncheck()) { - builder_.JSCallTargetTypeCheck(funcType, - func, builder_.IntPtr(methodIndex), gate); + builder_.JSCallTargetTypeCheck(func, + builder_.IntPtr(methodIndex), gate); } LowerFastCall(gate, func, argsFastCall, isNoGC); } else { if (!Uncheck()) { - builder_.JSCallTargetTypeCheck(funcType, - func, builder_.IntPtr(methodIndex), gate); + builder_.JSCallTargetTypeCheck(func, + builder_.IntPtr(methodIndex), gate); } LowerCall(gate, func, args, isNoGC); } @@ -1634,13 +1578,30 @@ void TypedBytecodeLowering::LowerTypedCall(const TypeAccessor &tacc) argsFastCall.emplace_back(builder_.Undefined()); args.emplace_back(builder_.Undefined()); } + AddProfiling(gate); CheckCallTargetAndLowerCall(tacc, args, argsFastCall); } +const JSPandaFile* TypedBytecodeLowering::GetCalleePandaFile(GateRef gate) +{ + auto profileType = acc_.TryGetPGOType(gate).GetPGOSampleType(); + bool haveProfileType = profileType->IsProfileType() && !profileType->IsProfileTypeNone(); + if (haveProfileType) { + auto abcId = profileType->GetProfileType().GetAbcId(); + CString fileDesc; + if (!decoder_->GetAbcNameById(abcId, fileDesc)) { + UNREACHABLE(); + } + return JSPandaFileManager::GetInstance()->FindJSPandaFileByNormalizedName(fileDesc).get(); + } + // nullptr if no pgo info + return nullptr; +} + void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate) { - CallArg0TypeInfoAccessor tacc(thread_, circuit_, gate); - if (!tacc.IsFunctionTypeKind()) { + CallArg0TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + if (!tacc.IsValidCallMethodId()) { return; } LowerTypedCall(tacc); @@ -1648,19 +1609,15 @@ void TypedBytecodeLowering::LowerTypedCallArg0(GateRef gate) void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate) { - CallArg1TypeInfoAccessor tacc(thread_, circuit_, gate); + CallArg1TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); GateRef func = tacc.GetFunc(); GateRef a0Value = tacc.GetValue(); - GateType a0Type = tacc.GetValueGateType(); - BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinId(); - if ((IS_TYPED_BUILTINS_MATH_ID(id) && a0Type.IsNumberType())) { - AddProfiling(gate); - SpeculateCallBuiltin(gate, func, { a0Value }, id, false); - } else if (IS_TYPED_BUILTINS_NUMBER_ID(id)) { + BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId(); + if (IS_TYPED_BUILTINS_NUMBER_ID(id)) { AddProfiling(gate); SpeculateCallBuiltin(gate, func, { a0Value }, id, true); } else { - if (!tacc.IsFunctionTypeKind()) { + if (!tacc.IsValidCallMethodId()) { return; } LowerTypedCall(tacc); @@ -1669,8 +1626,8 @@ void TypedBytecodeLowering::LowerTypedCallArg1(GateRef gate) void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate) { - CallArg2TypeInfoAccessor tacc(thread_, circuit_, gate); - if (!tacc.IsFunctionTypeKind()) { + CallArg2TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + if (!tacc.IsValidCallMethodId()) { return; } LowerTypedCall(tacc); @@ -1678,8 +1635,8 @@ void TypedBytecodeLowering::LowerTypedCallArg2(GateRef gate) void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate) { - CallArg3TypeInfoAccessor tacc(thread_, circuit_, gate); - if (!tacc.IsFunctionTypeKind()) { + CallArg3TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + if (!tacc.IsValidCallMethodId()) { return; } LowerTypedCall(tacc); @@ -1687,8 +1644,8 @@ void TypedBytecodeLowering::LowerTypedCallArg3(GateRef gate) void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate) { - CallRangeTypeInfoAccessor tacc(thread_, circuit_, gate); - if (!tacc.IsFunctionTypeKind()) { + CallRangeTypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + if (!tacc.IsValidCallMethodId()) { return; } LowerTypedCall(tacc); @@ -1697,7 +1654,7 @@ void TypedBytecodeLowering::LowerTypedCallrange(GateRef gate) bool TypedBytecodeLowering::IsLoadVtable(GateRef func) { auto op = acc_.GetOpCode(func); - if (op != OpCode::LOAD_PROPERTY || !acc_.IsVtable(func)) { + if (op != OpCode::LOAD_PROPERTY) { return false; } return true; @@ -1754,19 +1711,14 @@ void TypedBytecodeLowering::LowerTypedThisCall(const TypeAccessor &tacc) argsFastCall.emplace_back(builder_.Undefined()); args.emplace_back(builder_.Undefined()); } + AddProfiling(gate); CheckThisCallTargetAndLowerCall(tacc, args, argsFastCall); } void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate) { - CallThis0TypeInfoAccessor tacc(thread_, circuit_, gate); - BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::ARRAY); - if (id == BuiltinsStubCSigns::ID::SORT) { - AddProfiling(gate); - SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetThisObj() }, id, true); - return; - } - BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinId(); + CallThis0TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId(); if (IS_TYPED_BUILTINS_ID_CALL_THIS0(pgoFuncId)) { AddProfiling(gate); SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetThisObj() }, pgoFuncId, true, true); @@ -1780,19 +1732,12 @@ void TypedBytecodeLowering::LowerTypedCallthis0(GateRef gate) void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate) { - CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate); - BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::MATH); - if (id == BuiltinsStubCSigns::ID::NONE) { - id = tacc.TryGetBuiltinId(BuiltinTypeId::JSON); - if (id != BuiltinsStubCSigns::ID::NONE) { - AddProfiling(gate); - SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArg0() }, id, true); - return; - } - } else if (tacc.Arg0IsNumberType()) { - AddProfiling(gate); - SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArg0() }, id, false); - return; + CallThis1TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId(); + if (IS_TYPED_BUILTINS_ID_CALL_THIS1(pgoFuncId)) { + AddProfiling(gate); + SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArg0() }, pgoFuncId, true); + return; } if (!tacc.CanOptimizeAsFastCall()) { return; @@ -1802,7 +1747,7 @@ void TypedBytecodeLowering::LowerTypedCallthis1(GateRef gate) void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate) { - CallThis2TypeInfoAccessor tacc(thread_, circuit_, gate); + CallThis2TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); if (!tacc.CanOptimizeAsFastCall()) { return; } @@ -1811,11 +1756,11 @@ void TypedBytecodeLowering::LowerTypedCallthis2(GateRef gate) void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate) { - CallThis3TypeInfoAccessor tacc(thread_, circuit_, gate); - BuiltinsStubCSigns::ID id = tacc.TryGetBuiltinId(BuiltinTypeId::STRING); - if (IS_TYPED_BUILTINS_ID_CALL_THIS3(id)) { + CallThis3TypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + BuiltinsStubCSigns::ID pgoFuncId = tacc.TryGetPGOBuiltinMethodId(); + if (IS_TYPED_BUILTINS_ID_CALL_THIS3(pgoFuncId)) { AddProfiling(gate); - SpeculateCallBuiltin(gate, tacc.GetFunc(), tacc.GetArgs(), id, true); + SpeculateCallBuiltin(gate, tacc.GetFunc(), { tacc.GetArgs() }, pgoFuncId, true); return; } if (!tacc.CanOptimizeAsFastCall()) { @@ -1826,7 +1771,7 @@ void TypedBytecodeLowering::LowerTypedCallthis3(GateRef gate) void TypedBytecodeLowering::LowerTypedCallthisrange(GateRef gate) { - CallThisRangeTypeInfoAccessor tacc(thread_, circuit_, gate); + CallThisRangeTypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); if (!tacc.CanOptimizeAsFastCall()) { return; } @@ -1873,20 +1818,21 @@ void TypedBytecodeLowering::AddProfiling(GateRef gate) current = gate; } + GateRef func = builder_.Undefined(); if (acc_.HasFrameState(gate)) { - // func, pcoffset, opcode, mode - GateRef func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); - GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate))); - EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate); - auto ecmaOpcodeGate = builder_.Int32(static_cast(ecmaOpcode)); - GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate); - GateRef mode = - builder_.Int32ToTaggedInt(builder_.Int32(static_cast(OptCodeProfiler::Mode::TYPED_PATH))); - GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current), - { func, bcIndex, constOpcode, mode }, gate); - acc_.SetDep(current, profiling); - builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT + func = argAcc_.GetFrameArgsIn(gate, FrameArgIdx::FUNC); } + + GateRef bcIndex = builder_.Int32ToTaggedInt(builder_.Int32(acc_.TryGetBcIndex(gate))); + EcmaOpcode ecmaOpcode = acc_.GetByteCodeOpcode(gate); + auto ecmaOpcodeGate = builder_.Int32(static_cast(ecmaOpcode)); + GateRef constOpcode = builder_.Int32ToTaggedInt(ecmaOpcodeGate); + GateRef mode = + builder_.Int32ToTaggedInt(builder_.Int32(static_cast(OptCodeProfiler::Mode::TYPED_PATH))); + GateRef profiling = builder_.CallRuntime(glue_, RTSTUB_ID(ProfileOptimizedCode), acc_.GetDep(current), + { func, bcIndex, constOpcode, mode }, gate); + acc_.SetDep(current, profiling); + builder_.SetDepend(acc_.GetDep(gate)); // set gate depend: profiling or STATE_SPLIT } } @@ -1916,23 +1862,22 @@ void TypedBytecodeLowering::AddHitBytecodeCount() void TypedBytecodeLowering::LowerTypedTypeOf(GateRef gate) { - // 1: number of value inputs TypeOfTypeInfoAccessor tacc(thread_, circuit_, gate); if (tacc.IsIllegalType()) { return; } AddProfiling(gate); if (!Uncheck()) { - builder_.TypeOfCheck(tacc.GetValue(), tacc.GetValueGateType()); + builder_.TypeOfCheck(tacc.GetValue(), tacc.GetParamType()); } - GateRef result = builder_.TypedTypeOf(tacc.GetValueGateType()); + GateRef result = builder_.TypedTypeOf(tacc.GetParamType()); acc_.ReplaceHirAndDeleteIfException(gate, builder_.GetStateDepend(), result); } void TypedBytecodeLowering::LowerGetIterator(GateRef gate) { - GetIteratorTypeInfoAccessor tacc(thread_, circuit_, gate); - BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinId(); + GetIteratorTypeInfoAccessor tacc(thread_, circuit_, gate, GetCalleePandaFile(gate), callMethodFlagMap_); + BuiltinsStubCSigns::ID id = tacc.TryGetPGOBuiltinMethodId(); if (id == BuiltinsStubCSigns::ID::NONE) { return; } @@ -1981,7 +1926,7 @@ void TypedBytecodeLowering::LowerInstanceOf(GateRef gate) GateRef obj = tacc.GetReceiver(); GateRef target = tacc.GetTarget(); - builder_.ObjectTypeCheck(acc_.GetGateType(gate), true, target, expectedHCIndexes[0]); + builder_.ObjectTypeCheck(true, target, expectedHCIndexes[0]); builder_.ProtoChangeMarkerCheck(target); result = builder_.OrdinaryHasInstance(obj, target); diff --git a/ecmascript/compiler/typed_bytecode_lowering.h b/ecmascript/compiler/typed_bytecode_lowering.h index bda9458481d913e7a9bff93053b9e106d8334421..771e2d9dda846327b15963c9e5bfa76ebaa7d0eb 100644 --- a/ecmascript/compiler/typed_bytecode_lowering.h +++ b/ecmascript/compiler/typed_bytecode_lowering.h @@ -18,6 +18,7 @@ #include "ecmascript/builtin_entries.h" #include "ecmascript/compiler/argument_accessor.h" +#include "ecmascript/compiler/aot_compiler_preprocessor.h" #include "ecmascript/compiler/builtins/builtins_call_signature.h" #include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/circuit_builder-inl.h" @@ -38,6 +39,8 @@ public: const std::string& name, bool enableLoweringBuiltin, const CString& recordName, + const CallMethodFlagMap* callMethodFlagMap, + PGOProfilerDecoder *decoder, const std::string optBCRange) : circuit_(circuit), acc_(circuit), @@ -58,6 +61,8 @@ public: thread_(ctx->GetEcmaVM()->GetJSThread()), enableLoweringBuiltin_(enableLoweringBuiltin), recordName_(recordName), + callMethodFlagMap_(callMethodFlagMap), + decoder_(decoder), optBCRange_(optBCRange) { } @@ -99,7 +104,7 @@ private: void Lower(GateRef gate); template - void LowerTypedBinOp(GateRef gate, bool convertNumberType = true); + void LowerTypedBinOp(GateRef gate); template void LowerTypedUnOp(GateRef gate); template @@ -119,8 +124,8 @@ private: using AccessMode = PGOObjectAccessHelper::AccessMode; bool TryLowerTypedLdObjByNameForBuiltin(GateRef gate); bool TryLowerTypedLdObjByNameForBuiltinsId(const LoadBulitinObjTypeInfoAccessor &tacc, BuiltinTypeId type); - bool TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc, BuiltinTypeId type); - bool TryLowerTypedLdObjByNameForGlobalsId(const LoadBulitinObjTypeInfoAccessor &tacc, ConstantIndex globalsId); + bool TryLowerTypedLdObjByNameForBuiltin(const LoadBulitinObjTypeInfoAccessor &tacc); + bool TryLowerTypedLdObjByNameForGlobalsId(const LoadBulitinObjTypeInfoAccessor &tacc, GlobalIndex globalsId); void LowerTypedLdArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc); void LowerTypedLdTypedArrayLength(const LoadBulitinObjTypeInfoAccessor &tacc); void LowerTypedLdStringLength(const LoadBulitinObjTypeInfoAccessor &tacc); @@ -197,9 +202,9 @@ private: void AddHitBytecodeCount(); template - void SpeculateStrings(GateRef gate); + void SpeculateStrings(const BinOpTypeInfoAccessor& tacc); template - void SpeculateNumbers(GateRef gate); + void SpeculateNumbers(const BinOpTypeInfoAccessor& tacc); template void SpeculateNumber(const UnOpTypeInfoAccessor& tacc); void SpeculateConditionJump(const ConditionJumpTypeInfoAccessor &tacc, bool flag); @@ -211,6 +216,9 @@ private: bool CheckIsInOptBCIgnoreRange(int32_t index, EcmaOpcode ecmaOpcode); int32_t GetEcmaOpCodeListIndex(EcmaOpcode ecmaOpCode); void ParseOptBytecodeRange(); + + const JSPandaFile* GetCalleePandaFile(GateRef gate); + void AddProfiling(GateRef gate); bool Uncheck() const @@ -243,6 +251,8 @@ private: const JSThread *thread_ {nullptr}; bool enableLoweringBuiltin_ {false}; const CString &recordName_; + const CallMethodFlagMap *callMethodFlagMap_; + PGOProfilerDecoder *decoder_ {nullptr}; std::string optBCRange_; std::vector> optBCRangeList_; }; diff --git a/ecmascript/compiler/typed_hcr_lowering.cpp b/ecmascript/compiler/typed_hcr_lowering.cpp index aac76814c51c97faaba66625fc3e5b4d7b880d2a..4b2b1fe32d5abd16c8ad4605711e105cb1b91709 100644 --- a/ecmascript/compiler/typed_hcr_lowering.cpp +++ b/ecmascript/compiler/typed_hcr_lowering.cpp @@ -313,52 +313,52 @@ void TypedHCRLowering::LowerStableArrayCheck(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } -void TypedHCRLowering::SetDeoptTypeInfo(BuiltinTypeId id, DeoptType &type, size_t &typedArrayRootHclassIndex, +void TypedHCRLowering::SetDeoptTypeInfo(JSType jstype, DeoptType &type, size_t &typedArrayRootHclassIndex, size_t &typedArrayRootHclassOnHeapIndex) { type = DeoptType::NOTARRAY1; - switch (id) { - case BuiltinTypeId::INT8_ARRAY: + switch (jstype) { + case JSType::JS_INT8_ARRAY: typedArrayRootHclassIndex = GlobalEnv::INT8_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::INT8_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::UINT8_ARRAY: + case JSType::JS_UINT8_ARRAY: typedArrayRootHclassIndex = GlobalEnv::UINT8_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::UINT8_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::UINT8_CLAMPED_ARRAY: + case JSType::JS_UINT8_CLAMPED_ARRAY: typedArrayRootHclassIndex = GlobalEnv::UINT8_CLAMPED_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::UINT8_CLAMPED_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::INT16_ARRAY: + case JSType::JS_INT16_ARRAY: typedArrayRootHclassIndex = GlobalEnv::INT16_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::INT16_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::UINT16_ARRAY: + case JSType::JS_UINT16_ARRAY: typedArrayRootHclassIndex = GlobalEnv::UINT16_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::UINT16_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::INT32_ARRAY: + case JSType::JS_INT32_ARRAY: typedArrayRootHclassIndex = GlobalEnv::INT32_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::INT32_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::UINT32_ARRAY: + case JSType::JS_UINT32_ARRAY: typedArrayRootHclassIndex = GlobalEnv::UINT32_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::UINT32_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::FLOAT32_ARRAY: + case JSType::JS_FLOAT32_ARRAY: typedArrayRootHclassIndex = GlobalEnv::FLOAT32_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::FLOAT32_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::FLOAT64_ARRAY: + case JSType::JS_FLOAT64_ARRAY: typedArrayRootHclassIndex = GlobalEnv::FLOAT64_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::FLOAT64_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::BIGINT64_ARRAY: + case JSType::JS_BIGINT64_ARRAY: typedArrayRootHclassIndex = GlobalEnv::BIGINT64_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::BIGINT64_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; - case BuiltinTypeId::BIGUINT64_ARRAY: + case JSType::JS_BIGUINT64_ARRAY: typedArrayRootHclassIndex = GlobalEnv::BIGUINT64_ARRAY_ROOT_HCLASS_INDEX; typedArrayRootHclassOnHeapIndex = GlobalEnv::BIGUINT64_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; break; @@ -375,9 +375,10 @@ void TypedHCRLowering::LowerTypedArrayCheck(GateRef gate) size_t typedArrayRootHclassIndex = GlobalEnv::INT8_ARRAY_ROOT_HCLASS_INDEX; size_t typedArrayRootHclassOnHeapIndex = GlobalEnv::INT8_ARRAY_ROOT_HCLASS_ON_HEAP_INDEX; auto deoptType = DeoptType::NOTCHECK; - - auto builtinTypeId = tsManager_->GetTypedArrayBuiltinId(accessor.GetType()); - SetDeoptTypeInfo(builtinTypeId, deoptType, typedArrayRootHclassIndex, typedArrayRootHclassOnHeapIndex); + ParamType paramType = accessor.GetParamType(); + ASSERT(paramType.IsBuiltinType()); + auto builtinType = paramType.GetBuiltinType(); + SetDeoptTypeInfo(builtinType, deoptType, typedArrayRootHclassIndex, typedArrayRootHclassOnHeapIndex); GateRef frameState = GetFrameState(gate); GateRef glueGlobalEnv = builder_.GetGlobalEnv(); @@ -530,25 +531,16 @@ void TypedHCRLowering::LowerRangeCheckPredicate(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } -void TypedHCRLowering::LowerBuiltinPrototypeHClassCheck(GateRef gate) +void TypedHCRLowering::BuiltinInstanceHClassCheck(Environment *env, GateRef gate) { - Environment env(gate, circuit_, &builder_); BuiltinPrototypeHClassAccessor accessor = acc_.GetBuiltinHClassAccessor(gate); BuiltinTypeId type = accessor.GetBuiltinTypeId(); ElementsKind kind = accessor.GetElementsKind(); - bool isPrototypeOfPrototype = accessor.IsPrototypeOfPrototype(); GateRef frameState = GetFrameState(gate); GateRef glue = acc_.GetGlueFromArgList(); - GateRef receiver = acc_.GetValueIn(gate, 0); - builder_.HeapObjectCheck(receiver, frameState); - - JSThread *thread = tsManager_->GetThread(); - // Only HClasses recorded in the JSThread during builtin initialization are available - [[maybe_unused]] JSHClass *initialPrototypeHClass = thread->GetBuiltinPrototypeHClass(type); - ASSERT(initialPrototypeHClass != nullptr); - GateRef ihcMatches = Circuit::NullGate(); + JSThread *thread = tsManager_->GetThread(); if (type == BuiltinTypeId::ARRAY) { if (Elements::IsGeneric(kind)) { auto arrayHClassIndexMap = thread->GetArrayHClassIndexMap(); @@ -564,16 +556,39 @@ void TypedHCRLowering::LowerBuiltinPrototypeHClassCheck(GateRef gate) builder_.NotEqual(elementsKind, builder_.Int32(static_cast(ElementsKind::GENERIC))); } } else { - size_t ihcOffset = JSThread::GlueData::GetBuiltinInstanceHClassOffset(type, env.IsArch32Bit()); + size_t ihcOffset = JSThread::GlueData::GetBuiltinInstanceHClassOffset(type, env->IsArch32Bit()); GateRef initialIhcAddress = builder_.LoadConstOffset(VariableType::JS_POINTER(), glue, ihcOffset); GateRef receiverHClass = builder_.LoadHClassByConstOffset(receiver); - ihcMatches = builder_.Equal(receiverHClass, initialIhcAddress); + if (IsTypedArrayType(type)) { + // check IHC onHeap hclass + size_t ihcOnHeapOffset = JSThread::GlueData::GetBuiltinExtraHClassOffset(type, env->IsArch32Bit()); + GateRef initialIhcOnHeapAddress = builder_.LoadConstOffset(VariableType::JS_POINTER(), + glue, ihcOnHeapOffset); + ihcMatches = builder_.Int64Or(builder_.Equal(receiverHClass, initialIhcAddress), + builder_.Equal(receiverHClass, initialIhcOnHeapAddress)); + } else { + ihcMatches = builder_.Equal(receiverHClass, initialIhcAddress); + } } // De-opt if HClass of x changed where X is the current builtin object. builder_.DeoptCheck(ihcMatches, frameState, DeoptType::BUILTININSTANCEHCLASSMISMATCH); +} + +void TypedHCRLowering::BuiltinPrototypeHClassCheck(Environment *env, GateRef gate) +{ + BuiltinPrototypeHClassAccessor accessor = acc_.GetBuiltinHClassAccessor(gate); + BuiltinTypeId type = accessor.GetBuiltinTypeId(); + bool isPrototypeOfPrototype = accessor.IsPrototypeOfPrototype(); + GateRef frameState = GetFrameState(gate); + GateRef glue = acc_.GetGlueFromArgList(); + GateRef receiver = acc_.GetValueIn(gate, 0); + JSThread *thread = tsManager_->GetThread(); + // Only HClasses recorded in the JSThread during builtin initialization are available + [[maybe_unused]] JSHClass *initialPrototypeHClass = thread->GetBuiltinPrototypeHClass(type); + ASSERT(initialPrototypeHClass != nullptr); // Phc = PrototypeHClass - size_t phcOffset = JSThread::GlueData::GetBuiltinPrototypeHClassOffset(type, env.IsArch32Bit()); + size_t phcOffset = JSThread::GlueData::GetBuiltinPrototypeHClassOffset(type, env->IsArch32Bit()); GateRef receiverPhcAddress = builder_.LoadPrototypeHClass(receiver); GateRef initialPhcAddress = builder_.LoadConstOffset(VariableType::JS_POINTER(), glue, phcOffset); GateRef phcMatches = builder_.Equal(receiverPhcAddress, initialPhcAddress); @@ -582,14 +597,23 @@ void TypedHCRLowering::LowerBuiltinPrototypeHClassCheck(GateRef gate) // array.Iterator should compare PrototypeOfPrototypeHClass. if (isPrototypeOfPrototype) { - size_t pphcOffset = JSThread::GlueData::GetBuiltinPrototypeOfPrototypeHClassOffset(type, env.IsArch32Bit()); + size_t pphcOffset = JSThread::GlueData::GetBuiltinPrototypeOfPrototypeHClassOffset(type, env->IsArch32Bit()); GateRef receiverPPhcAddress = builder_.LoadPrototypeOfPrototypeHClass(receiver); GateRef initialPPhcAddress = builder_.LoadConstOffset(VariableType::JS_POINTER(), glue, pphcOffset); GateRef pphcMatches = builder_.Equal(receiverPPhcAddress, initialPPhcAddress); // De-opt if HClass of X.prototype.prototype changed where X is the current builtin object. builder_.DeoptCheck(pphcMatches, frameState, DeoptType::BUILTINPROTOHCLASSMISMATCH2); } +} +void TypedHCRLowering::LowerBuiltinPrototypeHClassCheck(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef frameState = GetFrameState(gate); + GateRef receiver = acc_.GetValueIn(gate, 0); + builder_.HeapObjectCheck(receiver, frameState); + BuiltinInstanceHClassCheck(&env, gate); // check IHC + BuiltinPrototypeHClassCheck(&env, gate); // check PHC acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } @@ -626,18 +650,21 @@ GateRef TypedHCRLowering::LowerCallRuntime(GateRef glue, GateRef hirGate, int in void TypedHCRLowering::LowerTypeConvert(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto leftType = acc_.GetLeftType(gate); - auto rightType = acc_.GetRightType(gate); + + TypeConvertAccessor accessor(acc_.TryGetValue(gate)); + ParamType leftType = accessor.GetLeftType(); + GateType rightType = accessor.GetRightType(); if (rightType.IsNumberType()) { GateRef value = acc_.GetValueIn(gate, 0); - if (leftType.IsDigitablePrimitiveType()) { + // NOTICE-PGO: wx support undefined/null/boolean type: + if (leftType.HasNumberType()) { LowerPrimitiveToNumber(gate, value, leftType); } return; } } -void TypedHCRLowering::LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType srcType) +void TypedHCRLowering::LowerPrimitiveToNumber(GateRef dst, GateRef src, ParamType srcType) { DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant()); if (srcType.IsBooleanType()) { @@ -658,7 +685,8 @@ void TypedHCRLowering::LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType builder_.Bind(&exit); } else if (srcType.IsUndefinedType()) { result = DoubleToTaggedDoublePtr(builder_.Double(base::NAN_VALUE)); - } else if (srcType.IsBigIntType() || srcType.IsNumberType()) { + } else if (srcType.IsBigIntType() || srcType.HasNumberType()) { + ASSERT(!srcType.IsIntOverflowType()); result = src; } else if (srcType.IsNullType()) { result = IntToTaggedIntPtr(builder_.Int32(0)); @@ -1343,142 +1371,100 @@ void TypedHCRLowering::LowerTypedCallBuitin(GateRef gate) void TypedHCRLowering::LowerJSCallTargetFromDefineFuncCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto type = acc_.GetParamGateType(gate); - if (tsManager_->IsFunctionTypeKind(type)) { - GateRef frameState = GetFrameState(gate); - auto func = acc_.GetValueIn(gate, 0); - GateRef check = builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT); - builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT1); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } + GateRef frameState = GetFrameState(gate); + auto func = acc_.GetValueIn(gate, 0); + GateRef check = builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT); + builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT1); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void TypedHCRLowering::LowerJSCallTargetTypeCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto type = acc_.GetParamGateType(gate); - if (tsManager_->IsFunctionTypeKind(type)) { - ArgumentAccessor argAcc(circuit_); - GateRef frameState = GetFrameState(gate); - GateRef constpool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::CONST_POOL); - auto func = acc_.GetValueIn(gate, 0); - auto methodIndex = acc_.GetValueIn(gate, 1); - GateRef isObj = builder_.TaggedIsHeapObject(func); - GateRef funcMethodTarget = builder_.GetMethodFromFunction(func); - GateRef isOptimized = builder_.JudgeAotAndFastCallWithMethod(funcMethodTarget, - CircuitBuilder::JudgeMethodType::HAS_AOT); - GateRef checkFunc = builder_.BoolAnd(isObj, isOptimized); - GateRef methodTarget = builder_.GetValueFromTaggedArray(constpool, methodIndex); - GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget)); - builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT2); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } + ArgumentAccessor argAcc(circuit_); + GateRef frameState = GetFrameState(gate); + GateRef constpool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::CONST_POOL); + auto func = acc_.GetValueIn(gate, 0); + auto methodIndex = acc_.GetValueIn(gate, 1); + GateRef isObj = builder_.TaggedIsHeapObject(func); + GateRef funcMethodTarget = builder_.GetMethodFromFunction(func); + GateRef isOptimized = builder_.JudgeAotAndFastCallWithMethod(funcMethodTarget, + CircuitBuilder::JudgeMethodType::HAS_AOT); + GateRef checkFunc = builder_.BoolAnd(isObj, isOptimized); + GateRef methodTarget = builder_.GetValueFromTaggedArray(constpool, methodIndex); + GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget)); + builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT2); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void TypedHCRLowering::LowerJSFastCallTargetTypeCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto type = acc_.GetParamGateType(gate); - if (tsManager_->IsFunctionTypeKind(type)) { - ArgumentAccessor argAcc(circuit_); - GateRef frameState = GetFrameState(gate); - GateRef constpool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::CONST_POOL); - auto func = acc_.GetValueIn(gate, 0); - auto methodIndex = acc_.GetValueIn(gate, 1); - GateRef isObj = builder_.TaggedIsHeapObject(func); - GateRef canFastCall = builder_.CanFastCall(func); - GateRef funcMethodTarget = builder_.GetMethodFromFunction(func); - GateRef checkFunc = builder_.BoolAnd(isObj, canFastCall); - GateRef methodTarget = builder_.GetValueFromTaggedArray(constpool, methodIndex); - GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget)); - builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT1); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } + ArgumentAccessor argAcc(circuit_); + GateRef frameState = GetFrameState(gate); + GateRef constpool = argAcc.GetFrameArgsIn(frameState, FrameArgIdx::CONST_POOL); + auto func = acc_.GetValueIn(gate, 0); + auto methodIndex = acc_.GetValueIn(gate, 1); + GateRef isObj = builder_.TaggedIsHeapObject(func); + GateRef canFastCall = builder_.CanFastCall(func); + GateRef funcMethodTarget = builder_.GetMethodFromFunction(func); + GateRef checkFunc = builder_.BoolAnd(isObj, canFastCall); + GateRef methodTarget = builder_.GetValueFromTaggedArray(constpool, methodIndex); + GateRef check = builder_.BoolAnd(checkFunc, builder_.Equal(funcMethodTarget, methodTarget)); + builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT1); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void TypedHCRLowering::LowerJSCallThisTargetTypeCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto type = acc_.GetParamGateType(gate); - if (tsManager_->IsFunctionTypeKind(type)) { - GateRef frameState = GetFrameState(gate); - auto func = acc_.GetValueIn(gate, 0); - GateRef isObj = builder_.TaggedIsHeapObject(func); - GateRef isOptimized = builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT_NOTFASTCALL); - GateRef check = builder_.BoolAnd(isObj, isOptimized); - builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT3); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } + GateRef frameState = GetFrameState(gate); + auto func = acc_.GetValueIn(gate, 0); + GateRef isObj = builder_.TaggedIsHeapObject(func); + GateRef isOptimized = builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT_NOTFASTCALL); + GateRef check = builder_.BoolAnd(isObj, isOptimized); + builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT3); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void TypedHCRLowering::LowerJSNoGCCallThisTargetTypeCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto type = acc_.GetParamGateType(gate); - if (tsManager_->IsFunctionTypeKind(type)) { - GateRef frameState = GetFrameState(gate); - auto func = acc_.GetValueIn(gate, 0); - GateRef isObj = builder_.TaggedIsHeapObject(func); - GateRef isOptimized = builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT_NOTFASTCALL); - GateRef methodId = builder_.GetMethodId(func); - GateRef checkOptimized = builder_.BoolAnd(isObj, isOptimized); - GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1))); - builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT4); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } + GateRef frameState = GetFrameState(gate); + auto func = acc_.GetValueIn(gate, 0); + GateRef isObj = builder_.TaggedIsHeapObject(func); + GateRef isOptimized = builder_.JudgeAotAndFastCall(func, CircuitBuilder::JudgeMethodType::HAS_AOT_NOTFASTCALL); + GateRef methodId = builder_.GetMethodId(func); + GateRef checkOptimized = builder_.BoolAnd(isObj, isOptimized); + GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1))); + builder_.DeoptCheck(check, frameState, DeoptType::NOTJSCALLTGT4); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void TypedHCRLowering::LowerJSFastCallThisTargetTypeCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto type = acc_.GetParamGateType(gate); - if (tsManager_->IsFunctionTypeKind(type)) { - GateRef frameState = GetFrameState(gate); - auto func = acc_.GetValueIn(gate, 0); - GateRef isObj = builder_.TaggedIsHeapObject(func); - GateRef canFastCall = builder_.CanFastCall(func); - GateRef check = builder_.BoolAnd(isObj, canFastCall); - builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT2); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } + GateRef frameState = GetFrameState(gate); + auto func = acc_.GetValueIn(gate, 0); + GateRef isObj = builder_.TaggedIsHeapObject(func); + GateRef canFastCall = builder_.CanFastCall(func); + GateRef check = builder_.BoolAnd(isObj, canFastCall); + builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT2); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void TypedHCRLowering::LowerJSNoGCFastCallThisTargetTypeCheck(GateRef gate) { Environment env(gate, circuit_, &builder_); - auto type = acc_.GetParamGateType(gate); - if (tsManager_->IsFunctionTypeKind(type)) { - GateRef frameState = GetFrameState(gate); - auto func = acc_.GetValueIn(gate, 0); - GateRef isObj = builder_.TaggedIsHeapObject(func); - GateRef canFastCall = builder_.CanFastCall(func); - GateRef methodId = builder_.GetMethodId(func); - GateRef checkOptimized = builder_.BoolAnd(isObj, canFastCall); - GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1))); - builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT3); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); - } else { - LOG_COMPILER(FATAL) << "this branch is unreachable"; - UNREACHABLE(); - } + GateRef frameState = GetFrameState(gate); + auto func = acc_.GetValueIn(gate, 0); + GateRef isObj = builder_.TaggedIsHeapObject(func); + GateRef canFastCall = builder_.CanFastCall(func); + GateRef methodId = builder_.GetMethodId(func); + GateRef checkOptimized = builder_.BoolAnd(isObj, canFastCall); + GateRef check = builder_.BoolAnd(checkOptimized, builder_.Equal(methodId, acc_.GetValueIn(gate, 1))); + builder_.DeoptCheck(check, frameState, DeoptType::NOTJSFASTCALLTGT3); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), Circuit::NullGate()); } void TypedHCRLowering::LowerCallTargetCheck(GateRef gate) @@ -2134,7 +2120,8 @@ void TypedHCRLowering::LowerTypeOfCheck(GateRef gate) Environment env(gate, circuit_, &builder_); GateRef frameState = GetFrameState(gate); GateRef value = acc_.GetValueIn(gate, 0); - GateType type = acc_.GetParamGateType(gate); + GateTypeAccessor accessor(acc_.TryGetValue(gate)); + ParamType type = accessor.GetParamType(); GateRef check = Circuit::NullGate(); if (type.IsNumberType()) { check = builder_.TaggedIsNumber(value); @@ -2144,20 +2131,18 @@ void TypedHCRLowering::LowerTypeOfCheck(GateRef gate) check = builder_.TaggedIsNull(value); } else if (type.IsUndefinedType()) { check = builder_.TaggedIsUndefined(value); - } else if (type.IsStringType()) { - check = builder_.BoolAnd(builder_.TaggedIsHeapObject(value), builder_.TaggedIsString(value)); - } else if (type.IsBigIntType()) { - check = builder_.BoolAnd(builder_.TaggedIsHeapObject(value), builder_.IsJsType(value, JSType::BIGINT)); - } else if (type.IsSymbolType()) { - check = builder_.BoolAnd(builder_.TaggedIsHeapObject(value), builder_.IsJsType(value, JSType::SYMBOL)); - } else if (tsManager_->IsFunctionTypeKind(type) || tsManager_->IsClassTypeKind(type)) { - check = builder_.BoolAnd(builder_.TaggedIsHeapObject(value), builder_.IsCallable(value)); - } else if (tsManager_->IsObjectTypeKind(type) || tsManager_->IsClassInstanceTypeKind(type)) { - check = builder_.BoolAnd(builder_.TaggedIsHeapObject(value), builder_.IsJsType(value, JSType::JS_OBJECT)); - } else if (tsManager_->IsArrayTypeKind(type)) { - check = builder_.BoolAnd(builder_.TaggedIsHeapObject(value), builder_.IsJsType(value, JSType::JS_ARRAY)); } else { - UNREACHABLE(); + // NOTICE-PGO: wx add support for builtin(Function Object ArrayKind) + builder_.DeoptCheck(builder_.TaggedIsHeapObject(value), frameState, DeoptType::INCONSISTENTTYPE1); + if (type.IsStringType()) { + check = builder_.TaggedIsString(value); + } else if (type.IsBigIntType()) { + check = builder_.IsJsType(value, JSType::BIGINT); + } else if (type.IsSymbolType()) { + check = builder_.IsJsType(value, JSType::SYMBOL); + } else { + UNREACHABLE(); + } } builder_.DeoptCheck(check, frameState, DeoptType::INCONSISTENTTYPE1); @@ -2167,10 +2152,12 @@ void TypedHCRLowering::LowerTypeOfCheck(GateRef gate) void TypedHCRLowering::LowerTypeOf(GateRef gate, GateRef glue) { Environment env(gate, circuit_, &builder_); - GateType type = acc_.GetParamGateType(gate); + GateTypeAccessor accessor(acc_.TryGetValue(gate)); + ParamType type = accessor.GetParamType(); GateRef gConstAddr = builder_.Load(VariableType::JS_POINTER(), glue, builder_.IntPtr(JSThread::GlueData::GetGlobalConstOffset(builder_.GetCompilationConfig()->Is32Bit()))); ConstantIndex index; + // NOTICE-PGO: wx add support for builtin(Function Object ArrayKind) if (type.IsNumberType()) { index = ConstantIndex::NUMBER_STRING_INDEX; } else if (type.IsBooleanType()) { @@ -2185,12 +2172,6 @@ void TypedHCRLowering::LowerTypeOf(GateRef gate, GateRef glue) index = ConstantIndex::BIGINT_STRING_INDEX; } else if (type.IsSymbolType()) { index = ConstantIndex::SYMBOL_STRING_INDEX; - } else if (tsManager_->IsFunctionTypeKind(type) || tsManager_->IsClassTypeKind(type)) { - index = ConstantIndex::FUNCTION_STRING_INDEX; - } else if (tsManager_->IsObjectTypeKind(type) || tsManager_->IsClassInstanceTypeKind(type)) { - index = ConstantIndex::OBJECT_STRING_INDEX; - } else if (tsManager_->IsArrayTypeKind(type)) { - index = ConstantIndex::OBJECT_STRING_INDEX; } else { UNREACHABLE(); } diff --git a/ecmascript/compiler/typed_hcr_lowering.h b/ecmascript/compiler/typed_hcr_lowering.h index f5657ee7908039d34c21106029038a267ffdd535..62c79e59b0d749ecd5dd94b4818cc494d4898936 100644 --- a/ecmascript/compiler/typed_hcr_lowering.h +++ b/ecmascript/compiler/typed_hcr_lowering.h @@ -20,6 +20,7 @@ #include "ecmascript/compiler/bytecode_circuit_builder.h" #include "ecmascript/compiler/circuit_builder-inl.h" #include "ecmascript/compiler/combined_pass_visitor.h" +#include "ecmascript/compiler/type_info_accessors.h" namespace panda::ecmascript::kungfu { // TypeHCRLowering Process @@ -126,7 +127,7 @@ private: void LowerType(GateRef gate); void LowerPrimitiveTypeCheck(GateRef gate); void LowerTypeConvert(GateRef gate); - void LowerPrimitiveToNumber(GateRef dst, GateRef src, GateType srcType); + void LowerPrimitiveToNumber(GateRef dst, GateRef src, ParamType srcType); void LowerIntCheck(GateRef gate); void LowerDoubleCheck(GateRef gate); void LowerNumberCheck(GateRef gate); @@ -189,7 +190,7 @@ private: void LowerTypedSuperAllocateThis(GateRef gate, GateRef glue); void LowerGetSuperConstructor(GateRef gate); void LowerJSInlineTargetTypeCheck(GateRef gate); - void SetDeoptTypeInfo(BuiltinTypeId id, DeoptType &type, size_t &typedArrayRootHclassIndex, + void SetDeoptTypeInfo(JSType jstype, DeoptType &type, size_t &typedArrayRootHclassIndex, size_t &typedArrayRootHclassOnHeapIndex); void LowerLookupHolder(GateRef gate); void LowerLoadGetter(GateRef gate); @@ -225,6 +226,8 @@ private: GateRef CallAccessor(GateRef glue, GateRef gate, GateRef function, GateRef receiver, AccessorMode mode, GateRef value = Circuit::NullGate()); + void BuiltinInstanceHClassCheck(Environment *env, GateRef gate); + void BuiltinPrototypeHClassCheck(Environment *env, GateRef gate); void ReplaceHirWithPendingException(GateRef hirGate, GateRef glue, GateRef state, GateRef depend, GateRef value); GateRef DoubleToTaggedDoublePtr(GateRef gate); diff --git a/ecmascript/compiler/typed_native_inline_lowering.cpp b/ecmascript/compiler/typed_native_inline_lowering.cpp index b242f02ae57fb742764c54a45644f2f1c91f29d8..5067ce1c50aec818fa7e8938ede80fee83d4027d 100644 --- a/ecmascript/compiler/typed_native_inline_lowering.cpp +++ b/ecmascript/compiler/typed_native_inline_lowering.cpp @@ -13,8 +13,27 @@ * limitations under the License. */ #include "ecmascript/compiler/typed_native_inline_lowering.h" -#include "ecmascript/compiler/circuit_builder_helper.h" +#include "ecmascript/base/number_helper.h" +#include "ecmascript/builtins/builtins_errors.h" +#include "ecmascript/byte_array.h" +#include "ecmascript/compiler/assembler/assembler.h" +#include "ecmascript/compiler/builtins/builtins_call_signature.h" +#include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/circuit_builder-inl.h" +#include "ecmascript/compiler/circuit_builder.h" +#include "ecmascript/compiler/circuit_builder_helper.h" +#include "ecmascript/compiler/lcr_circuit_builder.h" +#include "ecmascript/compiler/gate.h" +#include "ecmascript/compiler/rt_call_signature.h" +#include "ecmascript/compiler/share_gate_meta_data.h" +#include "ecmascript/compiler/share_opcodes.h" +#include "ecmascript/compiler/variable_type.h" +#include "ecmascript/js_arraybuffer.h" +#include "ecmascript/js_dataview.h" +#include "ecmascript/js_hclass.h" +#include "ecmascript/js_native_pointer.h" +#include "ecmascript/message_string.h" +#include "macros.h" namespace panda::ecmascript::kungfu { GateRef TypedNativeInlineLowering::VisitGate(GateRef gate) @@ -42,6 +61,12 @@ GateRef TypedNativeInlineLowering::VisitGate(GateRef gate) case OpCode::MATH_LOG1P: LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatLog1p)); break; + case OpCode::MATH_EXP: + LowerMathExp(gate); + break; + case OpCode::MATH_EXPM1: + LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatExpm1)); + break; case OpCode::MATH_SINH: LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatSinh)); break; @@ -58,16 +83,16 @@ GateRef TypedNativeInlineLowering::VisitGate(GateRef gate) LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatTanh)); break; case OpCode::MATH_ACOS: - LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAcos)); + LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAcos)); break; case OpCode::MATH_ASIN: - LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAsin)); + LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAsin)); break; case OpCode::MATH_ATANH: - LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAtanh)); + LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAtanh)); break; case OpCode::MATH_ACOSH: - LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAcosh)); + LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatAcosh)); break; case OpCode::MATH_ATAN2: LowerMathAtan2(gate); @@ -75,21 +100,225 @@ GateRef TypedNativeInlineLowering::VisitGate(GateRef gate) case OpCode::MATH_ABS: LowerAbs(gate); break; + case OpCode::MATH_ABS_INT32: + LowerIntAbs(gate); + break; + case OpCode::MATH_ABS_DOUBLE: + LowerDoubleAbs(gate); + break; + case OpCode::MATH_TRUNC: + LowerTrunc(gate); + break; case OpCode::MATH_POW: LowerMathPow(gate); break; + case OpCode::MATH_CBRT: + LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatCbrt)); + break; + case OpCode::MATH_SIGN: + LowerMathSignInt(gate); + break; + case OpCode::MATH_SIGN_TAGGED: + LowerMathSignTagged(gate); + break; + case OpCode::MATH_MIN: + LowerMinMax(gate); + break; + case OpCode::MATH_MAX: + LowerMinMax(gate); + break; + case OpCode::MATH_MIN_INT32: + LowerIntMinMax(gate); + break; + case OpCode::MATH_MAX_INT32: + LowerIntMinMax(gate); + break; + case OpCode::MATH_MIN_DOUBLE: + LowerDoubleMinMax(gate); + break; + case OpCode::MATH_MAX_DOUBLE: + LowerDoubleMinMax(gate); + break; + case OpCode::MATH_CLZ32_DOUBLE: + LowerClz32Float64(gate); + break; + case OpCode::MATH_CLZ32_INT32: + LowerClz32Int32(gate); + break; + case OpCode::MATH_SQRT: + LowerMathSqrt(gate); + break; + case OpCode::MATH_ROUND: + LowerTaggedRounding(gate); + break; + case OpCode::MATH_ROUND_DOUBLE: + case OpCode::MATH_FROUND: + LowerDoubleRounding(gate); + break; + case OpCode::MATH_CEIL: + LowerMathCeilFloor(gate); + break; + case OpCode::MATH_FLOOR: + LowerMathCeilFloor(gate); + break; + case OpCode::MATH_IMUL: + LowerMathImul(gate); + break; + case OpCode::GLOBAL_IS_FINITE: + LowerGlobalIsFinite(gate); + break; + case OpCode::GLOBAL_IS_NAN: + LowerGlobalIsNan(gate); + break; + case OpCode::DATA_VIEW_GET: + LowerDataViewProtoFunc(gate, DataViewProtoFunc::GET); + break; + case OpCode::DATA_VIEW_SET: + LowerDataViewProtoFunc(gate, DataViewProtoFunc::SET); + break; + case OpCode::ARRAY_BUFFER_IS_VIEW: + LowerArrayBufferIsView(gate); + break; + case OpCode::NUMBER_IS_FINITE: + LowerNumberIsFinite(gate); + break; + case OpCode::NUMBER_IS_INTEGER: + LowerNumberIsInteger(gate); + break; + case OpCode::NUMBER_IS_NAN: + LowerNumberIsNaN(gate); + break; + case OpCode::NUMBER_IS_SAFEINTEGER: + LowerNumberIsSafeInteger(gate); + break; + case OpCode::MAP_GET: + LowerToCommonStub(gate, CommonStubCSigns::JSMapGet); + break; default: break; } return Circuit::NullGate(); } +template +void TypedNativeInlineLowering::LowerMathCeilFloor(GateRef gate) +{ + if (builder_.GetCompilationConfig()->IsAArch64()) { + LowerMathCeilFloorWithIntrinsic(gate); + } else { + LowerMathCeilFloorWithRuntimeCall(gate); + } +} + +template +void TypedNativeInlineLowering::LowerMathCeilFloorWithIntrinsic(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue()); + GateRef arg = acc_.GetValueIn(gate, 0); + + if constexpr (IS_CEIL) { + result = builder_.DoubleCeil(arg); + } else { + result = builder_.DoubleFloor(arg); + } + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); +} + +template +void TypedNativeInlineLowering::LowerMathCeilFloorWithRuntimeCall(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue()); + GateRef arg = acc_.GetValueIn(gate, 0); + GateRef glue = acc_.GetGlueFromArgList(); + + if constexpr (IS_CEIL) { + result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatCeil), Gate::InvalidGateRef, {arg}, gate); + } else { + result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatFloor), Gate::InvalidGateRef, {arg}, gate); + } + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); +} +GateRef TypedNativeInlineLowering::LowerGlobalDoubleIsFinite(GateRef value) +{ + // set the sign bit to 0 by shift left then right. + auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1)); + auto res = builder_.Int64LSR(temp, builder_.Int64(1)); + auto abs = builder_.CastInt64ToFloat64(res); + auto result = builder_.DoubleLessThan(abs, builder_.Double(base::POSITIVE_INFINITY)); + return result; +} + +GateRef TypedNativeInlineLowering::LowerGlobalTNumberIsFinite(GateRef value) +{ + ASSERT(!acc_.GetGateType(value).IsNJSValueType()); + DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.Boolean(true)); + + Label isInt(&builder_); + Label notInt(&builder_); + Label exit(&builder_); + builder_.Branch(builder_.TaggedIsInt(value), &isInt, ¬Int); + builder_.Bind(&isInt); + { + result = builder_.Boolean(true); + builder_.Jump(&exit); + } + builder_.Bind(¬Int); + { + result = LowerGlobalDoubleIsFinite(value); + builder_.Jump(&exit); + } + builder_.Bind(&exit); + return *result; +} + +void TypedNativeInlineLowering::LowerGlobalIsFinite(GateRef gate) +{ + GateRef value = acc_.GetValueIn(gate, 0); + Environment env(gate, circuit_, &builder_); + GateRef result = LowerGlobalDoubleIsFinite(value); + + acc_.ReplaceGate(gate, builder_.GetStateDepend(), result); +} + +GateRef TypedNativeInlineLowering::LowerGlobalTNumberIsNan(GateRef value) +{ + ASSERT(!acc_.GetGateType(value).IsNJSValueType()); + DEFVALUE(result, (&builder_), VariableType::BOOL(), builder_.Boolean(false)); + + Label isInt(&builder_); + Label notInt(&builder_); + Label exit(&builder_); + builder_.Branch(builder_.TaggedIsInt(value), &isInt, ¬Int); + builder_.Bind(&isInt); + { + result = builder_.Boolean(false); + builder_.Jump(&exit); + } + builder_.Bind(¬Int); + { + result = builder_.DoubleIsNAN(value); + builder_.Jump(&exit); + } + builder_.Bind(&exit); + return *result; +} + +void TypedNativeInlineLowering::LowerGlobalIsNan(GateRef gate) +{ + GateRef value = acc_.GetValueIn(gate, 0); + Environment env(gate, circuit_, &builder_); + GateRef result = builder_.DoubleIsNAN(value); + + acc_.ReplaceGate(gate, builder_.GetStateDepend(), result); +} + void TypedNativeInlineLowering::LowerMathPow(GateRef gate) { Environment env(gate, circuit_, &builder_); GateRef base = acc_.GetValueIn(gate, 0); GateRef exp = acc_.GetValueIn(gate, 1); - Label exit(&builder_); Label notNan(&builder_); @@ -115,38 +344,39 @@ void TypedNativeInlineLowering::LowerMathPow(GateRef gate) acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); } -template -void TypedNativeInlineLowering::LowerGeneralUnaryMath(GateRef gate, RuntimeStubCSigns::ID stubId) +void TypedNativeInlineLowering::LowerMathExp(GateRef gate) { +#ifdef SUPPORT_LLVM_INTRINSICS_WITH_CALLS Environment env(gate, circuit_, &builder_); + constexpr double one = 1.0; + GateRef base = builder_.Double(std::exp(one)); + GateRef power = acc_.GetValueIn(gate, 0U); - Label exit(&builder_); - Label checkNotPassed(&builder_); + GateRef exp = builder_.DoubleExp(base, power); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), exp); +#else + LowerGeneralUnaryMath(gate, RTSTUB_ID(FloatExp)); +#endif +} - GateRef value = acc_.GetValueIn(gate, 0); - DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(base::NAN_VALUE)); +void TypedNativeInlineLowering::LowerMathImul(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef val1 = acc_.GetValueIn(gate, 0); + GateRef val2 = acc_.GetValueIn(gate, 1); + ASSERT(acc_.GetGateType(val1).IsNJSValueType() && acc_.GetGateType(val2).IsNJSValueType()); - GateRef check; - const double doubleOne = 1.0; - if constexpr (CHECK == TypedNativeInlineLowering::MathTrigonometricCheck::NOT_NAN) { - check = builder_.DoubleIsNAN(value); - } else if constexpr (CHECK == TypedNativeInlineLowering::MathTrigonometricCheck::LT_ONE) { - check = builder_.DoubleLessThan(value, builder_.Double(doubleOne)); - } else if constexpr (CHECK == TypedNativeInlineLowering::MathTrigonometricCheck::ABS_GT_ONE) { - auto gt = builder_.DoubleGreaterThan(value, builder_.Double(doubleOne)); - auto lt = builder_.DoubleLessThan(value, builder_.Double(-doubleOne)); - check = builder_.BoolOr(gt, lt); - } - - BRANCH_CIR(check, &exit, &checkNotPassed); - builder_.Bind(&checkNotPassed); - { - GateRef glue = acc_.GetGlueFromArgList(); - result = builder_.CallNGCRuntime(glue, stubId, Gate::InvalidGateRef, {value}, gate); - builder_.Jump(&exit); - } - builder_.Bind(&exit); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); + GateRef result = builder_.Int32Mul(val1, val2); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); +} + +void TypedNativeInlineLowering::LowerGeneralUnaryMath(GateRef gate, RuntimeStubCSigns::ID stubId) +{ + Environment env(gate, circuit_, &builder_); + GateRef value = acc_.GetValueIn(gate, 0); + GateRef glue = acc_.GetGlueFromArgList(); + GateRef result = builder_.CallNGCRuntime(glue, stubId, Gate::InvalidGateRef, {value}, gate); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } void TypedNativeInlineLowering::LowerMathAtan2(GateRef gate) @@ -154,78 +384,45 @@ void TypedNativeInlineLowering::LowerMathAtan2(GateRef gate) Environment env(gate, circuit_, &builder_); GateRef y = acc_.GetValueIn(gate, 0); GateRef x = acc_.GetValueIn(gate, 1); - - DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(base::NAN_VALUE)); - - Label exit(&builder_); - Label label1(&builder_); - Label label2(&builder_); - Label label3(&builder_); - - auto yIsNan = builder_.DoubleIsNAN(y); - auto xIsNan = builder_.DoubleIsNAN(x); - auto checkNaN = builder_.BoolOr(yIsNan, xIsNan); - BRANCH_CIR(checkNaN, &exit, &label1); - builder_.Bind(&label1); - { - Label label4(&builder_); - auto yIsZero = builder_.DoubleEqual(y, builder_.Double(0.)); - auto xIsMoreZero = builder_.DoubleGreaterThan(x, builder_.Double(0.)); - auto check = builder_.BoolAnd(yIsZero, xIsMoreZero); - BRANCH_CIR(check, &label4, &label2); - builder_.Bind(&label4); - { - result = y; - builder_.Jump(&exit); - } - } - builder_.Bind(&label2); - { - Label label5(&builder_); - auto xIsPositiveInf = builder_.DoubleEqual(x, builder_.Double(std::numeric_limits::infinity())); - BRANCH_CIR(xIsPositiveInf, &label5, &label3); - builder_.Bind(&label5); - { - Label label6(&builder_); - Label label7(&builder_); - auto yPositiveCheck = builder_.DoubleGreaterThanOrEqual(y, builder_.Double(0.)); - BRANCH_CIR(yPositiveCheck, &label6, &label7); - builder_.Bind(&label6); - { - result = builder_.Double(0.0); - builder_.Jump(&exit); - } - builder_.Bind(&label7); - { - result = builder_.Double(-0.0); - builder_.Jump(&exit); - } - } - } - builder_.Bind(&label3); - { - GateRef glue = acc_.GetGlueFromArgList(); - result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatAtan2), Gate::InvalidGateRef, {y, x}, gate); - builder_.Jump(&exit); - } - - builder_.Bind(&exit); - acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); + GateRef glue = acc_.GetGlueFromArgList(); + GateRef result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatAtan2), Gate::InvalidGateRef, {y, x}, gate); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); } // Int abs : The internal representation of an integer is inverse code, // The absolute value of a negative number can be found by inverting it by adding one. +GateRef TypedNativeInlineLowering::BuildIntAbs(GateRef value) +{ + ASSERT(acc_.GetMachineType(value) == MachineType::I32); + if (isLiteCG_) { + auto temp = builder_.Int32ASR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET)); + auto res = builder_.Int32Xor(value, temp); + return builder_.Int32Sub(res, temp); + } + return builder_.Abs(value); +} // Float abs : A floating-point number is composed of mantissa and exponent. // The length of mantissa will affect the precision of the number, and its sign will determine the sign of the number. // The absolute value of a floating-point number can be found by setting mantissa sign bit to 0. -void TypedNativeInlineLowering::LowerAbs(GateRef gate) +GateRef TypedNativeInlineLowering::BuildDoubleAbs(GateRef value) { - Environment env(gate, circuit_, &builder_); - Label exit(&builder_); - GateRef param = acc_.GetValueIn(gate, 0); + ASSERT(acc_.GetMachineType(value) == MachineType::F64); + if (isLiteCG_) { + // set the sign bit to 0 by shift left then right. + auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1)); + auto res = builder_.Int64LSR(temp, builder_.Int64(1)); + return builder_.CastInt64ToFloat64(res); + } + return builder_.FAbs(value); +} + +GateRef TypedNativeInlineLowering::BuildTNumberAbs(GateRef param) +{ + ASSERT(!acc_.GetGateType(param).IsNJSValueType()); DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.HoleConstant()); + Label exit(&builder_); Label isInt(&builder_); Label notInt(&builder_); Label isIntMin(&builder_); @@ -238,9 +435,7 @@ void TypedNativeInlineLowering::LowerAbs(GateRef gate) BRANCH_CIR(builder_.Equal(value, builder_.Int32(INT32_MIN)), &isIntMin, &isResultInt); builder_.Bind(&isResultInt); { - auto temp = builder_.Int32ASR(value, builder_.Int32(JSTaggedValue::INT_SIGN_BIT_OFFSET)); - auto res = builder_.Int32Xor(value, temp); - result = builder_.Int32ToTaggedPtr(builder_.Int32Sub(res, temp)); + result = builder_.Int32ToTaggedPtr(BuildIntAbs(value)); builder_.Jump(&intExit); } builder_.Bind(&isIntMin); @@ -255,15 +450,1069 @@ void TypedNativeInlineLowering::LowerAbs(GateRef gate) builder_.Bind(¬Int); { auto value = builder_.GetDoubleOfTDouble(param); - // set the sign bit to 0 by shift left then right. - auto temp = builder_.Int64LSL(builder_.CastDoubleToInt64(value), builder_.Int64(1)); - auto res = builder_.Int64LSR(temp, builder_.Int64(1)); - result = builder_.DoubleToTaggedDoublePtr(builder_.CastInt64ToFloat64(res)); + result = builder_.DoubleToTaggedDoublePtr(BuildDoubleAbs(value)); + builder_.Jump(&exit); + } + builder_.Bind(&exit); + return *result; +} + +void TypedNativeInlineLowering::LowerAbs(GateRef gate) +{ + GateRef value = acc_.GetValueIn(gate, 0); + Environment env(gate, circuit_, &builder_); + GateRef res = BuildTNumberAbs(value); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), res); +} + +GateRef TypedNativeInlineLowering::BuildRounding(GateRef gate, GateRef value, OpCode op) +{ + if (op == OpCode::MATH_ROUND || op == OpCode::MATH_ROUND_DOUBLE) { + Label entry(&builder_); + builder_.SubCfgEntry(&entry); + const double diff = 0.5; + GateRef diffValue = builder_.Double(diff); + const double zero = 0.0; + Label subOne(&builder_); + Label exit(&builder_); + Label retCeil(&builder_); + Label nonZero(&builder_); + DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.Double(zero)); + // 0 <= x < 0.5, return 0 + GateRef returnZero = builder_.BoolAnd(builder_.DoubleLessThan(value, diffValue), + builder_.DoubleGreaterThan(value, builder_.Double(zero))); + BRANCH_CIR(returnZero, &exit, &nonZero); + builder_.Bind(&nonZero); + { + GateRef rounded; + if (builder_.GetCompilationConfig()->IsAArch64() && !isLiteCG_) { + rounded = builder_.DoubleCeil(value); + } else { + GateRef glue = acc_.GetGlueFromArgList(); + rounded = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatCeil), Gate::InvalidGateRef, {value}, gate); + } + // if ceil(x) - x > 0.5, return ceil(x) - 1 + // else return ceil(x) + BRANCH_CIR(builder_.DoubleGreaterThan(builder_.DoubleSub(rounded, value), diffValue), + &subOne, &retCeil); + builder_.Bind(&subOne); + { + result = builder_.DoubleSub(rounded, builder_.Double(1U)); + builder_.Jump(&exit); + } + builder_.Bind(&retCeil); + result = rounded; + builder_.Jump(&exit); + } + builder_.Bind(&exit); + GateRef res = *result; + builder_.SubCfgExit(); + return res; + } else if (op == OpCode::MATH_FROUND) { + return builder_.ExtFloat32ToDouble(builder_.TruncDoubleToFloat32(value)); + } else { + UNREACHABLE(); + } +} + +void TypedNativeInlineLowering::LowerTaggedRounding(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + + DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue()); + + GateRef in = acc_.GetValueIn(gate, 0); + Label isInt(&builder_); + Label isDouble(&builder_); + Label exit(&builder_); + + builder_.Branch(builder_.TaggedIsInt(in), &isInt, &isDouble); + builder_.Bind(&isInt); + { + result = builder_.GetDoubleOfTInt(in); builder_.Jump(&exit); } + builder_.Bind(&isDouble); + { + GateRef value = builder_.GetDoubleOfTDouble(in); + result = BuildRounding(gate, value, acc_.GetOpCode(gate)); + builder_.Jump(&exit); + } + builder_.Bind(&exit); acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); } +void TypedNativeInlineLowering::LowerDoubleRounding(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef value = acc_.GetValueIn(gate, 0); + GateRef res = BuildRounding(gate, value, acc_.GetOpCode(gate)); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), res); +} + +void TypedNativeInlineLowering::LowerIntAbs(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef value = acc_.GetValueIn(gate, 0); + auto frameState = FindFrameState(gate); + builder_.DeoptCheck(builder_.NotEqual(value, builder_.Int32(INT32_MIN)), frameState, DeoptType::NOTINT3); + GateRef res = BuildIntAbs(value); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), res); +} + +void TypedNativeInlineLowering::LowerDoubleAbs(GateRef gate) +{ + GateRef value = acc_.GetValueIn(gate, 0); + Environment env(gate, circuit_, &builder_); + GateRef res = BuildDoubleAbs(value); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), res); +} + +// for min select in1 if int1 < int2, in2 otherwise +template +GateRef TypedNativeInlineLowering::BuildIntMinMax(GateRef int1, GateRef int2, GateRef in1, GateRef in2) +{ + Label entry(&builder_); + builder_.SubCfgEntry(&entry); + // int or tagged + VariableType type {acc_.GetMachineType(in1), acc_.GetGateType(in1)}; + DEFVALUE(result, (&builder_), type, (IS_MAX ? in1 : in2)); + Label left(&builder_); + Label exit(&builder_); + builder_.Branch(builder_.Int32LessThan(int1, int2), &left, &exit); + builder_.Bind(&left); + { + result = IS_MAX ? in2 : in1; + builder_.Jump(&exit); + } + builder_.Bind(&exit); + GateRef res = *result; + builder_.SubCfgExit(); + return res; +} + +template +GateRef TypedNativeInlineLowering::BuildIntMinMax(GateRef in1, GateRef in2) +{ + ASSERT(acc_.GetMachineType(in1) == MachineType::I32); + ASSERT(acc_.GetMachineType(in2) == MachineType::I32); + if (isLiteCG_) { + return BuildIntMinMax(in1, in2, in1, in2); + } + return IS_MAX ? builder_.Int32Max(in1, in2) : builder_.Int32Min(in1, in2); +} + +/* for min select: + * NaN if double1 or double2 is NaN + * in1 if double1 and double2 are equal and in1 is negative zero + * in1 if double1 < double2, in2 otherwise */ +template +GateRef TypedNativeInlineLowering::BuildDoubleMinMax(GateRef double1, GateRef double2, GateRef in1, GateRef in2) +{ + Label entry(&builder_); + builder_.SubCfgEntry(&entry); + GateRef nanValue = builder_.NanValue(); + if (in1 != double1) { // case when in1 and in2 are tagged + nanValue = builder_.DoubleToTaggedDoublePtr(nanValue); + } + // double or tagged + VariableType type {acc_.GetMachineType(in1), acc_.GetGateType(in1)}; + DEFVALUE(result, (&builder_), type, nanValue); + Label left(&builder_); + Label rightOrZeroOrNan(&builder_); + Label right(&builder_); + Label exit(&builder_); + Label equal(&builder_); + Label equalOrNan(&builder_); + builder_.Branch(builder_.DoubleLessThan(double1, double2), &left, &rightOrZeroOrNan); + builder_.Bind(&rightOrZeroOrNan); + { + builder_.Branch(builder_.DoubleGreaterThan(double1, double2), &right, &equalOrNan); + builder_.Bind(&equalOrNan); + { + builder_.Branch(builder_.DoubleEqual(double1, double2), &equal, &exit); + builder_.Bind(&equal); + { + // Whether to return in1 or in2 matters only in case of 0, -0 + const double negZero = -0.0; + GateRef negZeroValue = builder_.CastDoubleToInt64(builder_.Double(negZero)); + builder_.Branch(builder_.Equal(builder_.CastDoubleToInt64(double1), negZeroValue), &left, &right); + } + } + builder_.Bind(&right); + { + result = IS_MAX ? in1 : in2; + builder_.Jump(&exit); + } + } + builder_.Bind(&left); + { + result = IS_MAX ? in2 : in1; + builder_.Jump(&exit); + } + builder_.Bind(&exit); + GateRef res = *result; + builder_.SubCfgExit(); + return res; +} + +template +GateRef TypedNativeInlineLowering::BuildDoubleMinMax(GateRef in1, GateRef in2) +{ + ASSERT(acc_.GetMachineType(in1) == MachineType::F64); + ASSERT(acc_.GetMachineType(in2) == MachineType::F64); + if (!isLiteCG_ && builder_.GetCompilationConfig()->IsAArch64()) { + return IS_MAX ? builder_.DoubleMax(in1, in2) : builder_.DoubleMin(in1, in2); + } + return BuildDoubleMinMax(in1, in2, in1, in2); } +template +void TypedNativeInlineLowering::LowerTNumberMinMax(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef in1 = acc_.GetValueIn(gate, 0); + GateRef in2 = acc_.GetValueIn(gate, 1); + GateRef nanValue = builder_.DoubleToTaggedDoublePtr(builder_.NanValue()); + DEFVALUE(result, (&builder_), VariableType::JS_ANY(), nanValue); + DEFVALUE(double1, (&builder_), VariableType::FLOAT64(), builder_.Double(0)); + DEFVALUE(double2, (&builder_), VariableType::FLOAT64(), builder_.Double(0)); + + Label isInt1(&builder_); + Label isInt2(&builder_); + Label isDouble1(&builder_); + Label isDouble2(&builder_); + Label doubleExit(&builder_); + Label exit(&builder_); + builder_.Branch(builder_.TaggedIsInt(in1), &isInt1, &isDouble1); + { + builder_.Bind(&isInt1); + GateRef int1 = builder_.GetInt32OfTInt(in1); + builder_.Branch(builder_.TaggedIsInt(in2), &isInt2, &isDouble2); + { + builder_.Bind(&isInt2); + GateRef int2 = builder_.GetInt32OfTInt(in2); + result = BuildIntMinMax(int1, int2, in1, in2); + builder_.Jump(&exit); + } + builder_.Bind(&isDouble2); + double1 = builder_.ChangeInt32ToFloat64(int1); + double2 = builder_.GetDoubleOfTDouble(in2); + builder_.Jump(&doubleExit); + } + { + builder_.Bind(&isDouble1); + double1 = builder_.GetDoubleOfTDouble(in1); + double2 = builder_.GetDoubleOfTNumber(in2); + builder_.Jump(&doubleExit); + } + builder_.Bind(&doubleExit); + result = BuildDoubleMinMax(*double1, *double2, in1, in2); + builder_.Jump(&exit); + + builder_.Bind(&exit); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result); +} + +template +void TypedNativeInlineLowering::LowerMathMinMaxWithIntrinsic(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef in1 = acc_.GetValueIn(gate, 0); + GateRef in2 = acc_.GetValueIn(gate, 1); + GateRef nanValue = builder_.DoubleToTaggedDoublePtr(builder_.NanValue()); + DEFVALUE(result, (&builder_), VariableType::JS_ANY(), nanValue); + + Label intRes(&builder_); + Label doubleRes(&builder_); + Label exit(&builder_); + + builder_.Branch(builder_.BoolAnd(builder_.TaggedIsInt(in1), builder_.TaggedIsInt(in2)), &intRes, &doubleRes); + builder_.Bind(&intRes); + { + GateRef int1 = builder_.GetInt32OfTInt(in1); + GateRef int2 = builder_.GetInt32OfTInt(in2); + GateRef intRet = BuildIntMinMax(int1, int2); + result = builder_.Int32ToTaggedPtr(intRet); + builder_.Jump(&exit); + } + builder_.Bind(&doubleRes); + { + GateRef double1 = builder_.GetDoubleOfTNumber(in1); + GateRef double2 = builder_.GetDoubleOfTNumber(in2); + // LLVM supports lowering of `minimum/maximum` intrinsics on X86 only since version 17 + // see https://github.com/llvm/llvm-project/commit/a82d27a9a6853c96f857ba0f514a78cd03bc5c35 + if (builder_.GetCompilationConfig()->IsAArch64()) { + GateRef doubleRet = IS_MAX ? builder_.DoubleMax(double1, double2) : builder_.DoubleMin(double1, double2); + result = builder_.DoubleToTaggedDoublePtr(doubleRet); + } else { + result = BuildDoubleMinMax(double1, double2, in1, in2); + } + builder_.Jump(&exit); + } + builder_.Bind(&exit); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), *result); +} + +template +void TypedNativeInlineLowering::LowerMinMax(GateRef gate) +{ + if (isLiteCG_) { + LowerTNumberMinMax(gate); + } else { + LowerMathMinMaxWithIntrinsic(gate); + } +} + +template +void TypedNativeInlineLowering::LowerIntMinMax(GateRef gate) +{ + GateRef in1 = acc_.GetValueIn(gate, 0); + GateRef in2 = acc_.GetValueIn(gate, 1); + Environment env(gate, circuit_, &builder_); + GateRef res = BuildIntMinMax(in1, in2); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), res); +} + +template +void TypedNativeInlineLowering::LowerDoubleMinMax(GateRef gate) +{ + GateRef in1 = acc_.GetValueIn(gate, 0); + GateRef in2 = acc_.GetValueIn(gate, 1); + Environment env(gate, circuit_, &builder_); + GateRef res = BuildDoubleMinMax(in1, in2); + acc_.ReplaceGate(gate, builder_.GetStateDepend(), res); +} + +GateRef TypedNativeInlineLowering::FindFrameState(GateRef gate) +{ + while (!acc_.HasFrameState(gate)) { + ASSERT(acc_.GetDependCount(gate) > 0); + gate = acc_.GetDep(gate); + } + return acc_.GetFrameState(gate); +} + +void TypedNativeInlineLowering::LowerClz32Float64(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + Label exit(&builder_); + Label isFinit(&builder_); + + GateRef param = acc_.GetValueIn(gate, 0); + const int32_t defaultReturnValue = 32; + DEFVALUE(result, (&builder_), VariableType::INT32(), builder_.Int32(defaultReturnValue)); + + // NaN, Inf, -Inf after ToUint32 equal 0, so we in advance know result: Clz32(0) = 32 + auto paramCheck = builder_.BoolOr(builder_.DoubleIsNAN(param), builder_.DoubleIsINF(param)); + builder_.Branch(paramCheck, &exit, &isFinit); + builder_.Bind(&isFinit); + { + auto truncedValue = builder_.TruncInt64ToInt32(builder_.TruncFloatToInt64(param)); + result = builder_.CountLeadingZeroes32(truncedValue); + builder_.Jump(&exit); + } + + builder_.Bind(&exit); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); +} + +void TypedNativeInlineLowering::LowerClz32Int32(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef param = acc_.GetValueIn(gate, 0); + GateRef result = builder_.CountLeadingZeroes32(param); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), result); +} + +// Int trunc(x) : return x +// Float trunc(x) : return the integer part removing all fractional digits +void TypedNativeInlineLowering::LowerTrunc(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + GateRef param = acc_.GetValueIn(gate, 0); + DEFVALUE(result, (&builder_), VariableType::FLOAT64(), builder_.NanValue()); + + Label isInt(&builder_); + Label notInt(&builder_); + Label isDouble(&builder_); + Label exit(&builder_); + + BRANCH_CIR(builder_.TaggedIsInt(param), &isInt, ¬Int); + builder_.Bind(&isInt); + { + result = builder_.ChangeInt32ToFloat64(builder_.GetInt32OfTInt(param)); + builder_.Jump(&exit); + } + builder_.Bind(¬Int); + { + BRANCH_CIR(builder_.TaggedIsDouble(param), &isDouble, &exit); + builder_.Bind(&isDouble); + { + GateRef input = builder_.GetDoubleOfTDouble(param); + if (builder_.GetCompilationConfig()->IsAArch64()) { + result = builder_.DoubleTrunc(input); + } else { + GateRef glue = acc_.GetGlueFromArgList(); + result = builder_.CallNGCRuntime(glue, RTSTUB_ID(FloatTrunc), Gate::InvalidGateRef, {input}, gate); + } + builder_.Jump(&exit); + } + } + builder_.Bind(&exit); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); +} + +void TypedNativeInlineLowering::LowerMathSqrt(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + builder_.SetEnvironment(&env); + GateRef param = acc_.GetValueIn(gate, 0); + // 20.2.2.32 + // If value is NAN or negative, include -NaN and -Infinity but not -0.0, the result is NaN + // Assembly instruction support NAN and negative + auto ret = builder_.Sqrt(param); + acc_.SetMachineType(ret, MachineType::F64); + acc_.SetGateType(ret, GateType::NJSValue()); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), ret); +} + +void TypedNativeInlineLowering::LowerArrayBufferIsView(GateRef gate) +{ + Environment env(gate, circuit_, &builder_); + + GateRef arg = acc_.GetValueIn(gate, 0); + DEFVALUE(result, (&builder_), VariableType::JS_ANY(), builder_.TaggedFalse()); + Label exit(&builder_); + Label isDataViewOrTypedArray(&builder_); + Label returnTaggedTrue(&builder_); + BRANCH_CIR(builder_.IsEcmaObject(arg), &isDataViewOrTypedArray, &exit); + builder_.Bind(&isDataViewOrTypedArray); + { + GateRef isDataView = builder_.CheckJSType(arg, JSType::JS_DATA_VIEW); + GateRef isTypedArray = builder_.TaggedObjectIsTypedArray(arg); + BRANCH_CIR(builder_.BoolOr(isDataView, isTypedArray), &returnTaggedTrue, &exit); + } + builder_.Bind(&returnTaggedTrue); + { + result = builder_.TaggedTrue(); + builder_.Jump(&exit); + } + builder_.Bind(&exit); + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), *result); +} + +void TypedNativeInlineLowering::LowerDataViewProtoFunc(GateRef gate, DataViewProtoFunc func) +{ + Environment env(gate, circuit_, &builder_); + + Label isNotDetachedBuffer(&builder_); + Label isNotByteArray(&builder_); + Label getPointFromByteArray(&builder_); + Label getPointFromNotByteArray(&builder_); + Label getValueFromBuffer(&builder_); + Label bufferByteLengthIsZero(&builder_); + Label bufferByteLengthIsNotZero(&builder_); + GateRef thisobj = acc_.GetValueIn(gate, 0); + GateRef requestIndex = acc_.GetValueIn(gate, 1); // 1: requestIndex + GateRef builtinId = Circuit::NullGate(); + GateRef isLittleEndian = Circuit::NullGate(); + GateRef frameState = Circuit::NullGate(); + ASSERT(func == DataViewProtoFunc::GET || func == DataViewProtoFunc::SET); + if (func == DataViewProtoFunc::GET) { + builtinId = acc_.GetValueIn(gate, 2); // 2: builtinId + isLittleEndian = acc_.GetValueIn(gate, 3); // 3: isLittleEndian + frameState = acc_.GetValueIn(gate, 4); // 4: frameState + } else if (func == DataViewProtoFunc::SET) { + builtinId = acc_.GetValueIn(gate, 3); // 3: builtinId + isLittleEndian = acc_.GetValueIn(gate, 4); // 4: isLittleEndian + frameState = acc_.GetValueIn(gate, 5); // 5: frameState + } else { + UNREACHABLE(); + } + + GateRef resultfinal = Circuit::NullGate(); + + DEFVALUE(dataPointer, (&builder_), VariableType::NATIVE_POINTER(), builder_.IntPtr(0)); + + builder_.DeoptCheck(builder_.Int32UnsignedLessThan(requestIndex, builder_.Int32(INT32_MAX)), + frameState, + DeoptType::INDEXLESSZEROORINFINITY); + GateRef viewedArrayBufferOffset = builder_.IntPtr(JSDataView::VIEW_ARRAY_BUFFER_OFFSET); + GateRef buffer = builder_.Load(VariableType::JS_ANY(), thisobj, viewedArrayBufferOffset); + BRANCH_CIR(builder_.CheckJSType(buffer, JSType::BYTE_ARRAY), &isNotDetachedBuffer, &isNotByteArray); + builder_.Bind(&isNotByteArray); + { + GateRef dataOffset = builder_.IntPtr(JSArrayBuffer::DATA_OFFSET); + GateRef dataSlot = builder_.Load(VariableType::JS_ANY(), buffer, dataOffset); + builder_.DeoptCheck(builder_.TaggedIsNotNull(dataSlot), frameState, DeoptType::ARRAYBUFFERISDETACHED); + builder_.Jump(&isNotDetachedBuffer); + } + builder_.Bind(&isNotDetachedBuffer); + GateRef byteOffset = builder_.IntPtr(JSDataView::BYTE_OFFSET_OFFSET); + GateRef offset = builder_.Load(VariableType::INT32(), thisobj, byteOffset); + GateRef sizeOffset = builder_.IntPtr(JSDataView::BYTE_LENGTH_OFFSET); + GateRef size = builder_.Load(VariableType::INT32(), thisobj, sizeOffset); + GateRef elementSize = BuiltinIdToSize(builtinId); + GateRef totalSize = builder_.Int32Add(requestIndex, elementSize); + + builder_.DeoptCheck(builder_.Int32LessThan(totalSize, size), frameState, DeoptType::TOTALSIZEOVERFLOW); + GateRef bufferIndex = builder_.Int32Add(requestIndex, offset); + BRANCH_CIR(builder_.CheckJSType(buffer, JSType::BYTE_ARRAY), &getPointFromByteArray, &getPointFromNotByteArray); + builder_.Bind(&getPointFromByteArray); + { + dataPointer = builder_.Load(VariableType::NATIVE_POINTER(), buffer, builder_.IntPtr(ByteArray::DATA_OFFSET)); + builder_.Jump(&getValueFromBuffer); + } + builder_.Bind(&getPointFromNotByteArray); + { + GateRef arrayBufferByteLengthOffset = builder_.IntPtr(JSArrayBuffer::BYTE_LENGTH_OFFSET); + GateRef arrayBufferByteLength = builder_.Load(VariableType::INT32(), buffer, arrayBufferByteLengthOffset); + BRANCH_CIR(builder_.Int32Equal(arrayBufferByteLength, builder_.Int32(0)), + &bufferByteLengthIsZero, + &bufferByteLengthIsNotZero); + builder_.Bind(&bufferByteLengthIsZero); + { + dataPointer = builder_.IntPtr(0); + builder_.Jump(&getValueFromBuffer); + } + builder_.Bind(&bufferByteLengthIsNotZero); + { + GateRef bufferDataOffset = builder_.IntPtr(JSArrayBuffer::DATA_OFFSET); + GateRef data = builder_.Load(VariableType::JS_ANY(), buffer, bufferDataOffset); + GateRef externalPointerOffset = builder_.IntPtr(JSNativePointer::POINTER_OFFSET); + GateRef externalPointer = builder_.Load(VariableType::NATIVE_POINTER(), data, externalPointerOffset); + dataPointer = externalPointer; + builder_.Jump(&getValueFromBuffer); + } + } + builder_.Bind(&getValueFromBuffer); + ASSERT(func == DataViewProtoFunc::GET || func == DataViewProtoFunc::SET); + if (func == DataViewProtoFunc::GET) { + resultfinal = GetValueFromBuffer(bufferIndex, *dataPointer, isLittleEndian, builtinId); + } else if (func == DataViewProtoFunc::SET) { + GateRef value = acc_.GetValueIn(gate, 2); // 2: value + resultfinal = + SetValueInBuffer(bufferIndex, value, *dataPointer, isLittleEndian, builtinId, acc_.GetGlueFromArgList()); + } else { + UNREACHABLE(); + } + + acc_.ReplaceGate(gate, builder_.GetState(), builder_.GetDepend(), resultfinal); +} + +GateRef TypedNativeInlineLowering::BuiltinIdToSize(GateRef ID) +{ + auto builtinsID = static_cast(acc_.GetConstantValue(ID)); + switch (builtinsID) { + case BuiltinsStubCSigns::ID::DataViewGetInt8: + case BuiltinsStubCSigns::ID::DataViewGetUint8: + case BuiltinsStubCSigns::ID::DataViewSetUint8: + case BuiltinsStubCSigns::ID::DataViewSetInt8: + return builder_.Int32(ElmentSize::BITS_8); + case BuiltinsStubCSigns::ID::DataViewGetInt16: + case BuiltinsStubCSigns::ID::DataViewGetUint16: + case BuiltinsStubCSigns::ID::DataViewSetInt16: + case BuiltinsStubCSigns::ID::DataViewSetUint16: + return builder_.Int32(ElmentSize::BITS_16); + case BuiltinsStubCSigns::ID::DataViewGetUint32: + case BuiltinsStubCSigns::ID::DataViewGetInt32: + case BuiltinsStubCSigns::ID::DataViewGetFloat32: + case BuiltinsStubCSigns::ID::DataViewSetUint32: + case BuiltinsStubCSigns::ID::DataViewSetInt32: + case BuiltinsStubCSigns::ID::DataViewSetFloat32: + return builder_.Int32(ElmentSize::BITS_32); + case BuiltinsStubCSigns::ID::DataViewGetFloat64: + case BuiltinsStubCSigns::ID::DataViewSetFloat64: + return builder_.Int32(ElmentSize::BITS_64); + default: + UNREACHABLE(); + } +} +GateRef TypedNativeInlineLowering::GetValueFromBuffer(GateRef bufferIndex, + GateRef dataPointer, + GateRef isLittleEndian, + GateRef ID) +{ + Label entry(&builder_); + builder_.SubCfgEntry(&entry); + Label exit(&builder_); + Label littleEndian(&builder_); + Label bigEndian(&builder_); + Label passResult(&builder_); + GateRef finalResult = builder_.NullConstant(); + BuiltinsStubCSigns::ID builtinsID = static_cast(acc_.GetConstantValue(ID)); + switch (builtinsID) { + case BuiltinsStubCSigns::ID::DataViewGetUint8: { + GateRef uint8Res = builder_.Load(VariableType::INT8(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + finalResult = builder_.ZExtInt8ToInt64(uint8Res); + builder_.Jump(&exit); + break; + } + case BuiltinsStubCSigns::ID::DataViewGetInt8: { + GateRef int8res = builder_.Load(VariableType::INT8(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + finalResult = builder_.SExtInt8ToInt64(int8res); + builder_.Jump(&exit); + break; + } + case BuiltinsStubCSigns::ID::DataViewGetUint16: { + DEFVALUE(tempRes, (&builder_), VariableType::INT32(), builder_.Int32(0)); + GateRef uint16Res = builder_.Load(VariableType::INT16(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + BRANCH_CIR(builder_.TaggedIsFalse(isLittleEndian), &bigEndian, &littleEndian); + builder_.Bind(&littleEndian); + { + tempRes = builder_.ZExtInt16ToInt32(uint16Res); + builder_.Jump(&passResult); + } + builder_.Bind(&bigEndian); + { + GateRef bigEndianInt16 = builder_.Int16ToBigEndianInt16(uint16Res); + tempRes = builder_.ZExtInt16ToInt32(bigEndianInt16); + builder_.Jump(&passResult); + } + builder_.Bind(&passResult); + { + finalResult = *tempRes; + builder_.Jump(&exit); + } + break; + } + case BuiltinsStubCSigns::ID::DataViewGetInt16: { + DEFVALUE(tempRes, (&builder_), VariableType::INT16(), builder_.Int16(0)); + GateRef int16Res = builder_.Load(VariableType::INT16(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + BRANCH_CIR(builder_.TaggedIsFalse(isLittleEndian), &bigEndian, &littleEndian); + builder_.Bind(&littleEndian); + { + tempRes = int16Res; + builder_.Jump(&passResult); + } + builder_.Bind(&bigEndian); + { + tempRes = builder_.Int16ToBigEndianInt16(int16Res); + builder_.Jump(&passResult); + } + builder_.Bind(&passResult); + { + finalResult = *tempRes; + builder_.Jump(&exit); + } + break; + } + case BuiltinsStubCSigns::ID::DataViewGetUint32: { + DEFVALUE(tempRes, (&builder_), VariableType::INT32(), builder_.Int32(0)); + GateRef uint32Res = builder_.Load(VariableType::INT32(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + BRANCH_CIR(builder_.TaggedIsFalse(isLittleEndian), &bigEndian, &littleEndian); + builder_.Bind(&littleEndian); + { + tempRes = uint32Res; + builder_.Jump(&passResult); + } + builder_.Bind(&bigEndian); + { + tempRes = builder_.Int32ToBigEndianInt32(uint32Res); + builder_.Jump(&passResult); + } + builder_.Bind(&passResult); + { + finalResult = *tempRes; + builder_.Jump(&exit); + } + break; + } + case BuiltinsStubCSigns::ID::DataViewGetInt32: { + DEFVALUE(tempRes, (&builder_), VariableType::INT32(), builder_.Int32(0)); + GateRef int32Res = builder_.Load(VariableType::INT32(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + BRANCH_CIR(builder_.TaggedIsFalse(isLittleEndian), &bigEndian, &littleEndian); + builder_.Bind(&littleEndian); + { + tempRes = int32Res; + builder_.Jump(&passResult); + } + builder_.Bind(&bigEndian); + { + tempRes = builder_.Int32ToBigEndianInt32(int32Res); + builder_.Jump(&passResult); + } + builder_.Bind(&passResult); + { + finalResult = *tempRes; + builder_.Jump(&exit); + } + break; + } + case BuiltinsStubCSigns::ID::DataViewGetFloat32: { + DEFVALUE(tempRes, (&builder_), VariableType::FLOAT64(), builder_.Double(base::NAN_VALUE)); + Label notNaN(&builder_); + GateRef int32Res = builder_.Load(VariableType::INT32(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + BRANCH_CIR(builder_.TaggedIsFalse(isLittleEndian), &bigEndian, &littleEndian); + builder_.Bind(&littleEndian); + { + GateRef float32Res = builder_.CastInt32ToFloat32(int32Res); + tempRes = builder_.ExtFloat32ToDouble(float32Res); + builder_.Jump(&passResult); + } + builder_.Bind(&bigEndian); + { + GateRef originFloat32Res = builder_.CastInt32ToFloat32(int32Res); + GateRef originDoubleRes = builder_.ExtFloat32ToDouble(originFloat32Res); + BRANCH_CIR(builder_.DoubleIsNAN(originDoubleRes), &passResult, ¬NaN); + builder_.Bind(¬NaN); + { + GateRef bigEndianInt32Res = builder_.Int32ToBigEndianInt32(int32Res); + GateRef float32Res = builder_.CastInt32ToFloat32(bigEndianInt32Res); + tempRes = builder_.ExtFloat32ToDouble(float32Res); + builder_.Jump(&passResult); + } + } + builder_.Bind(&passResult); + { + finalResult = *tempRes; + builder_.Jump(&exit); + } + break; + } + case BuiltinsStubCSigns::ID::DataViewGetFloat64: { + DEFVALUE(tempRes, (&builder_), VariableType::FLOAT64(), builder_.Double(base::NAN_VALUE)); + Label notNaN(&builder_); + GateRef int64Res = builder_.Load(VariableType::INT64(), dataPointer, builder_.ZExtInt32ToPtr(bufferIndex)); + BRANCH_CIR(builder_.TaggedIsFalse(isLittleEndian), &bigEndian, &littleEndian); + builder_.Bind(&littleEndian); + { + tempRes = builder_.CastInt64ToFloat64(int64Res); + builder_.Jump(&passResult); + } + builder_.Bind(&bigEndian); + { + GateRef originFloat64Res = builder_.CastInt64ToFloat64(int64Res); + BRANCH_CIR(builder_.DoubleIsNAN(originFloat64Res), &passResult, ¬NaN); + builder_.Bind(¬NaN); + { + GateRef bigEndianInt64Res = builder_.Int64ToBigEndianInt64(int64Res); + tempRes = builder_.CastInt64ToFloat64(bigEndianInt64Res); + builder_.Jump(&passResult); + } + } + builder_.Bind(&passResult); + { + finalResult = *tempRes; + builder_.Jump(&exit); + } + break; + } + default: + UNREACHABLE(); + } + builder_.Bind(&exit); + builder_.SubCfgExit(); + return finalResult; +} + +GateRef TypedNativeInlineLowering::SetValueInBuffer( + GateRef bufferIndex, GateRef value, GateRef dataPointer, GateRef isLittleEndian, GateRef ID, GateRef glue) +{ + Label entry(&builder_); + builder_.SubCfgEntry(&entry); + Label exit(&builder_); + + Label littleEndian(&builder_); + Label bigEndian(&builder_); + Label passResult(&builder_); + GateRef offset = builder_.ZExtInt32ToPtr(bufferIndex); + GateRef int64Value = builder_.TruncFloatToInt64(value); + BuiltinsStubCSigns::ID builtinsID = static_cast(acc_.GetConstantValue(ID)); + + switch (builtinsID) { + case BuiltinsStubCSigns::ID::DataViewSetUint8: + case BuiltinsStubCSigns::ID::DataViewSetInt8: { + GateRef int32Value = builder_.TruncInt64ToInt32(int64Value); + builder_.Store(VariableType::INT8(), glue, dataPointer, offset, builder_.TruncInt32ToInt8(int32Value)); + builder_.Jump(&exit); + break; + } + case BuiltinsStubCSigns::ID::DataViewSetUint16: + case BuiltinsStubCSigns::ID::DataViewSetInt16: { + BRANCH_CIR(builder_.TaggedIsTrue(isLittleEndian), &littleEndian, &bigEndian); + builder_.Bind(&littleEndian); + { + builder_.Store( + VariableType::INT16(), glue, dataPointer, offset, builder_.TruncInt64ToInt16(int64Value)); + builder_.Jump(&exit); + } + builder_.Bind(&bigEndian); + { + GateRef int16Value = builder_.TruncInt64ToInt16(int64Value); + GateRef bigEndianInt16 = builder_.Int16ToBigEndianInt16(int16Value); + builder_.Store(VariableType::INT16(), glue, dataPointer, offset, bigEndianInt16); + builder_.Jump(&exit); + } + break; + } + case BuiltinsStubCSigns::ID::DataViewSetFloat32: { + Label isNaN(&builder_); + Label notNaN(&builder_); + GateRef float32Value = builder_.TruncDoubleToFloat32(value); + BRANCH_CIR(builder_.DoubleIsNAN(value), &isNaN, ¬NaN); + builder_.Bind(&isNaN); + { + builder_.Store(VariableType::FLOAT32(), glue, dataPointer, offset, float32Value); + builder_.Jump(&exit); + } + builder_.Bind(¬NaN); + { + BRANCH_CIR(builder_.TaggedIsTrue(isLittleEndian), &littleEndian, &bigEndian); + builder_.Bind(&littleEndian); + { + builder_.Store(VariableType::FLOAT32(), glue, dataPointer, offset, float32Value); + builder_.Jump(&exit); + } + builder_.Bind(&bigEndian); + { + GateRef int32Value = builder_.CastFloat32ToInt32(float32Value); + GateRef bigEndianInt32Value = builder_.Int32ToBigEndianInt32(int32Value); + GateRef bigEndianFloat32Value = builder_.CastInt32ToFloat32(bigEndianInt32Value); + builder_.Store(VariableType::FLOAT32(), glue, dataPointer, offset, bigEndianFloat32Value); + builder_.Jump(&exit); + } + } + break; + } + case BuiltinsStubCSigns::ID::DataViewSetInt32: + case BuiltinsStubCSigns::ID::DataViewSetUint32: { + BRANCH_CIR(builder_.TaggedIsTrue(isLittleEndian), &littleEndian, &bigEndian); + builder_.Bind(&littleEndian); + { + builder_.Store( + VariableType::INT32(), glue, dataPointer, offset, builder_.TruncInt64ToInt32(int64Value)); + builder_.Jump(&exit); + } + builder_.Bind(&bigEndian); + { + GateRef int32Value = builder_.TruncInt64ToInt32(int64Value); + GateRef bigEndianInt32 = builder_.Int32ToBigEndianInt32(int32Value); + builder_.Store(VariableType::INT32(), glue, dataPointer, offset, bigEndianInt32); + builder_.Jump(&exit); + } + break; + } + case BuiltinsStubCSigns::ID::DataViewSetFloat64: { + Label isNaN(&builder_); + Label notNaN(&builder_); + BRANCH_CIR(builder_.DoubleIsNAN(value), &isNaN, ¬NaN); + { + builder_.Bind(&isNaN); + { + builder_.Store(VariableType::FLOAT64(), glue, dataPointer, offset, value); + builder_.Jump(&exit); + } + builder_.Bind(¬NaN); + { + BRANCH_CIR(builder_.TaggedIsTrue(isLittleEndian), &littleEndian, &bigEndian); + builder_.Bind(&littleEndian); + { + builder_.Store(VariableType::FLOAT64(), glue, dataPointer, offset, value); + builder_.Jump(&exit); + } + builder_.Bind(&bigEndian); + { + GateRef int64bitsValue = builder_.CastDoubleToInt64(value); + GateRef bigEndianInt64Value = builder_.Int64ToBigEndianInt64(int64bitsValue); + GateRef float64Value = builder_.CastInt64ToFloat64(bigEndianInt64Value); + builder_.Store(VariableType::FLOAT64(), glue, dataPointer, offset, float64Value); + builder_.Jump(&exit); + } + } + } + break; + } + default: + UNREACHABLE(); + } + builder_.Bind(&exit); + builder_.SubCfgExit(); + return builder_.UndefineConstant(); +} + +static void BuildMathSignDouble(Variable *resVarPtr, CircuitBuilder *builder, GateRef param, + std::vector