diff --git a/BUILD.gn b/BUILD.gn index bea20a7536327ea350d4a783d3a49699ed79edf5..da0e9f229353de2a90c3e903462cf871cde0962d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -123,6 +123,7 @@ source_set("libark_js_intl_static") { deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", + "$ark_root/runtime:arkruntime_header_deps", "//third_party/icu/icu4c:shared_icui18n", "//third_party/icu/icu4c:shared_icuuc", sdk_libc_secshared_dep, @@ -131,6 +132,9 @@ source_set("libark_js_intl_static") { config("ark_jsruntime_common_config") { defines = [ "PANDA_ENABLE_LTO" ] + if (enable_stub_aot) { + defines += [ "ECMASCRIPT_ENABLE_STUB_AOT" ] + } if (is_standard_system) { defines += [ "IS_STANDARD_SYSTEM" ] @@ -182,6 +186,15 @@ config("ark_jsruntime_common_config") { "-O0", "-ggdb3", ] + if (is_linux && (current_cpu == "x86" || current_cpu == "x64") && + run_with_asan) { + cflags_cc += [ + "-fsanitize=address", + "-fno-omit-frame-pointer", + ] + ldflags += [ "-L" + rebase_path("${root_out_dir}/ark/ark_js_runtime") ] + libs = [ "clang_rt.asan-x86_64" ] + } } else { defines += [ "NDEBUG" ] } @@ -235,6 +248,7 @@ ecma_source = [ "ecmascript/base/typed_array_helper.cpp", "ecmascript/base/utf_helper.cpp", "ecmascript/builtins.cpp", + "ecmascript/builtins/builtins_ark_tools.cpp", "ecmascript/builtins/builtins_array.cpp", "ecmascript/builtins/builtins_arraybuffer.cpp", "ecmascript/builtins/builtins_async_function.cpp", @@ -328,6 +342,7 @@ ecma_source = [ "ecmascript/mem/c_string.cpp", "ecmascript/mem/chunk.cpp", "ecmascript/mem/compress_collector.cpp", + "ecmascript/mem/concurrent_sweeper.cpp", "ecmascript/mem/ecma_heap_manager.cpp", "ecmascript/mem/free_object_kind.cpp", "ecmascript/mem/free_object_list.cpp", @@ -345,6 +360,9 @@ ecma_source = [ "ecmascript/napi/jsnapi.cpp", "ecmascript/object_factory.cpp", "ecmascript/object_operator.cpp", + "ecmascript/platform/platform.cpp", + "ecmascript/platform/runner.cpp", + "ecmascript/platform/task_queue.cpp", "ecmascript/layout_info.cpp", "ecmascript/regexp/dyn_chunk.cpp", "ecmascript/regexp/regexp_executor.cpp", @@ -361,6 +379,7 @@ ecma_source = [ "ecmascript/vmstat/caller_stat.cpp", "ecmascript/vmstat/runtime_stat.cpp", "ecmascript/weak_vector.cpp", + "ecmascript/compiler/llvm/llvm_stackmap_parser.cpp", ] ecma_source += [ @@ -390,6 +409,11 @@ source_set("libark_jsruntime_static") { } else { deps += [ "$ark_root/runtime:libarkruntime" ] } + + if (is_debug && is_linux && (current_cpu == "x86" || current_cpu == "x64") && + run_with_asan) { + deps += [ ":copy_asan_runtime" ] + } } ohos_shared_library("libark_jsruntime") { @@ -415,14 +439,20 @@ source_set("libark_jsruntime_test_static") { sources += intl_sources deps = [ - ":copy_resource_xml", + ":copy_ark_resource", "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", + "$ark_root/runtime:arkruntime_header_deps", "//third_party/icu/icu4c:shared_icui18n", "//third_party/icu/icu4c:shared_icuuc", sdk_libc_secshared_dep, ] + if (is_debug && is_linux && (current_cpu == "x86" || current_cpu == "x64") && + run_with_asan) { + deps += [ ":copy_asan_runtime" ] + } + public_configs = [ ":ark_jsruntime_public_config", # should add before # arkruntime_public_config @@ -451,24 +481,35 @@ ohos_shared_library("libark_jsruntime_test") { subsystem_name = "test" } -action("copy_resource_xml") { +action("copy_ark_resource") { deps = [] script = "//ark/js_runtime/test/copy_resource.py" - src_path = "//ark/js_runtime/test/resource/js_runtime/" + src_path = "//ark/js_runtime/test/resource/js_runtime" src_xml = "ohos_test.xml" dst_path = "//ark/test/resource/js_runtime/" args = [ "--src-path", - rebase_path(src_path), + rebase_path("${src_path}/"), "--src-xml", src_xml, "--dst-path", rebase_path(dst_path), ] - inputs = [ src_path + src_xml ] + inputs = [ + src_path, + "${src_path}/${src_xml}", + ] outputs = [ "$target_out_dir" ] } + +if (is_debug && is_linux && (current_cpu == "x86" || current_cpu == "x64") && + run_with_asan) { + ohos_copy("copy_asan_runtime") { + sources = [ "${asan_lib_path}/libclang_rt.asan-x86_64.a" ] + outputs = [ "${root_out_dir}/ark/ark_js_runtime/{{source_file_part}}" ] + } +} diff --git a/ecmascript/base/error_helper.cpp b/ecmascript/base/error_helper.cpp index 4b6e4f0df9bed623652c084e429d5441c91e8d70..05dcc8afcfec3295077d2955b1c11956437b540b 100644 --- a/ecmascript/base/error_helper.cpp +++ b/ecmascript/base/error_helper.cpp @@ -19,6 +19,7 @@ #include "ecmascript/ecma_macros.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_env.h" +#include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_object-inl.h" #include "ecmascript/js_tagged_value-inl.h" @@ -192,8 +193,9 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) { auto ecmaVm = thread->GetEcmaVM(); CString data; - EcmaFrameHandler frameHandler(thread); - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + auto sp = const_cast(thread->GetCurrentSPFrame()); + InterpretedFrameHandler frameHandler(sp); + for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { if (frameHandler.IsBreakFrame()) { continue; } diff --git a/ecmascript/base/json_stringifier.cpp b/ecmascript/base/json_stringifier.cpp index 719f4a738ee86ead096a09894121861b53fa861b..56b1a5e0495fa6d56e37836e908c783b57363604 100644 --- a/ecmascript/base/json_stringifier.cpp +++ b/ecmascript/base/json_stringifier.cpp @@ -631,21 +631,23 @@ bool JsonStringifier::SerializeElements(const JSHandle &obj, const JSH } } else { JSHandle numberDic(elementsArr); - CVector sortArr; + CVector> sortArr; int size = numberDic->Size(); for (int hashIndex = 0; hashIndex < size; hashIndex++) { JSTaggedValue key = numberDic->GetKey(hashIndex); if (!key.IsUndefined() && !key.IsHole()) { PropertyAttributes attr = numberDic->GetAttributes(hashIndex); if (attr.IsEnumerable()) { - sortArr.emplace_back(JSTaggedValue(static_cast(key.GetInt()))); + JSTaggedValue numberKey = JSTaggedValue(static_cast(key.GetInt())); + sortArr.emplace_back(JSHandle(thread_, numberKey)); } } } - std::sort(sortArr.begin(), sortArr.end(), NumberDictionary::CompKey); + std::sort(sortArr.begin(), sortArr.end(), CompareNumber); for (const auto &entry : sortArr) { - handleKey_.Update(entry); - int index = numberDic->FindEntry(entry); + JSTaggedValue entryKey = entry.GetTaggedValue(); + handleKey_.Update(entryKey); + int index = numberDic->FindEntry(entryKey); JSTaggedValue value = numberDic->GetValue(index); handleValue_.Update(value); hasContent = JsonStringifier::AppendJsonString(obj, replacer, hasContent); @@ -720,7 +722,7 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl } JSHandle nameDic(propertiesArr); int size = nameDic->Size(); - CVector> sortArr; + CVector, PropertyAttributes>> sortArr; for (int hashIndex = 0; hashIndex < size; hashIndex++) { JSTaggedValue key = nameDic->GetKey(hashIndex); if (!key.IsString()) { @@ -730,13 +732,14 @@ bool JsonStringifier::SerializeKeys(const JSHandle &obj, const JSHandl if (!attr.IsEnumerable()) { continue; } - std::pair pair(key, attr); + std::pair, PropertyAttributes> pair(JSHandle(thread_, key), attr); sortArr.emplace_back(pair); } - std::sort(sortArr.begin(), sortArr.end(), NameDictionary::CompKey); + std::sort(sortArr.begin(), sortArr.end(), CompareKey); for (const auto &entry : sortArr) { - handleKey_.Update(entry.first); - int index = nameDic->FindEntry(entry.first); + JSTaggedValue entryKey = entry.first.GetTaggedValue(); + handleKey_.Update(entryKey); + int index = nameDic->FindEntry(entryKey); JSTaggedValue value = nameDic->GetValue(index); if (UNLIKELY(value.IsAccessor())) { value = JSObject::CallGetter(thread_, AccessorData::Cast(value.GetTaggedObject()), diff --git a/ecmascript/base/json_stringifier.h b/ecmascript/base/json_stringifier.h index 6979f0e3d40f448522363c86aac17fd9e3ac46f3..b4f1401ca7cb55615bcaa2b349aa472367421330 100644 --- a/ecmascript/base/json_stringifier.h +++ b/ecmascript/base/json_stringifier.h @@ -66,7 +66,16 @@ private: bool SerializeElements(const JSHandle &obj, const JSHandle &replacer, bool hasContent); bool SerializeKeys(const JSHandle &obj, const JSHandle &replacer, bool hasContent); - static void FastStorePropertyByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value); + static inline bool CompareKey(const std::pair, PropertyAttributes> &a, + const std::pair, PropertyAttributes> &b) + { + return a.second.GetDictionaryOrder() < b.second.GetDictionaryOrder(); + } + + static inline bool CompareNumber(const JSHandle &a, const JSHandle &b) + { + return a->GetNumber() < b->GetNumber(); + } CString gap_; CString result_; diff --git a/ecmascript/base/utf_helper.cpp b/ecmascript/base/utf_helper.cpp index 25e0995e73e90a9ad62ef737d8dfdddb32f10207..5cb168e06f8e10c0c3fccec8f7e428c0999166a5 100644 --- a/ecmascript/base/utf_helper.cpp +++ b/ecmascript/base/utf_helper.cpp @@ -138,8 +138,14 @@ size_t Utf16ToUtf8Size(const uint16_t *utf16, uint32_t length, bool modify) } else if (utf16[i] < utf::HI_SURROGATE_MIN || utf16[i] > utf::HI_SURROGATE_MAX) { res += UtfLength::THREE; } else { - res += UtfLength::FOUR; - ++i; + if (i < length - 1 && + utf16[i + 1] >= utf::LO_SURROGATE_MIN && // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + utf16[i + 1] <= utf::LO_SURROGATE_MAX) { // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + res += UtfLength::FOUR; + ++i; + } else { + res += UtfLength::THREE; + } } } return res; diff --git a/ecmascript/builtins.cpp b/ecmascript/builtins.cpp index 239543543a0bf7c584273e21edc2885e306bd130..5c32ec6195d83d9e303792d1c529faf181538f42 100644 --- a/ecmascript/builtins.cpp +++ b/ecmascript/builtins.cpp @@ -17,6 +17,7 @@ #include "ecmascript/base/error_type.h" #include "ecmascript/base/number_helper.h" +#include "ecmascript/builtins/builtins_ark_tools.h" #include "ecmascript/builtins/builtins_array.h" #include "ecmascript/builtins/builtins_arraybuffer.h" #include "ecmascript/builtins/builtins_async_function.h" @@ -74,6 +75,7 @@ #include "ecmascript/js_promise.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_relative_time_format.h" +#include "ecmascript/js_runtime_options.h" #include "ecmascript/js_set.h" #include "ecmascript/js_set_iterator.h" #include "ecmascript/js_string_iterator.h" @@ -250,7 +252,6 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread) InitializeString(env, primRefObjDynclass); InitializeArrayBuffer(env, objFuncDynclass); InitializeDataView(env, objFuncDynclass); - InitializeJSNativeObject(env); JSHandle argumentsDynclass = factory_->CreateJSArguments(); env->SetArgumentsClass(thread_, argumentsDynclass); @@ -268,7 +269,7 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread) InitializePromise(env, objFuncDynclass); InitializePromiseJob(env); - RuntimeOptions options = vm_->GetOptions(); + JSRuntimeOptions options = vm_->GetJSOptions(); std::string icuPath = options.GetIcuDataPath(); if (icuPath == "default") { SetHwIcuDirectory(); @@ -302,6 +303,11 @@ void Builtins::InitializeGlobalObject(const JSHandle &env, const JSHa SetFunction(env, globalObject, "stopRuntimeStat", Global::StopRuntimeStat, 0); #endif + JSRuntimeOptions options = vm_->GetJSOptions(); + if (options.IsEnableArkTools()) { + SetConstant(globalObject, "ArkTools", InitializeArkTools(env).GetTaggedValue()); + } + // Global object function SetFunction(env, globalObject, "eval", Global::NotSupportEval, FunctionLength::ONE); SetFunction(env, globalObject, "isFinite", Global::IsFinite, FunctionLength::ONE); @@ -2725,12 +2731,12 @@ void Builtins::InitializePluralRules(const JSHandle &env) SetFunction(env, prPrototype, "resolvedOptions", PluralRules::ResolvedOptions, FunctionLength::ZERO); } -void Builtins::InitializeJSNativeObject(const JSHandle &env) const +JSHandle Builtins::InitializeArkTools(const JSHandle &env) const { [[maybe_unused]] EcmaHandleScope scope(thread_); - JSHandle dynclass = factory_->NewEcmaDynClass(JSNativeObject::SIZE, JSType::JS_NATIVE_OBJECT, - JSHandle(thread_, JSTaggedValue::Null())); - env->SetJSNativeObjectClass(thread_, dynclass); + JSHandle tools = factory_->NewEmptyJSObject(); + SetFunction(env, tools, "print", builtins::BuiltinsArkTools::ObjectDump, FunctionLength::ZERO); + return tools; } } // namespace panda::ecmascript diff --git a/ecmascript/builtins.h b/ecmascript/builtins.h index 7a7753ea9633b6ddcde42fc5ab3ad3e546c9c7bc..63fa4b4fe76e12058165a70e6df98b086b781213 100644 --- a/ecmascript/builtins.h +++ b/ecmascript/builtins.h @@ -208,7 +208,7 @@ private: const JSHandle &getter, const JSHandle &setter) const; void SetGetter(const JSHandle &obj, const JSHandle &key, const JSHandle &getter) const; - void InitializeJSNativeObject(const JSHandle &env) const; + JSHandle InitializeArkTools(const JSHandle &env) const; }; } // namespace panda::ecmascript #endif // ECMASCRIPT_BUILTINS_H diff --git a/ecmascript/builtins/builtins_ark_tools.cpp b/ecmascript/builtins/builtins_ark_tools.cpp new file mode 100644 index 0000000000000000000000000000000000000000..d2b063f546b4a066b0a47eb1ce04749ad703a6f8 --- /dev/null +++ b/ecmascript/builtins/builtins_ark_tools.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2021 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_ark_tools.h" +#include "ecmascript/base/string_helper.h" + +namespace panda::ecmascript::builtins { +using StringHelper = base::StringHelper; + +JSTaggedValue BuiltinsArkTools::ObjectDump(EcmaRuntimeCallInfo *msg) +{ + ASSERT(msg); + JSThread *thread = msg->GetThread(); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle str = JSTaggedValue::ToString(thread, GetCallArg(msg, 0)); + // The default log level of ace_engine and js_runtime is error + LOG(ERROR, RUNTIME) << ": " << base::StringHelper::ToStdString(*str); + + uint32_t numArgs = msg->GetArgsNumber(); + for (uint32_t i = 1; i < numArgs; i++) { + JSHandle obj = GetCallArg(msg, i); + std::ostringstream oss; + obj->Dump(thread, oss); + + // The default log level of ace_engine and js_runtime is error + LOG(ERROR, RUNTIME) << ": " << oss.str(); + } + + return JSTaggedValue::Undefined(); +} +} // namespace panda::ecmascript::builtins diff --git a/ecmascript/builtins/builtins_ark_tools.h b/ecmascript/builtins/builtins_ark_tools.h new file mode 100644 index 0000000000000000000000000000000000000000..f5256bb6d9a4230d10eb2a2732d3dea5345ebbb8 --- /dev/null +++ b/ecmascript/builtins/builtins_ark_tools.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 2021 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_ARK_TOOLS_H +#define ECMASCRIPT_BUILTINS_BUILTINS_ARK_TOOLS_H + +#include "ecmascript/base/builtins_base.h" +#include "ecmascript/js_thread.h" + +namespace panda::ecmascript::builtins { +class BuiltinsArkTools : public base::BuiltinsBase { +public: + // Make sure the ECMASCRIPT_OBJECT_DUMP in config.h has been opened before use it + // Use through arkTools.print(msg, [obj1, obj2, ... objn]) in js + static JSTaggedValue ObjectDump(EcmaRuntimeCallInfo *msg); +}; +} // namespace panda::ecmascript::builtins + +#endif // ECMASCRIPT_BUILTINS_BUILTINS_ARK_TOOLS_H diff --git a/ecmascript/builtins/builtins_promise.cpp b/ecmascript/builtins/builtins_promise.cpp index 0e57dd6ad3e4d824743ad27087d56a4090b933a6..5cdd765d6807ef3b36f28480806671754c84f94c 100644 --- a/ecmascript/builtins/builtins_promise.cpp +++ b/ecmascript/builtins/builtins_promise.cpp @@ -399,14 +399,13 @@ JSTaggedValue BuiltinsPromise::PerformPromiseThen(JSThread *thread, const JSHand if (JSTaggedValue::SameValue(promise->GetPromiseState(), JSTaggedValue(static_cast(PromiseStatus::PENDING)))) { JSHandle fulfillReactions(thread, promise->GetPromiseFulfillReactions()); - auto result = - JSTaggedValue(TaggedQueue::Push(thread, fulfillReactions, JSHandle::Cast(fulfillReaction))); - promise->SetPromiseFulfillReactions(thread, result); + TaggedQueue *newQueue = + TaggedQueue::Push(thread, fulfillReactions, JSHandle::Cast(fulfillReaction)); + promise->SetPromiseFulfillReactions(thread, JSTaggedValue(newQueue)); JSHandle rejectReactions(thread, promise->GetPromiseRejectReactions()); - result = - JSTaggedValue(TaggedQueue::Push(thread, rejectReactions, JSHandle::Cast(rejectReaction))); - promise->SetPromiseRejectReactions(thread, result); + newQueue = TaggedQueue::Push(thread, rejectReactions, JSHandle::Cast(rejectReaction)); + promise->SetPromiseRejectReactions(thread, JSTaggedValue(newQueue)); } else if (JSTaggedValue::SameValue(promise->GetPromiseState(), JSTaggedValue(static_cast(PromiseStatus::FULFILLED)))) { JSHandle argv = factory->NewTaggedArray(2); // 2: 2 means two args stored in array @@ -414,7 +413,7 @@ JSTaggedValue BuiltinsPromise::PerformPromiseThen(JSThread *thread, const JSHand argv->Set(thread, 1, promise->GetPromiseResult()); JSHandle promiseReactionsJob(env->GetPromiseReactionJob()); - job->EnqueueJob(thread, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, argv); + job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, argv); } else if (JSTaggedValue::SameValue(promise->GetPromiseState(), JSTaggedValue(static_cast(PromiseStatus::REJECTED)))) { JSHandle argv = factory->NewTaggedArray(2); // 2: 2 means two args stored in array @@ -422,7 +421,7 @@ JSTaggedValue BuiltinsPromise::PerformPromiseThen(JSThread *thread, const JSHand argv->Set(thread, 1, promise->GetPromiseResult()); JSHandle promiseReactionsJob(env->GetPromiseReactionJob()); - job->EnqueueJob(thread, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, argv); + job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, argv); } return capability->GetPromise(); } diff --git a/ecmascript/builtins/builtins_promise_handler.cpp b/ecmascript/builtins/builtins_promise_handler.cpp index 0d9a8cf690d8a3d8c9d967ad8baedc468aeab296..966e132570fce89cdcf7c879bab3e1054596502d 100644 --- a/ecmascript/builtins/builtins_promise_handler.cpp +++ b/ecmascript/builtins/builtins_promise_handler.cpp @@ -95,7 +95,7 @@ JSTaggedValue BuiltinsPromiseHandler::Resolve(EcmaRuntimeCallInfo *argv) JSHandle promiseResolveThenableJob(env->GetPromiseResolveThenableJob()); JSHandle job = thread->GetEcmaVM()->GetMicroJobQueue(); - job->EnqueueJob(thread, job::QueueType::QUEUE_PROMISE, promiseResolveThenableJob, arguments); + job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseResolveThenableJob, arguments); // 13. Return undefined. return JSTaggedValue::Undefined(); diff --git a/ecmascript/builtins/tests/builtins_promise_test.cpp b/ecmascript/builtins/tests/builtins_promise_test.cpp index cba9fba226c33b3ff291a6e47d94eb437101cff7..d5e7bcb52e9cb1f19e1455523ed29e2145a33064 100644 --- a/ecmascript/builtins/tests/builtins_promise_test.cpp +++ b/ecmascript/builtins/tests/builtins_promise_test.cpp @@ -449,7 +449,7 @@ HWTEST_F_L0(BuiltinsPromiseTest, Race2) */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); if (!thread->HasPendingException()) { - microJobQueue->ExecutePendingJob(thread); + job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -550,7 +550,7 @@ HWTEST_F_L0(BuiltinsPromiseTest, All) */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); if (!thread->HasPendingException()) { - microJobQueue->ExecutePendingJob(thread); + job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -606,7 +606,7 @@ HWTEST_F_L0(BuiltinsPromiseTest, Catch) */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); if (!thread->HasPendingException()) { - microJobQueue->ExecutePendingJob(thread); + job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -664,7 +664,7 @@ HWTEST_F_L0(BuiltinsPromiseTest, ThenResolve) */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); if (!thread->HasPendingException()) { - microJobQueue->ExecutePendingJob(thread); + job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -721,7 +721,7 @@ HWTEST_F_L0(BuiltinsPromiseTest, ThenReject) */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); if (!thread->HasPendingException()) { - microJobQueue->ExecutePendingJob(thread); + job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } } // namespace panda::test diff --git a/ecmascript/class_linker/program_object.h b/ecmascript/class_linker/program_object.h index 6f27229019979cdef004dfa3ee8e465c8ce070c6..df56dea7194f6f7625e764e064aef8bd792d23fc 100644 --- a/ecmascript/class_linker/program_object.h +++ b/ecmascript/class_linker/program_object.h @@ -37,8 +37,8 @@ public: inline void FreeMethodData(RegionFactory *factory); - DECL_DUMP() DECL_VISIT_OBJECT(LOCATION_OFFSET, METHODS_DATA_OFFSET) + DECL_DUMP() }; class LexicalFunction : public ECMAObject { @@ -65,6 +65,7 @@ public: ACCESSORS(Program, PROGRAM_OFFSET, SIZE) DECL_VISIT_OBJECT(NAME_OFFSET, SIZE) + DECL_DUMP() }; class ConstantPool : public TaggedArray { diff --git a/ecmascript/compiler/BUILD.gn b/ecmascript/compiler/BUILD.gn index 0cfb8f7727c12c625442f231d4514592698676f8..a2884c971b76bb9f50f50eeec3b0b0aaf4bc5c88 100644 --- a/ecmascript/compiler/BUILD.gn +++ b/ecmascript/compiler/BUILD.gn @@ -46,8 +46,6 @@ source_set("libark_jsoptimizer_static") { "gate.cpp", "llvm_codegen.cpp", "llvm_ir_builder.cpp", - "llvm_mcjit_engine.cpp", - "llvm_stackmap_parse.cpp", "scheduler.cpp", "stub.cpp", "stub_descriptor.cpp", @@ -107,30 +105,34 @@ source_set("libark_jsoptimizer_static") { "LLVMAsmParser", "LLVMMCParser", "LLVMMIRParser", - "LLVMX86Info", - "LLVMAArch64Info", - "LLVMARMDesc", - "LLVMAArch64Desc", - "LLVMX86Desc", - "LLVMX86Disassembler", - "LLVMARMDisassembler", - "LLVMAArch64Disassembler", "LLVMMCDisassembler", - "LLVMAArch64CodeGen", - "LLVMARMCodeGen", "LLVMCodeGen", - "LLVMX86CodeGen", - "LLVMX86AsmParser", "LLVMTransformUtils", - "LLVMAArch64Utils", + "LLVMIRReader", "LLVMARMUtils", + "LLVMARMCodeGen", + "LLVMARMDisassembler", + "LLVMARMDesc", + "LLVMARMInfo", + "LLVMARMAsmParser", + "LLVMAArch64Utils", + "LLVMAArch64CodeGen", + "LLVMAArch64Info", + "LLVMAArch64Desc", + "LLVMAArch64Disassembler", + "LLVMAArch64AsmParser", "LLVMX86Utils", - "LLVMIRReader", + "LLVMX86AsmParser", + "LLVMX86CodeGen", + "LLVMX86Desc", + "LLVMX86Disassembler", + "LLVMX86Info", ] deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", + "$ark_root/runtime:arkruntime_header_deps", ] } @@ -174,8 +176,16 @@ ohos_shared_library("libark_jsoptimizer_test") { subsystem_name = "test" } +ark_gen_file("stub_aot_options_gen_h") { + template_file = "options.h.erb" + data_file = "stub_aot_options.yaml" + requires = [ "$ark_root/templates/common.rb" ] + output_file = "$target_gen_dir/generated/stub_aot_options_gen.h" +} + ohos_executable("ark_stub_opt") { sources = [ "stub_aot_compiler.cpp" ] + include_dirs = [ "$target_gen_dir" ] configs = [ ":include_llvm", @@ -185,6 +195,7 @@ ohos_executable("ark_stub_opt") { ] deps = [ + ":stub_aot_options_gen_h", "$ark_root/libpandabase:libarkbase", "//ark/js_runtime:libark_jsruntime", "//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer", diff --git a/ecmascript/compiler/circuit.cpp b/ecmascript/compiler/circuit.cpp index ab4a1c23169250e36547149f5b103d29e2af4764..e469311c2e956a0246fbcbf8f07f3dffb36a0fdf 100644 --- a/ecmascript/compiler/circuit.cpp +++ b/ecmascript/compiler/circuit.cpp @@ -182,6 +182,11 @@ MarkCode Circuit::GetMark(AddrShift gate) const return this->LoadGatePtrConst(gate)->GetMark(this->GetTime()); } +TypeCode Circuit::GetTypeCode(AddrShift gate) const +{ + return this->LoadGatePtrConst(gate)->GetTypeCode(); +} + void Circuit::SetMark(AddrShift gate, MarkCode mark) const { const_cast(this->LoadGatePtrConst(gate))->SetMark(mark, this->GetTime()); diff --git a/ecmascript/compiler/circuit.h b/ecmascript/compiler/circuit.h index a331b55a2c85e591f33bfbaa27235b30f49e450e..51da2c17a35b5da28a6dfc338208a559ffb6c7f0 100644 --- a/ecmascript/compiler/circuit.h +++ b/ecmascript/compiler/circuit.h @@ -72,6 +72,7 @@ public: [[nodiscard]] OpCode GetOpCode(AddrShift gate) const; [[nodiscard]] TimeStamp GetTime() const; [[nodiscard]] MarkCode GetMark(AddrShift gate) const; + [[nodiscard]] TypeCode GetTypeCode(AddrShift gate) const; void SetMark(AddrShift gate, MarkCode mark) const; [[nodiscard]] bool Verify(AddrShift gate) const; [[nodiscard]] Gate *LoadGatePtr(AddrShift shift); diff --git a/ecmascript/compiler/circuit_builder.cpp b/ecmascript/compiler/circuit_builder.cpp index 0fcc17683ab076fd3de0ade1fdad8dcc9f3c2fad..ff9f0ba9eb4b358cad9047c42236460ee3c41812 100644 --- a/ecmascript/compiler/circuit_builder.cpp +++ b/ecmascript/compiler/circuit_builder.cpp @@ -155,30 +155,30 @@ AddrShift CircuitBuilder::NewDefaultCase(AddrShift switchBranch) OpCode CircuitBuilder::GetStoreOpCodeFromMachineType(MachineType type) { switch (type) { - case INT8_TYPE: + case MachineType::INT8_TYPE: return OpCode(OpCode::INT8_STORE); - case INT16_TYPE: + case MachineType::INT16_TYPE: return OpCode(OpCode::INT16_STORE); - case INT32_TYPE: + case MachineType::INT32_TYPE: return OpCode(OpCode::INT32_STORE); - case INT64_TYPE: + case MachineType::INT64_TYPE: return OpCode(OpCode::INT64_STORE); - case BOOL_TYPE: + case MachineType::BOOL_TYPE: return OpCode(OpCode::INT32_STORE); - case UINT8_TYPE: + case MachineType::UINT8_TYPE: return OpCode(OpCode::INT8_STORE); - case UINT16_TYPE: + case MachineType::UINT16_TYPE: return OpCode(OpCode::INT16_STORE); - case UINT32_TYPE: + case MachineType::UINT32_TYPE: return OpCode(OpCode::INT32_STORE); - case UINT64_TYPE: - case POINTER_TYPE: - case TAGGED_TYPE: - case TAGGED_POINTER_TYPE: + case MachineType::UINT64_TYPE: + case MachineType::POINTER_TYPE: + case MachineType::TAGGED_TYPE: + case MachineType::TAGGED_POINTER_TYPE: return OpCode(OpCode::INT64_STORE); - case FLOAT32_TYPE: + case MachineType::FLOAT32_TYPE: return OpCode(OpCode::FLOAT32_STORE); - case FLOAT64_TYPE: + case MachineType::FLOAT64_TYPE: return OpCode(OpCode::FLOAT64_STORE); default: UNREACHABLE(); @@ -188,30 +188,30 @@ OpCode CircuitBuilder::GetStoreOpCodeFromMachineType(MachineType type) OpCode CircuitBuilder::GetLoadOpCodeFromMachineType(MachineType type) { switch (type) { - case INT8_TYPE: + case MachineType::INT8_TYPE: return OpCode(OpCode::INT8_LOAD); - case INT16_TYPE: + case MachineType::INT16_TYPE: return OpCode(OpCode::INT16_LOAD); - case INT32_TYPE: + case MachineType::INT32_TYPE: return OpCode(OpCode::INT32_LOAD); - case INT64_TYPE: + case MachineType::INT64_TYPE: return OpCode(OpCode::INT64_LOAD); - case BOOL_TYPE: + case MachineType::BOOL_TYPE: return OpCode(OpCode::INT32_LOAD); - case UINT8_TYPE: + case MachineType::UINT8_TYPE: return OpCode(OpCode::INT8_LOAD); - case UINT16_TYPE: + case MachineType::UINT16_TYPE: return OpCode(OpCode::INT16_LOAD); - case UINT32_TYPE: + case MachineType::UINT32_TYPE: return OpCode(OpCode::INT32_LOAD); - case UINT64_TYPE: - case POINTER_TYPE: - case TAGGED_TYPE: - case TAGGED_POINTER_TYPE: + case MachineType::UINT64_TYPE: + case MachineType::POINTER_TYPE: + case MachineType::TAGGED_TYPE: + case MachineType::TAGGED_POINTER_TYPE: return OpCode(OpCode::INT64_LOAD); - case FLOAT32_TYPE: + case MachineType::FLOAT32_TYPE: return OpCode(OpCode::FLOAT32_LOAD); - case FLOAT64_TYPE: + case MachineType::FLOAT64_TYPE: return OpCode(OpCode::FLOAT64_LOAD); default: UNREACHABLE(); @@ -221,32 +221,32 @@ OpCode CircuitBuilder::GetLoadOpCodeFromMachineType(MachineType type) OpCode CircuitBuilder::GetSelectOpCodeFromMachineType(MachineType type) { switch (type) { - case NONE_TYPE: + case MachineType::NONE_TYPE: return OpCode(OpCode::DEPEND_SELECTOR); - case INT8_TYPE: + case MachineType::INT8_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT8); - case INT16_TYPE: + case MachineType::INT16_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT16); - case INT32_TYPE: + case MachineType::INT32_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT32); - case INT64_TYPE: + case MachineType::INT64_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT64); - case BOOL_TYPE: + case MachineType::BOOL_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT1); - case UINT8_TYPE: + case MachineType::UINT8_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT8); - case UINT16_TYPE: + case MachineType::UINT16_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT16); - case UINT32_TYPE: + case MachineType::UINT32_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT32); - case UINT64_TYPE: - case POINTER_TYPE: - case TAGGED_TYPE: - case TAGGED_POINTER_TYPE: + case MachineType::UINT64_TYPE: + case MachineType::POINTER_TYPE: + case MachineType::TAGGED_TYPE: + case MachineType::TAGGED_POINTER_TYPE: return OpCode(OpCode::VALUE_SELECTOR_INT64); - case FLOAT32_TYPE: + case MachineType::FLOAT32_TYPE: return OpCode(OpCode::VALUE_SELECTOR_FLOAT32); - case FLOAT64_TYPE: + case MachineType::FLOAT64_TYPE: return OpCode(OpCode::VALUE_SELECTOR_FLOAT64); default: UNREACHABLE(); @@ -270,13 +270,13 @@ AddrShift CircuitBuilder::NewDependAnd(std::initializer_list args) AddrShift CircuitBuilder::NewLoadGate(MachineType type, AddrShift val, AddrShift depend) { OpCode op = GetLoadOpCodeFromMachineType(type); - return circuit_->NewGate(op, type, {depend, val}, TypeCode::NOTYPE); + return circuit_->NewGate(op, static_cast(type), {depend, val}, TypeCode::NOTYPE); } AddrShift CircuitBuilder::NewStoreGate(MachineType type, AddrShift ptr, AddrShift val, AddrShift depend) { OpCode op = GetStoreOpCodeFromMachineType(type); - return circuit_->NewGate(op, type, {depend, val, ptr}, TypeCode::NOTYPE); + return circuit_->NewGate(op, static_cast(type), {depend, val, ptr}, TypeCode::NOTYPE); } AddrShift CircuitBuilder::NewArithMeticGate(OpCode opcode, AddrShift left, AddrShift right) @@ -291,82 +291,55 @@ AddrShift CircuitBuilder::NewArithMeticGate(OpCode opcode, AddrShift value) AddrShift CircuitBuilder::NewLogicGate(OpCode opcode, AddrShift left, AddrShift right) { - return circuit_->NewGate(opcode, MachineType::BOOL_TYPE, {left, right}, TypeCode::NOTYPE); + return circuit_->NewGate(opcode, static_cast(MachineType::BOOL_TYPE), {left, right}, TypeCode::NOTYPE); } AddrShift CircuitBuilder::NewLogicGate(OpCode opcode, AddrShift value) { - return circuit_->NewGate(opcode, MachineType::BOOL_TYPE, {value}, TypeCode::NOTYPE); + return circuit_->NewGate(opcode, static_cast(MachineType::BOOL_TYPE), {value}, TypeCode::NOTYPE); } OpCode CircuitBuilder::GetCallOpCodeFromMachineType(MachineType type) { switch (type) { - case NONE_TYPE: + case MachineType::NONE_TYPE: return OpCode(OpCode::CALL); - case INT8_TYPE: + case MachineType::INT8_TYPE: return OpCode(OpCode::INT8_CALL); - case INT16_TYPE: + case MachineType::INT16_TYPE: return OpCode(OpCode::INT16_CALL); - case INT32_TYPE: + case MachineType::INT32_TYPE: return OpCode(OpCode::INT32_CALL); - case INT64_TYPE: + case MachineType::INT64_TYPE: return OpCode(OpCode::INT64_CALL); - case BOOL_TYPE: + case MachineType::BOOL_TYPE: return OpCode(OpCode::INT1_CALL); - case UINT8_TYPE: + case MachineType::UINT8_TYPE: return OpCode(OpCode::INT8_CALL); - case UINT16_TYPE: + case MachineType::UINT16_TYPE: return OpCode(OpCode::INT16_CALL); - case UINT32_TYPE: + case MachineType::UINT32_TYPE: return OpCode(OpCode::INT32_CALL); - case UINT64_TYPE: - case POINTER_TYPE: - case TAGGED_TYPE: - case TAGGED_POINTER_TYPE: + case MachineType::UINT64_TYPE: + case MachineType::POINTER_TYPE: + case MachineType::TAGGED_TYPE: + case MachineType::TAGGED_POINTER_TYPE: return OpCode(OpCode::INT64_CALL); - case FLOAT32_TYPE: + case MachineType::FLOAT32_TYPE: return OpCode(OpCode::FLOAT32_CALL); - case FLOAT64_TYPE: + case MachineType::FLOAT64_TYPE: return OpCode(OpCode::FLOAT64_CALL); default: UNREACHABLE(); } } -AddrShift CircuitBuilder::NewCallGate(StubDescriptor *descriptor, AddrShift target, +AddrShift CircuitBuilder::NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, std::initializer_list args) { std::vector inputs; - auto dependEntry = Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY)); - inputs.push_back(dependEntry); - inputs.push_back(target); - for (auto arg : args) { - inputs.push_back(arg); - } - OpCode opcode = GetCallOpCodeFromMachineType(descriptor->GetReturnType()); - - return circuit_->NewGate(opcode, args.size() + 1, inputs, TypeCode::JS_ANY); -} - -AddrShift CircuitBuilder::NewCallGate(StubDescriptor *descriptor, AddrShift target, AddrShift depend, - std::initializer_list args) -{ - std::vector inputs; - inputs.push_back(depend); - inputs.push_back(target); - for (auto arg : args) { - inputs.push_back(arg); - } - OpCode opcode = GetCallOpCodeFromMachineType(descriptor->GetReturnType()); - return circuit_->NewGate(opcode, args.size() + 1, inputs, TypeCode::JS_ANY); -} - -AddrShift CircuitBuilder::NewCallRuntimeGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, - std::initializer_list args) -{ - ASSERT(descriptor->GetStubKind() == StubDescriptor::RUNTIME_STUB); - std::vector inputs; + // 2 means extra two input gates (target thread) + const size_t extraparamCnt = 2; auto dependEntry = Circuit::GetCircuitRoot(OpCode(OpCode::DEPEND_ENTRY)); inputs.push_back(dependEntry); inputs.push_back(target); @@ -375,14 +348,15 @@ AddrShift CircuitBuilder::NewCallRuntimeGate(StubDescriptor *descriptor, AddrShi inputs.push_back(arg); } OpCode opcode = GetCallOpCodeFromMachineType(descriptor->GetReturnType()); - // 2 : 2 means extra two input gates (target thread ) - return circuit_->NewGate(opcode, args.size() + 2, inputs, TypeCode::JS_ANY); + if (descriptor->GetReturnType() == MachineType::TAGGED_POINTER_TYPE) { + return circuit_->NewGate(opcode, args.size() + extraparamCnt, inputs, TypeCode::TAGGED_POINTER_TYPE); + } + return circuit_->NewGate(opcode, args.size() + extraparamCnt, inputs, TypeCode::JS_ANY); } -AddrShift CircuitBuilder::NewCallRuntimeGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, - AddrShift depend, std::initializer_list args) +AddrShift CircuitBuilder::NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, + AddrShift depend, std::initializer_list args) { - ASSERT(descriptor->GetStubKind() == StubDescriptor::RUNTIME_STUB); std::vector inputs; inputs.push_back(depend); inputs.push_back(target); diff --git a/ecmascript/compiler/circuit_builder.h b/ecmascript/compiler/circuit_builder.h index d027c77c4876502ed9faacaee6eaeab2fb661417..11e12674b7d620805467313737930e51ba397a00 100644 --- a/ecmascript/compiler/circuit_builder.h +++ b/ecmascript/compiler/circuit_builder.h @@ -59,12 +59,9 @@ public: AddrShift NewArithMeticGate(OpCode opcode, AddrShift value); AddrShift NewLogicGate(OpCode opcode, AddrShift left, AddrShift right); AddrShift NewLogicGate(OpCode opcode, AddrShift value); - AddrShift NewCallGate(StubDescriptor *descriptor, AddrShift target, std::initializer_list args); - AddrShift NewCallGate(StubDescriptor *descriptor, AddrShift target, AddrShift depend, - std::initializer_list args); - AddrShift NewCallRuntimeGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, + AddrShift NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, std::initializer_list args); - AddrShift NewCallRuntimeGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, + AddrShift NewCallGate(StubDescriptor *descriptor, AddrShift thread, AddrShift target, AddrShift depend, std::initializer_list args); static OpCode GetLoadOpCodeFromMachineType(MachineType type); static OpCode GetStoreOpCodeFromMachineType(MachineType type); diff --git a/ecmascript/compiler/circuit_ir_specification.md b/ecmascript/compiler/circuit_ir_specification.md new file mode 100644 index 0000000000000000000000000000000000000000..4f0a57374aff08f108243eb98b66d5bda1760780 --- /dev/null +++ b/ecmascript/compiler/circuit_ir_specification.md @@ -0,0 +1,45 @@ +# Circuit IR specification + +## General design + +Circuit IR is like a circuit diagram, which is good at representing the intrinsic logic of a computation process. The circuit diagram is a directed graph: [logic gates](https://en.wikipedia.org/wiki/Logic_gate) are nodes, wires are directed edges. Circuit IR describes semantic of programs in a language-neutral and target-neutral way, targeting multi-language and multi-target support. The design of Circuit IR has a great emphasis on compilation speed (for JIT), code optimization (on both high and low levels), and canonicalization (unique representation for same intrinsic logic). + +Circuit IR splits a program into two major parts: [sequential logic](https://en.wikipedia.org/wiki/Sequential_logic) part and [combinational logic](https://en.wikipedia.org/wiki/Combinational_logic) part: + +* The **sequential logic** part is a subgraph of Circuit IR which is similar to the underlying control flow graph (CFG) of the program, and gates in this part are named **state gates** (since they acted like a [finite state machine](https://en.wikipedia.org/wiki/Finite-state_machine) (FSM)). Wires that connect two state gates represent possible state transitions of the FSM, and they are named **state wires**. + +* The **combinational logic** part is the other subgraph of Circuit IR which represents all computations in a program using a directed acyclic graph (DAG), and gates in this part are named **computation gates**. A computation gate can do simple things such as adding two integer values, or complex things such as calling a function (and thus make a change to the global memory). Most of **computation gates** will take some values as input and output a value. These values can be transferred by **data wires**. Some computation gates will load from or store to the global memory, so they should be executed non-simultaneously and in some order that will not violate memory dependencies (such as RAW, WAR and WAW). Addressing this issue, **dependency wires** are introduced to constrain the possible execution order of such computations. When a computation gate has multiple dependencies, an auxiliary gate `DEPEND_AND` is used to merge dependencies. + +In traditional [SSA](https://en.wikipedia.org/wiki/Static_single_assignment_form) form IR (e.g. LLVM IR), each instruction is placed inside a node of CFG (basic block), and all instructions in a basic block are [linearly ordered](https://en.wikipedia.org/wiki/Total_order). However, in Circuit IR, computation gates are not tied to state gates, and they are [partially ordered](https://en.wikipedia.org/wiki/Partially_ordered_set) by wires. Sequential logic part and combinational logic part are loosely coupled, they only interact in three ways: + +* State gates that have multiple transitions (corresponding to multiple control flow branches) such as `IF_BRANCH` and `SWITCH_BRANCH` will need an input value computed from combinational logic part to select which next state the FSM will transit to. + +* Similar to the Φ functions in traditional SSA form IR, there are **[selector](https://en.wikipedia.org/wiki/Multiplexer) gates** such as `VALUE_SELECTOR_INT64` and `DEPEND_SELECTOR` that select a data or dependency path based on the state transition action of the FSM. Selector gates are affiliated (many-to-one) to `MERGE` state gates (which have several transition sources), and take several values or dependencies from computation part as input, and will select a value or dependency from input as output, based on which state transition action is taken. + +* In some cases, a computation gate with side effect (i.e. may store to the global memory) should not be executed before a specific branch state transition action is taken. Addressing this problem, **[relay](https://en.wikipedia.org/wiki/Relay) gates** `DEPEND_RELAY` are introduced. They take a state gate (the target of action) as input, and reinterpret it as a kind of memory dependency that can be used by computation gates with side effect. + +Loose coupling of sequential logic part and combinational logic part can benefit compilation speed, code optimization. Firstly, most of IR passes can focus on only one part and will not be interfered by the other part, so the implementation will be simpler. In addition, some special and important code optimizations such as (register pressure sensitive) loop invariant code motion and code sink can be done in the IR scheduling phrase (without furthermore IR analysis or modification), thus they will not couple with other code optimizations and can be done perfectly. Last but not least, less coupling means more canonicalization, this implies fewer branches in the implementation of IR optimization algorithms. + +There are several gates named **root gates** in Circuit IR. Root gates are representing starting/ending vertices of the IR graph, or registering lists of starting/ending vertices of the IR graph. IR Passes usually traverse a part of all gates (forwardly or reversely) starting from root gates. Explanations of Root gates are listed below: + +* `STATE_ENTRY`: representing the initial state of the sequential logic part (for traversing forwardly from beginning to ending) + +* `DEPEND_ENTRY`: the origin of dependency flows of the entire circuit + +* `RETURN_LIST`: registering all terminal states (for traversing reversely from ending to beginning) + +* `CONSTANT_LIST` `ARG_LIST`: registering all value origins such as constants and arguments (they are special computation gates that do not depend on other values) + +## Type system + +### Levels of types + +There are two levels of types of values in Circuit IR: + +* Primary types: This level of types are **low level** (closer to ISA) and **fundamental** for Circuit IR, and are determined by the opcode of gates. They describe the bit width of values, and which type of registers (integer or float) should such values be put into. Circuit IR can be translated to correct machine code with only primary types. All primary types are `INT1` `INT8` `INT16` `INT32` `INT64` `FLOAT32` `FLOAT64`. Note that pointer type is not included in primary types, since pointers are not different from integers in common ISAs. The concept of pointers should be expressed in secondary types. + +* Secondary types: This level of types are **high level** (closer to language) and **optional**. They can provide information for program analysis, code optimization and garbage collection (generating stack maps). Secondary types can represent categories of possible bit vectors the value can be (e.g. `JS_ANY` `JS_BOOLEAN` `JS_NULL` `JS_UNDEFINED` `JS_NUMBER` `JS_SMI` etc. builtin categories and user defined bit vectors categories), and possible classes of objects the value points to as a pointer (e.g. `JS_HEAP_OBJECT` `JS_STRING` `JS_OBJECT` `JS_ARRAY` `JS_TYPED_ARRAY` `JS_UINT8_ARRAY` etc. builtin classes and user defined classes). + +### Type inference + +Primary types are all set during construction of Circuit IR, so no furthermore type inference is required. Circuit IR verifier will verify consistency of primary types. Secondary types can be not precisely set during construction (e.g. leaving many intermediate values as `JS_ANY`), and the compiler should be able to do type inference (and check consistency) following data flow paths (e.g. `c:=JS_ADD(a:, b:) -> c:=JS_ADD(a:, b:)` and `c:=VALUE_SELECTOR(a:, b:) -> c:=JS_ADD(a:, b:)`), thus the secondary types will be more precise than initially set at the end. diff --git a/ecmascript/compiler/compile_llvm_lib.sh b/ecmascript/compiler/compile_llvm_lib.sh index 58c117ed66e0976cb4030519ac5fe03035dd3bf9..0891662c328fb3e2f1d2c0e563c1c7e43308dac5 100755 --- a/ecmascript/compiler/compile_llvm_lib.sh +++ b/ecmascript/compiler/compile_llvm_lib.sh @@ -25,20 +25,24 @@ echo ${BIN_PATH} echo ${BASE_HOME} if [ ! -d ${BASE_HOME}/third_party/llvm-project ]; then + cd ${BASE_HOME}/third_party dd if=/dev/zero of=/tmp/mem.swap bs=1M count=4096 - git clone https://gitee.com/github-repos/llvm-project.git + git clone https://gitee.com/surpassgoodchao/llvm-project.git fi cd ${BASE_HOME}/third_party/llvm-project if [ ! -d "build" ];then + git checkout -b local llvmorg-10.0.1 + cp ../../ark/js_runtime/ecmascript/compiler/llvm/llvm.patch . + git apply --reject llvm.patch mkdir build && cd build - cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llvm + cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DBUILD_ARK_GC_SUPPORT=ON -DLLVM_ENABLE_TERMINFO=OFF DLLVM_STATIC_LINK_CXX_STDLIB=OFF -DLLVM_ENABLE_ZLIB=OFF ../llvm ninja else cd build if [ ! -d "lib" ]; then rm -rf * - cmake -GNinja -DCMAKE_BUILD_TYPE=Release ../llvm + cmake -GNinja -DCMAKE_BUILD_TYPE=Release -DBUILD_ARK_GC_SUPPORT=ON -DLLVM_ENABLE_TERMINFO=OFF DLLVM_STATIC_LINK_CXX_STDLIB=OFF -DLLVM_ENABLE_ZLIB=OFF ../llvm ninja fi fi diff --git a/ecmascript/compiler/fast_stub.cpp b/ecmascript/compiler/fast_stub.cpp index ac005e5b53c0a9d3b7c40941583eae2ff1687815..9e125fa833ae6be39409247402f3f23ac9edb7c0 100644 --- a/ecmascript/compiler/fast_stub.cpp +++ b/ecmascript/compiler/fast_stub.cpp @@ -29,14 +29,13 @@ void FastArrayLoadElementStub::GenerateCircuit() AddrShift indexVal = Int32Argument(1); // load a.length - AddrShift lengthOffset = GetInteger32Constant(JSArray::GetArrayLengthOffset()); + AddrShift lengthOffset = GetInt32Constant(JSArray::GetArrayLengthOffset()); if (PtrValueCode() == ValueCode::INT64) { lengthOffset = SExtInt32ToInt64(lengthOffset); } else if (PtrValueCode() == ValueCode::INT32) { aVal = TruncInt64ToInt32(aVal); } AddrShift taggedLength = Load(MachineType::TAGGED_TYPE, aVal, lengthOffset); - AddrShift intLength = TaggedCastToInt32(taggedLength); // if index < length Label ifTrue(env); @@ -75,7 +74,7 @@ void FastAddStub::GenerateCircuit() Bind(&xIsInt); { intX = TaggedCastToInt32(x); - doubleX = CastInt32ToFloat64(*intX); + doubleX = ChangeInt32ToFloat64(*intX); Jump(&xIsNumberAndyIsNumber); } Bind(&xNotInt); @@ -95,7 +94,7 @@ void FastAddStub::GenerateCircuit() Bind(&yIsInt); { intY = TaggedCastToInt32(y); - doubleY = CastInt32ToFloat64(*intY); + doubleY = ChangeInt32ToFloat64(*intY); Jump(&xIsDoubleAndyIsDouble); } Bind(&yNotInt); @@ -150,7 +149,7 @@ void FastSubStub::GenerateCircuit() Bind(&yNotInt); { doubleY = TaggedCastToDouble(y); - doubleX = CastInt32ToFloat64(*intX); + doubleX = ChangeInt32ToFloat64(*intX); Jump(&xNotIntOryNotInt); } } @@ -163,7 +162,7 @@ void FastSubStub::GenerateCircuit() Bind(&yIsInt); { intY = TaggedCastToInt32(y); - doubleY = CastInt32ToFloat64(*intY); + doubleY = ChangeInt32ToFloat64(*intY); Jump(&xNotIntOryNotInt); } Bind(&yNotInt); @@ -211,7 +210,7 @@ void FastMulStub::GenerateCircuit() Bind(&xIsInt); { intX = TaggedCastToInt32(x); - doubleX = CastInt32ToFloat64(*intX); + doubleX = ChangeInt32ToFloat64(*intX); Jump(&xIsNumberAndyIsNumber); } Bind(&xNotInt); @@ -231,7 +230,7 @@ void FastMulStub::GenerateCircuit() Bind(&yIsInt); { intY = TaggedCastToInt32(y); - doubleY = CastInt32ToFloat64(*intY); + doubleY = ChangeInt32ToFloat64(*intY); Jump(&xIsDoubleAndyIsDouble); } Bind(&yNotInt); @@ -272,7 +271,7 @@ void FastDivStub::GenerateCircuit() Bind(&xIsInt); { intX = TaggedCastToInt32(x); - doubleX = CastInt32ToFloat64(*intX); + doubleX = ChangeInt32ToFloat64(*intX); Jump(&xIsNumberAndyIsNumber); } Bind(&xNotInt); @@ -291,7 +290,7 @@ void FastDivStub::GenerateCircuit() Bind(&yIsInt); { intY = TaggedCastToInt32(y); - doubleY = CastInt32ToFloat64(*intY); + doubleY = ChangeInt32ToFloat64(*intY); Jump(&xIsDoubleAndyIsDouble); } Bind(&yNotInt); @@ -344,25 +343,24 @@ void FastDivStub::GenerateCircuit() } } -void FastFindOwnElementStub::GenerateCircuit() +void FindOwnElementStub::GenerateCircuit() { auto env = GetEnvironment(); AddrShift thread = PtrArgument(0); AddrShift obj = PtrArgument(1); AddrShift index = Int32Argument(2); // 2: 3rd parameter - index - Label notDict(env); Label isDict(env); Label invalidValue(env); Label end(env); - AddrShift elements = Load(POINTER_TYPE, obj, GetPtrConstant(JSObject::ELEMENTS_OFFSET)); - + AddrShift elements = Load(MachineType::POINTER_TYPE, obj, GetPtrConstant(JSObject::ELEMENTS_OFFSET)); Branch(IsDictionaryMode(elements), &isDict, ¬Dict); Bind(¬Dict); { Label outOfArray(env); Label notOutOfArray(env); - AddrShift arrayLength = Load(UINT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); + AddrShift arrayLength = Load(MachineType::UINT32_TYPE, elements, + GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); Branch(Int32LessThanOrEqual(arrayLength, index), &outOfArray, ¬OutOfArray); Bind(&outOfArray); Jump(&invalidValue); @@ -370,7 +368,7 @@ void FastFindOwnElementStub::GenerateCircuit() { AddrShift offset = PtrMul(ChangeInt32ToPointer(index), GetPtrConstant(JSTaggedValue::TaggedTypeSize())); AddrShift dataIndex = PtrAdd(offset, GetPtrConstant(panda::coretypes::Array::GetDataOffset())); - AddrShift value = Load(TAGGED_TYPE, elements, dataIndex); + AddrShift value = Load(MachineType::TAGGED_TYPE, elements, dataIndex); Label isHole1(env); Label notHole1(env); Branch(TaggedIsHole(value), &isHole1, ¬Hole1); @@ -382,14 +380,13 @@ void FastFindOwnElementStub::GenerateCircuit() Bind(&invalidValue); Return(GetHoleConstant()); } - // IsDictionary Bind(&isDict); { AddrShift taggedIndex = IntBuildTagged(index); AddrShift entry = FindElementFromNumberDictionary(thread, elements, taggedIndex); Label notNegtiveOne(env); Label negtiveOne(env); - Branch(Word32NotEqual(entry, GetInteger32Constant(-1)), ¬NegtiveOne, &negtiveOne); + Branch(Word32NotEqual(entry, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { Return(GetValueFromDictionary(elements, entry)); @@ -401,7 +398,7 @@ void FastFindOwnElementStub::GenerateCircuit() Return(GetHoleConstant()); } -void FastGetElementStub::GenerateCircuit() +void GetElementStub::GenerateCircuit() { auto env = GetEnvironment(); AddrShift thread = PtrArgument(0); @@ -419,12 +416,13 @@ void FastGetElementStub::GenerateCircuit() AddrShift objPtr = ChangeInt64ToPointer(receiver); auto findOwnElementDescriptor = GET_STUBDESCRIPTOR(FindOwnElement); AddrShift callFindOwnElementVal = - CallStub(findOwnElementDescriptor, GetWord64Constant(FAST_STUB_ID(FindOwnElement)), {thread, objPtr, index}); + CallStub(findOwnElementDescriptor, thread, GetWord64Constant(FAST_STUB_ID(FindOwnElement)), + {thread, objPtr, index}); Branch(TaggedIsHole(callFindOwnElementVal), &isHole, ¬Hole); Bind(¬Hole); Return(callFindOwnElementVal); Bind(&isHole); - receiver = Load(TAGGED_TYPE, LoadHClass(objPtr), GetPtrConstant(JSHClass::PROTOTYPE_OFFSET)); + receiver = Load(MachineType::TAGGED_TYPE, LoadHClass(objPtr), GetPtrConstant(JSHClass::PROTOTYPE_OFFSET)); Branch(TaggedIsHeapObject(receiver), &loopEnd, ¬HeapObj); Bind(¬HeapObj); Return(GetUndefinedConstant()); @@ -432,7 +430,7 @@ void FastGetElementStub::GenerateCircuit() LoopEnd(&loopHead); } -void FastFindOwnElement2Stub::GenerateCircuit() +void FindOwnElement2Stub::GenerateCircuit() { auto env = GetEnvironment(); AddrShift thread = PtrArgument(0); @@ -445,11 +443,11 @@ void FastFindOwnElement2Stub::GenerateCircuit() Label notDictionary(env); Label isDictionary(env); Label end(env); - Branch(Word32Equal(isDict, GetInteger32Constant(0)), ¬Dictionary, &isDictionary); + Branch(Word32Equal(isDict, GetInt32Constant(0)), ¬Dictionary, &isDictionary); Bind(¬Dictionary); { AddrShift elementsLength = - Load(UINT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); + Load(MachineType::UINT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); Label outOfElements(env); Label notOutOfElements(env); Branch(Int32LessThanOrEqual(elementsLength, index), &outOfElements, ¬OutOfElements); @@ -467,9 +465,9 @@ void FastFindOwnElement2Stub::GenerateCircuit() Jump(&end); Bind(¬Hole); { - Store(UINT32_TYPE, attr, GetPtrConstant(0), - GetInteger32Constant(PropertyAttributes::GetDefaultAttributes())); - Store(UINT32_TYPE, indexOrEntry, GetPtrConstant(0), index); + Store(MachineType::UINT32_TYPE, attr, GetPtrConstant(0), + GetInt32Constant(PropertyAttributes::GetDefaultAttributes())); + Store(MachineType::UINT32_TYPE, indexOrEntry, GetPtrConstant(0), index); Return(value); } } @@ -479,11 +477,11 @@ void FastFindOwnElement2Stub::GenerateCircuit() AddrShift entry = FindElementFromNumberDictionary(thread, elements, IntBuildTagged(index)); Label notNegtiveOne(env); Label negtiveOne(env); - Branch(Word32NotEqual(entry, GetInteger32Constant(-1)), ¬NegtiveOne, &negtiveOne); + Branch(Word32NotEqual(entry, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { - Store(UINT32_TYPE, attr, GetPtrConstant(0), GetAttributesFromDictionary(elements, entry)); - Store(UINT32_TYPE, indexOrEntry, GetPtrConstant(0), entry); + Store(MachineType::UINT32_TYPE, attr, GetPtrConstant(0), GetAttributesFromDictionary(elements, entry)); + Store(MachineType::UINT32_TYPE, indexOrEntry, GetPtrConstant(0), entry); Return(GetValueFromDictionary(elements, entry)); } Bind(&negtiveOne); @@ -493,7 +491,7 @@ void FastFindOwnElement2Stub::GenerateCircuit() Return(GetHoleConstant()); } -void FastSetElementStub::GenerateCircuit() +void SetElementStub::GenerateCircuit() { auto env = GetEnvironment(); AddrShift thread = PtrArgument(0); @@ -507,13 +505,14 @@ void FastSetElementStub::GenerateCircuit() AddrShift pattr = Alloca(static_cast(MachineRep::K_WORD32)); AddrShift pindexOrEntry = Alloca(static_cast(MachineRep::K_WORD32)); Label loopHead(env); + Label loopEnd(env); Jump(&loopHead); LoopBegin(&loopHead); { AddrShift elements = GetElements(*holder); AddrShift isDictionary = IsDictionaryMode(elements); StubDescriptor *findOwnElemnt2 = GET_STUBDESCRIPTOR(FindOwnElement2); - AddrShift val = CallStub(findOwnElemnt2, GetWord64Constant(FAST_STUB_ID(FindOwnElement2)), + AddrShift val = CallStub(findOwnElemnt2, thread, GetWord64Constant(FAST_STUB_ID(FindOwnElement2)), {thread, elements, index, isDictionary, pattr, pindexOrEntry}); Label notHole(env); Label isHole(env); @@ -538,7 +537,7 @@ void FastSetElementStub::GenerateCircuit() { Label isThrow(env); Label notThrow(env); - Branch(Word32NotEqual(mayThrow, GetInteger32Constant(0)), &isThrow, ¬Throw); + Branch(Word32NotEqual(mayThrow, GetInt32Constant(0)), &isThrow, ¬Throw); Bind(&isThrow); ThrowTypeAndReturn(thread, GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible), FalseConstant()); Bind(¬Throw); @@ -548,11 +547,11 @@ void FastSetElementStub::GenerateCircuit() StubDescriptor *addElementInternal = GET_STUBDESCRIPTOR(AddElementInternal); Return(CallRuntime(addElementInternal, thread, GetWord64Constant(FAST_STUB_ID(AddElementInternal)), {thread, receiver, index, value, - GetInteger32Constant(PropertyAttributes::GetDefaultAttributes())})); + GetInt32Constant(PropertyAttributes::GetDefaultAttributes())})); } Bind(&afterOnProtoType); { - AddrShift attr = Load(INT32_TYPE, pattr); + AddrShift attr = Load(MachineType::INT32_TYPE, pattr); Label isAccessor(env); Label notAccessor(env); Branch(IsAccessor(attr), &isAccessor, ¬Accessor); @@ -566,17 +565,17 @@ void FastSetElementStub::GenerateCircuit() AddrShift elements = GetElements(receiver); Label isDict(env); Label notDict(env); - AddrShift indexOrEntry = Load(INT32_TYPE, pindexOrEntry); + AddrShift indexOrEntry = Load(MachineType::INT32_TYPE, pindexOrEntry); Branch(isDictionary, &isDict, ¬Dict); Bind(¬Dict); { - StoreElement(elements, indexOrEntry, value); + StoreElement(thread, elements, indexOrEntry, value); UpdateRepresention(LoadHClass(receiver), value); Return(TrueConstant()); } Bind(&isDict); { - UpdateValueAndAttributes(elements, indexOrEntry, value, attr); + UpdateValueAndAttributes(thread, elements, indexOrEntry, value, attr); Return(TrueConstant()); } } @@ -584,7 +583,7 @@ void FastSetElementStub::GenerateCircuit() { Label isThrow(env); Label notThrow(env); - Branch(Word32NotEqual(mayThrow, GetInteger32Constant(0)), &isThrow, ¬Throw); + Branch(Word32NotEqual(mayThrow, GetInt32Constant(0)), &isThrow, ¬Throw); Bind(&isThrow); ThrowTypeAndReturn(thread, GET_MESSAGE_STRING_ID(SetReadOnlyProperty), FalseConstant()); Bind(¬Throw); @@ -619,7 +618,7 @@ void FastSetElementStub::GenerateCircuit() { Label isThrow(env); Label notThrow(env); - Branch(Word32NotEqual(mayThrow, GetInteger32Constant(0)), &isThrow, ¬Throw); + Branch(Word32NotEqual(mayThrow, GetInt32Constant(0)), &isThrow, ¬Throw); Bind(&isThrow); ThrowTypeAndReturn(thread, GET_MESSAGE_STRING_ID(SetPropertyWhenNotExtensible), FalseConstant()); Bind(¬Throw); @@ -630,7 +629,7 @@ void FastSetElementStub::GenerateCircuit() StubDescriptor *addElementInternal = GET_STUBDESCRIPTOR(AddElementInternal); Return(CallRuntime(addElementInternal, thread, GetWord64Constant(FAST_STUB_ID(AddElementInternal)), {thread, receiver, index, value, - GetInteger32Constant(PropertyAttributes::GetDefaultAttributes())})); + GetInt32Constant(PropertyAttributes::GetDefaultAttributes())})); } } Bind(&isHeapObj); @@ -647,13 +646,15 @@ void FastSetElementStub::GenerateCircuit() } Bind(¬JsProxy); onPrototype = TrueConstant(); + Jump(&loopEnd); } } } + Bind(&loopEnd); LoopEnd(&loopHead); } -void FastGetPropertyByIndexStub::GenerateCircuit() +void GetPropertyByIndexStub::GenerateCircuit() { auto env = GetEnvironment(); AddrShift thread = PtrArgument(0); @@ -715,7 +716,7 @@ void FastGetPropertyByIndexStub::GenerateCircuit() FindElementFromNumberDictionary(thread, elements, IntBuildTagged(index)); Label notNegtiveOne(env); Label negtiveOne(env); - Branch(Word32NotEqual(entry, GetInteger32Constant(-1)), ¬NegtiveOne, &negtiveOne); + Branch(Word32NotEqual(entry, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { AddrShift attr = GetAttributesFromDictionary(elements, entry); @@ -733,13 +734,13 @@ void FastGetPropertyByIndexStub::GenerateCircuit() StubDescriptor *callAccessorGetter = GET_STUBDESCRIPTOR(AccessorGetter); Return(CallRuntime(callAccessorGetter, thread, GetWord64Constant(FAST_STUB_ID(AccessorGetter)), - {thread, *holder, value})); + {thread, value, *holder})); } Bind(¬Internal); { StubDescriptor *callGetter = GET_STUBDESCRIPTOR(CallGetter); Return(CallRuntime(callGetter, thread, GetWord64Constant(FAST_STUB_ID(CallGetter)), - {thread, receiver, value})); + {thread, value, receiver})); } } Bind(¬Accessor); @@ -765,7 +766,7 @@ void FastGetPropertyByIndexStub::GenerateCircuit() } } -void FastSetPropertyByIndexStub::GenerateCircuit() +void SetPropertyByIndexStub::GenerateCircuit() { auto env = GetEnvironment(); AddrShift thread = PtrArgument(0); @@ -811,7 +812,7 @@ void FastSetPropertyByIndexStub::GenerateCircuit() Branch(Word64NotEqual(value1, GetHoleConstant()), ¬Hole, &loopExit); Bind(¬Hole); { - StoreElement(elements, index, value); + StoreElement(thread, elements, index, value); Return(GetUndefinedConstant()); } } @@ -841,7 +842,7 @@ void FastSetPropertyByIndexStub::GenerateCircuit() AddrShift result = CallRuntime(addElementInternal, thread, GetWord64Constant(FAST_STUB_ID(AddElementInternal)), {thread, receiver, index, value, - GetInteger32Constant(PropertyAttributes::GetDefaultAttributes())}); + GetInt32Constant(PropertyAttributes::GetDefaultAttributes())}); Label success(env); Label failed(env); Branch(result, &success, &failed); @@ -857,7 +858,7 @@ void FastSetPropertyByIndexStub::GenerateCircuit() } } -void FastGetPropertyByNameStub::GenerateCircuit() +void GetPropertyByNameStub::GenerateCircuit() { auto env = GetEnvironment(); AddrShift thread = PtrArgument(0); @@ -889,7 +890,7 @@ void FastGetPropertyByNameStub::GenerateCircuit() Label isDicMode(env); Label notDicMode(env); // if branch condition : LIKELY(!hclass->IsDictionaryMode()) - Branch(IsDictionaryElement(hClass), &isDicMode, ¬DicMode); + Branch(IsDictionaryModeByHClass(hClass), &isDicMode, ¬DicMode); Bind(¬DicMode); { // LayoutInfo *layoutInfo = LayoutInfo::Cast(hclass->GetAttributes().GetTaggedObject()) @@ -904,7 +905,7 @@ void FastGetPropertyByNameStub::GenerateCircuit() Label hasEntry(env); Label noEntry(env); // if branch condition : entry != -1 - Branch(Word32NotEqual(entry, GetInteger32Constant(-1)), &hasEntry, &noEntry); + Branch(Word32NotEqual(entry, GetInt32Constant(-1)), &hasEntry, &noEntry); Bind(&hasEntry); { // PropertyAttributes attr(layoutInfo->GetAttr(entry)) @@ -925,13 +926,13 @@ void FastGetPropertyByNameStub::GenerateCircuit() StubDescriptor *callAccessorGetter = GET_STUBDESCRIPTOR(AccessorGetter); Return(CallRuntime(callAccessorGetter, thread, GetWord64Constant(FAST_STUB_ID(AccessorGetter)), - {thread, *holder, value})); + {thread, value, *holder})); } Bind(¬Internal); { StubDescriptor *callGetter = GET_STUBDESCRIPTOR(CallGetter); Return(CallRuntime(callGetter, thread, GetWord64Constant(FAST_STUB_ID(CallGetter)), - {thread, receiver, value})); + {thread, value, receiver})); } } Bind(¬Accessor); @@ -953,7 +954,7 @@ void FastGetPropertyByNameStub::GenerateCircuit() Label notNegtiveOne(env); Label negtiveOne(env); // if branch condition : entry != -1 - Branch(Word32NotEqual(entry, GetInteger32Constant(-1)), ¬NegtiveOne, &negtiveOne); + Branch(Word32NotEqual(entry, GetInt32Constant(-1)), ¬NegtiveOne, &negtiveOne); Bind(¬NegtiveOne); { // auto value = dict->GetValue(entry) @@ -974,13 +975,13 @@ void FastGetPropertyByNameStub::GenerateCircuit() StubDescriptor *callAccessorGetter1 = GET_STUBDESCRIPTOR(AccessorGetter); Return(CallRuntime(callAccessorGetter1, thread, GetWord64Constant(FAST_STUB_ID(AccessorGetter)), - {thread, *holder, value})); + {thread, value, *holder})); } Bind(¬Internal1); { StubDescriptor *callGetter1 = GET_STUBDESCRIPTOR(CallGetter); Return(CallRuntime(callGetter1, thread, GetWord64Constant(FAST_STUB_ID(CallGetter)), - {thread, receiver, value})); + {thread, value, receiver})); } } Bind(¬Accessor1); @@ -1011,8 +1012,9 @@ void FastGetPropertyByNameStub::GenerateCircuit() void FastModStub::GenerateCircuit() { auto env = GetEnvironment(); - AddrShift x = Int64Argument(0); - AddrShift y = Int64Argument(1); + AddrShift thread = PtrArgument(0); + AddrShift x = Int64Argument(1); + AddrShift y = Int64Argument(2); DEFVARIABLE(intX, MachineType::INT32_TYPE, 0); DEFVARIABLE(intY, MachineType::INT32_TYPE, 0); DEFVARIABLE(doubleX, MachineType::FLOAT64_TYPE, 0); @@ -1036,10 +1038,10 @@ void FastModStub::GenerateCircuit() { Label xGtZero(env); Label xGtZeroAndyGtZero(env); - Branch(Int32GreaterThan(*intX, GetInteger32Constant(0)), &xGtZero, &xNotIntOryNotInt); + Branch(Int32GreaterThan(*intX, GetInt32Constant(0)), &xGtZero, &xNotIntOryNotInt); Bind(&xGtZero); { - Branch(Int32GreaterThan(*intY, GetInteger32Constant(0)), &xGtZeroAndyGtZero, &xNotIntOryNotInt); + Branch(Int32GreaterThan(*intY, GetInt32Constant(0)), &xGtZeroAndyGtZero, &xNotIntOryNotInt); Bind(&xGtZeroAndyGtZero); { intX = Int32Mod(*intX, *intY); @@ -1068,7 +1070,7 @@ void FastModStub::GenerateCircuit() Bind(&xIfInt); { intX = TaggedCastToInt32(x); - doubleX = CastInt32ToFloat64(*intX); + doubleX = ChangeInt32ToFloat64(*intX); Jump(&xIsNumberAndyIsNumber); } Bind(&xIfNotInt); @@ -1087,7 +1089,7 @@ void FastModStub::GenerateCircuit() Bind(&yIfInt); { intY = TaggedCastToInt32(y); - doubleY = CastInt32ToFloat64(*intY); + doubleY = ChangeInt32ToFloat64(*intY); Jump(&xIsDoubleAndyIsDouble); } Bind(&yIfNotInt); @@ -1149,7 +1151,9 @@ void FastModStub::GenerateCircuit() Jump(&xIsZeroOryIsInf); Bind(&yNotInf); { - doubleX = DoubleMod(*doubleX, *doubleY); + StubDescriptor *floatMod = GET_STUBDESCRIPTOR(FloatMod); + doubleX =CallRuntime(floatMod, thread, GetWord64Constant(FAST_STUB_ID(FloatMod)), + {*doubleX, *doubleY}); Return(DoubleBuildTagged(*doubleX)); } Bind(&xIsZeroOryIsInf); @@ -1158,4 +1162,475 @@ void FastModStub::GenerateCircuit() } } } -} // namespace kungfu \ No newline at end of file + +#ifndef NDEBUG +void FastMulGCTestStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + env->GetCircuit()->SetFrameType(FrameType::OPTIMIZED_ENTRY_FRAME); + AddrShift thread = PtrArgument(0); + (void)thread; + AddrShift x = Int64Argument(1); + AddrShift y = Int64Argument(2); + + DEFVARIABLE(intX, MachineType::INT64_TYPE, 0); + DEFVARIABLE(intY, MachineType::INT64_TYPE, 0); + DEFVARIABLE(valuePtr, MachineType::INT64_TYPE, 0); + DEFVARIABLE(doubleX, MachineType::FLOAT64_TYPE, 0); + DEFVARIABLE(doubleY, MachineType::FLOAT64_TYPE, 0); + Label xIsNumber(env); + Label xNotNumberOryNotNumber(env); + Label xIsNumberAndyIsNumber(env); + Label xIsDoubleAndyIsDouble(env); + Branch(TaggedIsNumber(x), &xIsNumber, &xNotNumberOryNotNumber); + Bind(&xIsNumber); + { + Label yIsNumber(env); + // if right.IsNumber() + Branch(TaggedIsNumber(y), &yIsNumber, &xNotNumberOryNotNumber); + Bind(&yIsNumber); + { + Label xIsInt(env); + Label xNotInt(env); + Branch(TaggedIsInt(x), &xIsInt, &xNotInt); + Bind(&xIsInt); + { + intX = TaggedCastToInt64(x); + doubleX = CastInt64ToFloat64(*intX); + Jump(&xIsNumberAndyIsNumber); + } + Bind(&xNotInt); + { + doubleX = TaggedCastToDouble(x); + Jump(&xIsNumberAndyIsNumber); + } + } + } + Bind(&xNotNumberOryNotNumber); + Return(GetHoleConstant()); + Label yIsInt(env); + Label yNotInt(env); + Bind(&xIsNumberAndyIsNumber); + { + Branch(TaggedIsInt(y), &yIsInt, &yNotInt); + Bind(&yIsInt); + { + intY = TaggedCastToInt64(y); + doubleY = CastInt64ToFloat64(*intY); + Jump(&xIsDoubleAndyIsDouble); + } + Bind(&yNotInt); + { + doubleY = TaggedCastToDouble(y); + Jump(&xIsDoubleAndyIsDouble); + } + } + Bind(&xIsDoubleAndyIsDouble); + doubleX = DoubleMul(*doubleX, *doubleY); + StubDescriptor *getTaggedArrayPtr = GET_STUBDESCRIPTOR(GetTaggedArrayPtrTest); + AddrShift ptr1 = CallRuntime(getTaggedArrayPtr, thread, GetWord64Constant(FAST_STUB_ID(GetTaggedArrayPtrTest)), + {thread}); + AddrShift ptr2 = CallRuntime(getTaggedArrayPtr, thread, GetWord64Constant(FAST_STUB_ID(GetTaggedArrayPtrTest)), + {thread}); + (void)ptr2; + auto value = Load(MachineType::INT64_TYPE, ptr1); + AddrShift value2 = CastInt64ToFloat64(value); + doubleX = DoubleMul(*doubleX, value2); + Return(DoubleBuildTagged(*doubleX)); +} +#endif + +void FastTypeOfStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift thread = PtrArgument(0); + AddrShift obj = PtrArgument(1); + DEFVARIABLE(holder, MachineType::TAGGED_POINTER_TYPE, obj); + AddrShift gConstOffset = PtrAdd(thread, GetPtrConstant(panda::ecmascript::JSThread::GetGlobalConstantOffset())); + AddrShift booleanIndex = GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX); + AddrShift gConstUndefindStr = Load(MachineType::TAGGED_TYPE, gConstOffset, booleanIndex); + DEFVARIABLE(resultRep, MachineType::TAGGED_TYPE, gConstUndefindStr); + Label objIsTrue(env); + Label objNotTrue(env); + Label exit(env); + Label defaultLabel(env); + AddrShift gConstBooleanStr = Load( + MachineType::TAGGED_TYPE, gConstOffset, GetGlobalConstantString(ConstantIndex::BOOLEAN_STRING_INDEX)); + Branch(Word64Equal(obj, GetWord64Constant(JSTaggedValue::VALUE_TRUE)), &objIsTrue, &objNotTrue); + Bind(&objIsTrue); + { + resultRep = gConstBooleanStr; + Jump(&exit); + } + Bind(&objNotTrue); + { + Label objIsFalse(env); + Label objNotFalse(env); + Branch(Word64Equal(obj, GetWord64Constant(JSTaggedValue::VALUE_FALSE)), &objIsFalse, &objNotFalse); + Bind(&objIsFalse); + { + resultRep = gConstBooleanStr; + Jump(&exit); + } + Bind(&objNotFalse); + { + Label objIsNull(env); + Label objNotNull(env); + Branch(Word64Equal(obj, GetWord64Constant(JSTaggedValue::VALUE_NULL)), &objIsNull, &objNotNull); + Bind(&objIsNull); + { + resultRep = Load( + MachineType::TAGGED_TYPE, gConstOffset, + GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX)); + Jump(&exit); + } + Bind(&objNotNull); + { + Label objIsUndefined(env); + Label objNotUndefined(env); + Branch(Word64Equal(obj, GetWord64Constant(JSTaggedValue::VALUE_UNDEFINED)), &objIsUndefined, + &objNotUndefined); + Bind(&objIsUndefined); + { + resultRep = Load(MachineType::TAGGED_TYPE, gConstOffset, + GetGlobalConstantString(ConstantIndex::UNDEFINED_STRING_INDEX)); + Jump(&exit); + } + Bind(&objNotUndefined); + Jump(&defaultLabel); + } + } + } + Bind(&defaultLabel); + { + Label objIsHeapObject(env); + Label objNotHeapObject(env); + Branch(TaggedIsHeapObject(obj), &objIsHeapObject, &objNotHeapObject); + Bind(&objIsHeapObject); + { + Label objIsString(env); + Label objNotString(env); + Branch(IsString(obj), &objIsString, &objNotString); + Bind(&objIsString); + { + resultRep = Load( + MachineType::TAGGED_TYPE, gConstOffset, + GetGlobalConstantString(ConstantIndex::STRING_STRING_INDEX)); + Jump(&exit); + } + Bind(&objNotString); + { + Label objIsSymbol(env); + Label objNotSymbol(env); + Branch(IsSymbol(obj), &objIsSymbol, &objNotSymbol); + Bind(&objIsSymbol); + { + resultRep = Load(MachineType::TAGGED_TYPE, gConstOffset, + GetGlobalConstantString(ConstantIndex::SYMBOL_STRING_INDEX)); + Jump(&exit); + } + Bind(&objNotSymbol); + { + Label objIsCallable(env); + Label objNotCallable(env); + Branch(IsCallable(obj), &objIsCallable, &objNotCallable); + Bind(&objIsCallable); + { + resultRep = Load( + MachineType::TAGGED_TYPE, gConstOffset, + GetGlobalConstantString(ConstantIndex::FUNCTION_STRING_INDEX)); + Jump(&exit); + } + Bind(&objNotCallable); + { + resultRep = Load( + MachineType::TAGGED_TYPE, gConstOffset, + GetGlobalConstantString(ConstantIndex::OBJECT_STRING_INDEX)); + Jump(&exit); + } + } + } + } + Bind(&objNotHeapObject); + { + Label objIsNum(env); + Label objNotNum(env); + Branch(TaggedIsNumber(obj), &objIsNum, &objNotNum); + Bind(&objIsNum); + { + resultRep = Load( + MachineType::TAGGED_TYPE, gConstOffset, + GetGlobalConstantString(ConstantIndex::NUMBER_STRING_INDEX)); + Jump(&exit); + } + Bind(&objNotNum); + Jump(&exit); + } + } + Bind(&exit); + Return(*resultRep); +} + +void FunctionCallInternalStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift thread = PtrArgument(0); + AddrShift func = PtrArgument(1); + AddrShift thisArg = Int64Argument(2); /* 2 : 3rd parameter is value */ + AddrShift argc = Int32Argument(3); /* 3 : 4th parameter is value */ + AddrShift argv = PtrArgument(4); /* 4 : 5th parameter is ptr */ + Label funcNotBuiltinsConstructor(env); + Label funcIsBuiltinsConstructorOrFuncNotClassConstructor(env); + Label funcIsClassConstructor(env); + Branch(NotBuiltinsConstructor(func), &funcNotBuiltinsConstructor, + &funcIsBuiltinsConstructorOrFuncNotClassConstructor); + Bind(&funcNotBuiltinsConstructor); + { + Branch(IsClassConstructor(func), &funcIsClassConstructor, &funcIsBuiltinsConstructorOrFuncNotClassConstructor); + Bind(&funcIsClassConstructor); + ThrowTypeAndReturn(thread, GET_MESSAGE_STRING_ID(FunctionCallNotConstructor), GetExceptionConstant()); + } + Bind(&funcIsBuiltinsConstructorOrFuncNotClassConstructor); + StubDescriptor *execute = GET_STUBDESCRIPTOR(Execute); + Return(CallRuntime(execute, thread, GetWord64Constant(FAST_STUB_ID(Execute)), + {thread, func, thisArg, argc, argv})); +} + +void GetPropertyByValueStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift thread = PtrArgument(0); + AddrShift receiver = PtrArgument(1); + DEFVARIABLE(key, MachineType::TAGGED_TYPE, PtrArgument(2)); /* 2 : 3rd parameter is key */ + + Label isNumberOrStringSymbol(env); + Label notNumber(env); + Label isStringOrSymbol(env); + Label notStringOrSymbol(env); + Label exit(env); + + Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, ¬Number); + Bind(¬Number); + { + Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, ¬StringOrSymbol); + Bind(¬StringOrSymbol); + { + Return(GetHoleConstant()); + } + } + Bind(&isNumberOrStringSymbol); + { + AddrShift index = TryToElementsIndex(*key); + Label validIndex(env); + Label notValidIndex(env); + Branch(Int32GreaterThanOrEqual(index, GetInt32Constant(0)), &validIndex, ¬ValidIndex); + Bind(&validIndex); + { + auto getPropertyByIndex = GET_STUBDESCRIPTOR(GetPropertyByIndex); + Return(CallStub(getPropertyByIndex, thread, GetWord64Constant(FAST_STUB_ID(GetPropertyByIndex)), + {thread, receiver, index})); + } + Bind(¬ValidIndex); + { + Label notNumber(env); + Label getByName(env); + Branch(TaggedIsNumber(*key), &exit, ¬Number); + Bind(¬Number); + { + Label isString(env); + Label notString(env); + Label isInternalString(env); + Label notIntenalString(env); + Branch(TaggedIsString(*key), &isString, ¬String); + Bind(&isString); + { + Branch(IsInternalString(*key), &isInternalString, ¬IntenalString); + Bind(&isInternalString); + Jump(&getByName); + Bind(¬IntenalString); + { + StubDescriptor *newInternalString = GET_STUBDESCRIPTOR(NewInternalString); + key = CallRuntime(newInternalString, thread, + GetWord64Constant(FAST_STUB_ID(NewInternalString)), + {thread, *key}); + Jump(&getByName); + } + } + Bind(¬String); + { + Jump(&getByName); + } + } + Bind(&getByName); + { + auto getPropertyByName = GET_STUBDESCRIPTOR(GetPropertyByName); + Return(CallStub(getPropertyByName, thread, GetWord64Constant(FAST_STUB_ID(GetPropertyByName)), + {thread, receiver, *key})); + } + } + } + Bind(&exit); + Return(GetHoleConstant()); +} + +void SetPropertyByValueStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift thread = PtrArgument(0); + AddrShift receiver = PtrArgument(1); + DEFVARIABLE(key, MachineType::TAGGED_TYPE, PtrArgument(2)); /* 2 : 3rd parameter is key */ + AddrShift value = Int64Argument(3); /* 3 : 4th parameter is value */ + + Label isNumberOrStringSymbol(env); + Label notNumber(env); + Label isStringOrSymbol(env); + Label notStringOrSymbol(env); + Label exit(env); + + Branch(TaggedIsNumber(*key), &isNumberOrStringSymbol, ¬Number); + Bind(¬Number); + { + Branch(TaggedIsStringOrSymbol(*key), &isNumberOrStringSymbol, ¬StringOrSymbol); + Bind(¬StringOrSymbol); + { + Return(GetHoleConstant()); + } + } + Bind(&isNumberOrStringSymbol); + { + AddrShift index = TryToElementsIndex(*key); + Label validIndex(env); + Label notValidIndex(env); + Branch(Int32GreaterThanOrEqual(index, GetInt32Constant(0)), &validIndex, ¬ValidIndex); + Bind(&validIndex); + { + auto setPropertyByIndex = GET_STUBDESCRIPTOR(SetPropertyByIndex); + Return(CallStub(setPropertyByIndex, thread, GetWord64Constant(FAST_STUB_ID(SetPropertyByIndex)), + {thread, receiver, index, value})); + } + Bind(¬ValidIndex); + { + Label notNumber(env); + Label getByName(env); + Branch(TaggedIsNumber(*key), &exit, ¬Number); + Bind(¬Number); + { + Label isString(env); + Label notString(env); + Label isInternalString(env); + Label notIntenalString(env); + Branch(TaggedIsString(*key), &isString, ¬String); + Bind(&isString); + { + Branch(IsInternalString(*key), &isInternalString, ¬IntenalString); + Bind(&isInternalString); + Jump(&getByName); + Bind(¬IntenalString); + { + StubDescriptor *newInternalString = GET_STUBDESCRIPTOR(NewInternalString); + key = CallRuntime(newInternalString, thread, + GetWord64Constant(FAST_STUB_ID(NewInternalString)), + {thread, *key}); + Jump(&getByName); + } + } + Bind(¬String); + { + Jump(&getByName); + } + } + Bind(&getByName); + { + auto setPropertyByName = GET_STUBDESCRIPTOR(SetPropertyByName); + Return(CallStub(setPropertyByName, thread, GetWord64Constant(FAST_STUB_ID(SetPropertyByName)), + {thread, receiver, *key, value})); + } + } + } + Bind(&exit); + Return(GetHoleConstant()); +} + +void FastEqualStub::GenerateCircuit() +{ + auto env = GetEnvironment(); + AddrShift x = Int64Argument(0); + AddrShift y = Int64Argument(1); + DEFVARIABLE(doubleX, MachineType::FLOAT64_TYPE, 0); + Label xIsEqualy(env); + Label xIsNotEqualy(env); + Branch(Word64Equal(x, y), &xIsEqualy, &xIsNotEqualy); + Bind(&xIsEqualy); + { + Label xIsDouble(env); + Label xNotDoubleOrxNotNan(env); + Branch(TaggedIsDouble(x), &xIsDouble, &xNotDoubleOrxNotNan); + Bind(&xIsDouble); + { + AddrShift doubleX = TaggedCastToDouble(x); + Label xIsNan(env); + Branch(DoubleIsNAN(doubleX), &xIsNan, &xNotDoubleOrxNotNan); + Bind(&xIsNan); + Return(TaggedFalse()); + } + Bind(&xNotDoubleOrxNotNan); + Return(TaggedTrue()); + } + Bind(&xIsNotEqualy); + { + Label xIsNumber(env); + Label xNotNumberAndxNotIntAndyNotInt(env); + Branch(TaggedIsNumber(x), &xIsNumber, &xNotNumberAndxNotIntAndyNotInt); + Bind(&xIsNumber); + { + Label xIsInt(env); + Branch(TaggedIsInt(x), &xIsInt, &xNotNumberAndxNotIntAndyNotInt); + Bind(&xIsInt); + { + Label yIsInt(env); + Branch(TaggedIsInt(y), &yIsInt, &xNotNumberAndxNotIntAndyNotInt); + Bind(&yIsInt); + Return(TaggedFalse()); + } + } + Bind(&xNotNumberAndxNotIntAndyNotInt); + { + Label yIsUndefinedOrNull(env); + Label xyNotUndefinedAndNull(env); + Branch(TaggedIsUndefinedOrNull(y), &yIsUndefinedOrNull, &xyNotUndefinedAndNull); + Bind(&yIsUndefinedOrNull); + { + Label xIsHeapObject(env); + Label xNotHeapObject(env); + Branch(TaggedIsHeapObject(x), &xIsHeapObject, &xNotHeapObject); + Bind(&xIsHeapObject); + Return(TaggedFalse()); + Bind(&xNotHeapObject); + { + Label xIsUndefinedOrNull(env); + Branch(TaggedIsUndefinedOrNull(x), &xIsUndefinedOrNull, &xyNotUndefinedAndNull); + Bind(&xIsUndefinedOrNull); + Return(TaggedTrue()); + } + } + Bind(&xyNotUndefinedAndNull); + { + Label xIsBoolean(env); + Label xNotBooleanAndyNotSpecial(env); + Branch(TaggedIsBoolean(x), &xIsBoolean, &xNotBooleanAndyNotSpecial); + Bind(&xIsBoolean); + { + Label yIsSpecial(env); + Branch(TaggedIsSpecial(y), &yIsSpecial, &xNotBooleanAndyNotSpecial); + Bind(&yIsSpecial); + Return(TaggedFalse()); + } + Bind(&xNotBooleanAndyNotSpecial); + { + Return(GetHoleConstant()); + } + } + } + } +} +} // namespace kungfu diff --git a/ecmascript/compiler/fast_stub.h b/ecmascript/compiler/fast_stub.h index 6814fa37c7eb71f9d6dd577b292a622817038769..23f2de65f3a21bd69f8e65ffbfa2cb85f04ebcdb 100644 --- a/ecmascript/compiler/fast_stub.h +++ b/ecmascript/compiler/fast_stub.h @@ -60,6 +60,16 @@ public: void GenerateCircuit() override; }; +class FastMulGCTestStub : public Stub { +public: + // 3 : 3 means argument counts + explicit FastMulGCTestStub(Circuit *circuit) : Stub("FastMulGCTest", 3, circuit) {} + ~FastMulGCTestStub() = default; + NO_MOVE_SEMANTIC(FastMulGCTestStub); + NO_COPY_SEMANTIC(FastMulGCTestStub); + void GenerateCircuit() override; +}; + class FastDivStub : public Stub { public: // 2 : 2 means argument counts @@ -70,84 +80,156 @@ public: void GenerateCircuit() override; }; -class FastFindOwnElementStub : public Stub { +class FindOwnElementStub : public Stub { public: // 3 : 3 means argument counts - explicit FastFindOwnElementStub(Circuit *circuit) : Stub("FastFindOwnElement", 3, circuit) {} - ~FastFindOwnElementStub() = default; - NO_MOVE_SEMANTIC(FastFindOwnElementStub); - NO_COPY_SEMANTIC(FastFindOwnElementStub); + explicit FindOwnElementStub(Circuit *circuit) : Stub("FindOwnElement", 3, circuit) {} + ~FindOwnElementStub() = default; + NO_MOVE_SEMANTIC(FindOwnElementStub); + NO_COPY_SEMANTIC(FindOwnElementStub); void GenerateCircuit() override; }; -class FastGetElementStub : public Stub { +class GetElementStub : public Stub { public: // 3 : 3 means argument counts - explicit FastGetElementStub(Circuit *circuit) : Stub("FastGetElement", 3, circuit) {} - ~FastGetElementStub() = default; - NO_MOVE_SEMANTIC(FastGetElementStub); - NO_COPY_SEMANTIC(FastGetElementStub); + explicit GetElementStub(Circuit *circuit) : Stub("GetElement", 3, circuit) + { + circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME); + } + ~GetElementStub() = default; + NO_MOVE_SEMANTIC(GetElementStub); + NO_COPY_SEMANTIC(GetElementStub); void GenerateCircuit() override; }; -class FastFindOwnElement2Stub : public Stub { +class FindOwnElement2Stub : public Stub { public: // 6 : 6 means argument counts - explicit FastFindOwnElement2Stub(Circuit *circuit) : Stub("FastFindOwnElement2", 6, circuit) {} - ~FastFindOwnElement2Stub() = default; - NO_MOVE_SEMANTIC(FastFindOwnElement2Stub); - NO_COPY_SEMANTIC(FastFindOwnElement2Stub); + explicit FindOwnElement2Stub(Circuit *circuit) : Stub("FindOwnElement2", 6, circuit) {} + ~FindOwnElement2Stub() = default; + NO_MOVE_SEMANTIC(FindOwnElement2Stub); + NO_COPY_SEMANTIC(FindOwnElement2Stub); void GenerateCircuit() override; }; -class FastSetElementStub : public Stub { +class SetElementStub : public Stub { public: // 5 : 5 means argument counts - explicit FastSetElementStub(Circuit *circuit) : Stub("FastSetElement", 5, circuit) {} - ~FastSetElementStub() = default; - NO_MOVE_SEMANTIC(FastSetElementStub); - NO_COPY_SEMANTIC(FastSetElementStub); + explicit SetElementStub(Circuit *circuit) : Stub("SetElement", 5, circuit) {} + ~SetElementStub() = default; + NO_MOVE_SEMANTIC(SetElementStub); + NO_COPY_SEMANTIC(SetElementStub); void GenerateCircuit() override; }; -class FastGetPropertyByIndexStub : public Stub { +class GetPropertyByIndexStub : public Stub { public: // 3 : 3 means argument counts - explicit FastGetPropertyByIndexStub(Circuit *circuit) : Stub("FastGetPropertyByIndex", 3, circuit) {} - ~FastGetPropertyByIndexStub() = default; - NO_MOVE_SEMANTIC(FastGetPropertyByIndexStub); - NO_COPY_SEMANTIC(FastGetPropertyByIndexStub); + explicit GetPropertyByIndexStub(Circuit *circuit) : Stub("GetPropertyByIndex", 3, circuit) + { + circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME); + } + ~GetPropertyByIndexStub() = default; + NO_MOVE_SEMANTIC(GetPropertyByIndexStub); + NO_COPY_SEMANTIC(GetPropertyByIndexStub); void GenerateCircuit() override; }; -class FastSetPropertyByIndexStub : public Stub { +class SetPropertyByIndexStub : public Stub { public: // 4 : 4 means argument counts - explicit FastSetPropertyByIndexStub(Circuit *circuit) : Stub("FastSetPropertyByIndex", 4, circuit) {} - ~FastSetPropertyByIndexStub() = default; - NO_MOVE_SEMANTIC(FastSetPropertyByIndexStub); - NO_COPY_SEMANTIC(FastSetPropertyByIndexStub); + explicit SetPropertyByIndexStub(Circuit *circuit) : Stub("SetPropertyByIndex", 4, circuit) + { + circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME); + } + ~SetPropertyByIndexStub() = default; + NO_MOVE_SEMANTIC(SetPropertyByIndexStub); + NO_COPY_SEMANTIC(SetPropertyByIndexStub); void GenerateCircuit() override; }; -class FastGetPropertyByNameStub : public Stub { +class GetPropertyByNameStub : public Stub { public: // 3 : 3 means argument counts - explicit FastGetPropertyByNameStub(Circuit *circuit) : Stub("FastGetPropertyByName", 3, circuit) {} - ~FastGetPropertyByNameStub() = default; - NO_MOVE_SEMANTIC(FastGetPropertyByNameStub); - NO_COPY_SEMANTIC(FastGetPropertyByNameStub); + explicit GetPropertyByNameStub(Circuit *circuit) : Stub("GetPropertyByName", 3, circuit) + { + circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME); + } + ~GetPropertyByNameStub() = default; + NO_MOVE_SEMANTIC(GetPropertyByNameStub); + NO_COPY_SEMANTIC(GetPropertyByNameStub); void GenerateCircuit() override; }; class FastModStub : public Stub { public: - // 2 means argument counts - explicit FastModStub(Circuit *circuit) : Stub("FastMod", 2, circuit) {} + // 3 means argument counts + explicit FastModStub(Circuit *circuit) : Stub("FastMod", 3, circuit) + { + circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME); + } ~FastModStub() = default; NO_MOVE_SEMANTIC(FastModStub); NO_COPY_SEMANTIC(FastModStub); void GenerateCircuit() override; }; + +class FastTypeOfStub : public Stub { +public: + // 2 means argument counts + explicit FastTypeOfStub(Circuit *circuit) : Stub("FastTypeOf", 2, circuit) {} + ~FastTypeOfStub() = default; + NO_MOVE_SEMANTIC(FastTypeOfStub); + NO_COPY_SEMANTIC(FastTypeOfStub); + void GenerateCircuit() override; +}; + +class FunctionCallInternalStub : public Stub { +public: + // 5 : 5 means argument counts + explicit FunctionCallInternalStub(Circuit *circuit) : Stub("FunctionCallInternal", 5, circuit) {} + ~FunctionCallInternalStub() = default; + NO_MOVE_SEMANTIC(FunctionCallInternalStub); + NO_COPY_SEMANTIC(FunctionCallInternalStub); + void GenerateCircuit() override; +}; + +class GetPropertyByValueStub : public Stub { +public: + // 3 : 3 means argument counts + explicit GetPropertyByValueStub(Circuit *circuit) : Stub("FastGetPropertyByValue", 3, circuit) + { + circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME); + } + ~GetPropertyByValueStub() = default; + NO_MOVE_SEMANTIC(GetPropertyByValueStub); + NO_COPY_SEMANTIC(GetPropertyByValueStub); + void GenerateCircuit() override; +}; + +class SetPropertyByValueStub : public Stub { +public: + // 4 : 4 means argument counts + explicit SetPropertyByValueStub(Circuit *circuit) : Stub("FastSetPropertyByValue", 4, circuit) + { + circuit->SetFrameType(panda::ecmascript::FrameType::OPTIMIZED_ENTRY_FRAME); + } + ~SetPropertyByValueStub() = default; + NO_MOVE_SEMANTIC(SetPropertyByValueStub); + NO_COPY_SEMANTIC(SetPropertyByValueStub); + void GenerateCircuit() override; +}; + +class FastEqualStub : public Stub { +public: + // 2 means argument counts + explicit FastEqualStub(Circuit *circuit) : Stub("FastEqual", 2, circuit) {} + ~FastEqualStub() = default; + NO_MOVE_SEMANTIC(FastEqualStub); + NO_COPY_SEMANTIC(FastEqualStub); + void GenerateCircuit() override; +}; } // namespace kungfu -#endif // ECMASCRIPT_COMPILER_FASTPATH_STUB_H \ No newline at end of file + +#endif // ECMASCRIPT_COMPILER_FASTPATH_STUB_H diff --git a/ecmascript/compiler/fast_stub_define.h b/ecmascript/compiler/fast_stub_define.h index ccf3bf3c3140ef41882c7dfac82dce6aea719be5..c94c34dfe329d559109cdc0630eead6170297ba0 100644 --- a/ecmascript/compiler/fast_stub_define.h +++ b/ecmascript/compiler/fast_stub_define.h @@ -27,7 +27,12 @@ namespace kungfu { V(JSProxySetProperty, 6) \ V(GetHash32, 2) \ V(FindElementWithCache, 4) \ - V(StringGetHashCode, 1) + V(Execute, 5) \ + V(StringGetHashCode, 1) \ + V(FloatMod, 2) \ + V(SetValueWithBarrier, 4) \ + V(GetTaggedArrayPtrTest, 1) \ + V(NewInternalString, 2) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define FAST_RUNTIME_STUB_LIST(V) \ @@ -35,7 +40,7 @@ namespace kungfu { V(FastSub, 2) \ V(FastMul, 2) \ V(FastDiv, 2) \ - V(FastMod, 2) \ + V(FastMod, 3) \ V(FastEqual, 2) \ V(FastTypeOf, 2) \ V(FastStrictEqual, 2) \ @@ -43,8 +48,8 @@ namespace kungfu { V(IsSpecialIndexedObjForGet, 1) \ V(GetPropertyByName, 3) \ V(GetElement, 2) \ - V(SetElement, 5) \ V(SetPropertyByName, 5) \ + V(SetElement, 5) \ V(SetGlobalOwnProperty, 5) \ V(GetGlobalOwnProperty, 3) \ V(SetOwnPropertyByName, 4) \ @@ -57,11 +62,23 @@ namespace kungfu { V(FindOwnProperty2, 6) \ V(FindOwnElement2, 6) \ V(GetPropertyByIndex, 3) \ - V(SetPropertyByIndex, 4) + V(FunctionCallInternal, 5) \ + V(SetPropertyByIndex, 4) \ + V(GetPropertyByValue, 3) \ + V(SetPropertyByValue, 4) \ + V(FastMulGCTest, 3) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define TEST_FUNC_LIST(V) \ + V(FastLoadElement, 2) \ + V(PhiGateTest, 1) \ + V(LoopTest, 1) \ + V(LoopTest1, 1) -#define CALL_STUB_LIST(V) \ - FAST_RUNTIME_STUB_LIST(V) \ - EXTERNAL_RUNTIMESTUB_LIST(V) +#define CALL_STUB_LIST(V) \ + FAST_RUNTIME_STUB_LIST(V) \ + EXTERNAL_RUNTIMESTUB_LIST(V) \ + TEST_FUNC_LIST(V) enum CallStubId { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -69,11 +86,13 @@ enum CallStubId { FAST_RUNTIME_STUB_LIST(DEF_FAST_STUB) FAST_STUB_MAXCOUNT, EXTERNAL_RUNTIME_STUB_BEGIN = FAST_STUB_MAXCOUNT - 1, EXTERNAL_RUNTIMESTUB_LIST(DEF_FAST_STUB) EXTERN_RUNTIME_STUB_MAXCOUNT, + TEST_FUNC_BEGIN = EXTERN_RUNTIME_STUB_MAXCOUNT - 1, + TEST_FUNC_LIST(DEF_FAST_STUB) TEST_FUNC_MAXCOUNT, #undef DEF_FAST_STUB - CALL_STUB_MAXCOUNT = EXTERN_RUNTIME_STUB_MAXCOUNT, + CALL_STUB_MAXCOUNT = TEST_FUNC_MAXCOUNT, }; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define FAST_STUB_ID(name) kungfu::CallStubId::NAME_##name } // namespace kungfu -#endif // ECMASCRIPT_COMPILER_FASTSTUB_DEFINE_H \ No newline at end of file +#endif // ECMASCRIPT_COMPILER_FASTSTUB_DEFINE_H diff --git a/ecmascript/compiler/gate.cpp b/ecmascript/compiler/gate.cpp index f2e09834fd7cd10388850bd7a88853a39aa1ec4e..19f6aa8b62a91ecb99e9c8d42387da76a586d426 100644 --- a/ecmascript/compiler/gate.cpp +++ b/ecmascript/compiler/gate.cpp @@ -185,12 +185,20 @@ Properties OpCode::GetProperties() const return {INT64, NO_STATE, NO_DEPEND, VALUE(INT32), NO_ROOT}; case ZEXT_INT1_TO_INT32: return {INT32, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; + case ZEXT_INT8_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT8), NO_ROOT}; + case ZEXT_INT16_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT16), NO_ROOT}; case ZEXT_INT1_TO_INT64: return {INT64, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; case SEXT_INT32_TO_INT64: return {INT64, NO_STATE, NO_DEPEND, VALUE(INT32), NO_ROOT}; case SEXT_INT1_TO_INT32: return {INT32, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; + case SEXT_INT8_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT8), NO_ROOT}; + case SEXT_INT16_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(INT8), NO_ROOT}; case SEXT_INT1_TO_INT64: return {INT64, NO_STATE, NO_DEPEND, VALUE(INT1), NO_ROOT}; case TRUNC_INT64_TO_INT32: @@ -290,9 +298,11 @@ Properties OpCode::GetProperties() const return {NOVALUE, NO_STATE, ONE_DEPEND, VALUE(FLOAT64, PtrValueCode()), NO_ROOT}; case INT32_TO_FLOAT64: return {FLOAT64, NO_STATE, NO_DEPEND, VALUE(INT32), NO_ROOT}; - case INT64_TO_FLOAT64: + case FLOAT64_TO_INT32: + return {INT32, NO_STATE, NO_DEPEND, VALUE(FLOAT64), NO_ROOT}; + case BITCAST_INT64_TO_FLOAT64: return {FLOAT64, NO_STATE, NO_DEPEND, VALUE(INT64), NO_ROOT}; - case FLOAT64_TO_INT64: + case BITCAST_FLOAT64_TO_INT64: return {INT64, NO_STATE, NO_DEPEND, VALUE(FLOAT64), NO_ROOT}; default: std::cerr << "Please complete OpCode properties (OpCode=" << this->op << ")" << std::endl; @@ -381,6 +391,7 @@ std::string OpCode::Str() const {INT64_CALL, "INT64_CALL"}, {FLOAT32_CALL, "FLOAT32_CALL"}, {FLOAT64_CALL, "FLOAT64_CALL"}, + {TAGGED_POINTER_CALL, "TAGGED_POINTER_CALL"}, {ALLOCA, "ALLOCA"}, {INT1_ARG, "INT1_ARG"}, {INT8_ARG, "INT8_ARG"}, @@ -400,9 +411,13 @@ std::string OpCode::Str() const {FLOAT64_CONSTANT, "FLOAT64_CONSTANT"}, {ZEXT_INT32_TO_INT64, "ZEXT_INT32_TO_INT64"}, {ZEXT_INT1_TO_INT32, "ZEXT_INT1_TO_INT32"}, + {ZEXT_INT8_TO_INT32, "ZEXT_INT8_TO_INT32"}, + {ZEXT_INT16_TO_INT32, "ZEXT_INT16_TO_INT32"}, {ZEXT_INT1_TO_INT64, "ZEXT_INT1_TO_INT64"}, {SEXT_INT32_TO_INT64, "SEXT_INT32_TO_INT64"}, {SEXT_INT1_TO_INT32, "SEXT_INT1_TO_INT32"}, + {SEXT_INT8_TO_INT32, "SEXT_INT8_TO_INT32"}, + {SEXT_INT16_TO_INT32, "SEXT_INT16_TO_INT32"}, {SEXT_INT1_TO_INT64, "SEXT_INT1_TO_INT64"}, {TRUNC_INT64_TO_INT32, "TRUNC_INT64_TO_INT32"}, {TRUNC_INT64_TO_INT1, "TRUNC_INT64_TO_INT1"}, @@ -476,8 +491,9 @@ std::string OpCode::Str() const {FLOAT32_STORE, "FLOAT32_STORE"}, {FLOAT64_STORE, "FLOAT64_STORE"}, {INT32_TO_FLOAT64, "INT32_TO_FLOAT64"}, - {INT64_TO_FLOAT64, "INT64_TO_FLOAT64"}, - {FLOAT64_TO_INT64, "FLOAT64_TO_INT64"}, + {FLOAT64_TO_INT32, "FLOAT64_TO_INT32"}, + {BITCAST_INT64_TO_FLOAT64, "BITCAST_INT64_TO_FLOAT64"}, + {BITCAST_FLOAT64_TO_INT64, "BITCAST_FLOAT64_TO_INT64"}, }; if (strMap.count(this->op) > 0) { return strMap.at(this->op); @@ -1249,6 +1265,11 @@ void Gate::SetMark(MarkCode mark, TimeStamp stamp) this->mark = mark; } +TypeCode Gate::GetTypeCode() const +{ + return type; +} + bool OpCode::IsRoot() const { return (this->GetProperties().states == OpCode::CIRCUIT_ROOT) || (this->op == OpCode::CIRCUIT_ROOT); @@ -1305,4 +1326,9 @@ bool OpCode::IsLoopHead() const { return (this->op == OpCode::LOOP_BEGIN); } + +bool OpCode::IsNop() const +{ + return (this->op == OpCode::NOP); +} } // namespace kungfu \ No newline at end of file diff --git a/ecmascript/compiler/gate.h b/ecmascript/compiler/gate.h index a112479593b8bf378cf7639eb60a96ab746a5cd9..c41de70e44e6770d8b15a7836663b7f484441bd2 100644 --- a/ecmascript/compiler/gate.h +++ b/ecmascript/compiler/gate.h @@ -49,6 +49,7 @@ enum ValueCode { INT64, FLOAT32, FLOAT64, + TAGGED_POINTER, }; std::string ValueCodeToStr(ValueCode valueCode); @@ -128,6 +129,7 @@ public: INT64_CALL, FLOAT32_CALL, FLOAT64_CALL, + TAGGED_POINTER_CALL, ALLOCA, INT1_ARG, INT8_ARG, @@ -147,9 +149,13 @@ public: FLOAT64_CONSTANT, ZEXT_INT32_TO_INT64, ZEXT_INT1_TO_INT32, + ZEXT_INT8_TO_INT32, + ZEXT_INT16_TO_INT32, ZEXT_INT1_TO_INT64, SEXT_INT32_TO_INT64, SEXT_INT1_TO_INT32, + SEXT_INT8_TO_INT32, + SEXT_INT16_TO_INT32, SEXT_INT1_TO_INT64, TRUNC_INT64_TO_INT32, TRUNC_INT64_TO_INT1, @@ -224,8 +230,9 @@ public: FLOAT32_STORE, FLOAT64_STORE, INT32_TO_FLOAT64, - INT64_TO_FLOAT64, - FLOAT64_TO_INT64, + FLOAT64_TO_INT32, + BITCAST_INT64_TO_FLOAT64, + BITCAST_FLOAT64_TO_INT64, TAG64_TO_INT1, }; @@ -253,6 +260,7 @@ public: [[nodiscard]] bool IsCFGMerge() const; [[nodiscard]] bool IsControlCase() const; [[nodiscard]] bool IsLoopHead() const; + [[nodiscard]] bool IsNop() const; ~OpCode() = default; private: @@ -368,6 +376,7 @@ public: [[nodiscard]] bool Verify() const; [[nodiscard]] MarkCode GetMark(TimeStamp stamp) const; void SetMark(MarkCode mark, TimeStamp stamp); + TypeCode GetTypeCode() const; ~Gate() = default; private: diff --git a/ecmascript/compiler/llvm/llvm.patch b/ecmascript/compiler/llvm/llvm.patch new file mode 100644 index 0000000000000000000000000000000000000000..bfd0c418051ef5e979aaace5e3ac76cc2b652807 --- /dev/null +++ b/ecmascript/compiler/llvm/llvm.patch @@ -0,0 +1,125 @@ +diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt +index 0e85afa82c7..43756892e40 100644 +--- a/llvm/CMakeLists.txt ++++ b/llvm/CMakeLists.txt +@@ -505,8 +505,15 @@ option(LLVM_BUILD_RUNTIME + "Build the LLVM runtime libraries." ON) + option(LLVM_BUILD_EXAMPLES + "Build the LLVM example programs. If OFF, just generate build targets." OFF) ++option(BUILD_ARK_GC_SUPPORT ++ "ARK support GC. If ON, support GC." OFF) ++if(BUILD_ARK_GC_SUPPORT) ++ add_definitions(-DARK_GC_SUPPORT) ++endif(BUILD_ARK_GC_SUPPORT) ++ + option(LLVM_INCLUDE_EXAMPLES "Generate build targets for the LLVM examples" ON) + ++ + if(LLVM_BUILD_EXAMPLES) + add_definitions(-DBUILD_EXAMPLES) + endif(LLVM_BUILD_EXAMPLES) +diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp +index 1da20371caf..e0264827556 100644 +--- a/llvm/lib/Target/X86/X86FrameLowering.cpp ++++ b/llvm/lib/Target/X86/X86FrameLowering.cpp +@@ -1168,6 +1168,25 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, + else + MFI.setOffsetAdjustment(-StackSize); + } ++#ifdef ARK_GC_SUPPORT ++ // push marker ++ if (MF.getFunction().hasFnAttribute("js-stub-call")) ++ { ++ int64_t marker = 0x0; ++ MF.getFunction() ++ .getFnAttribute("js-stub-call") ++ .getValueAsString() ++ .getAsInteger(10, marker);//marker 1 break frame ++ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64i32 : X86::PUSH32i8)) ++ .addImm(marker) ++ .setMIFlag(MachineInstr::FrameSetup); ++ if (marker == JS_ENTRY_FRAME_MARK) { ++ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::PUSH64i32 : X86::PUSH32i8)) ++ .addImm(marker) ++ .setMIFlag(MachineInstr::FrameSetup); ++ } ++ } ++#endif + + // For EH funclets, only allocate enough space for outgoing calls. Save the + // NumBytes value that we would've used for the parent frame. +@@ -1635,6 +1654,27 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, + uint64_t SEHStackAllocAmt = NumBytes; + + if (HasFP) { ++#ifdef ARK_GC_SUPPORT ++ if (MF.getFunction().hasFnAttribute("js-stub-call")) ++ { ++ int64_t marker = 0x0; ++ MF.getFunction() ++ .getFnAttribute("js-stub-call") ++ .getValueAsString() ++ .getAsInteger(10, marker);//marker 1 break frame ++ ++ // pop marker ++ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), ++ MachineFramePtr) ++ .setMIFlag(MachineInstr::FrameDestroy); ++ if (marker == JS_ENTRY_FRAME_MARK) { ++ // pop thread.fp ++ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), ++ MachineFramePtr) ++ .setMIFlag(MachineInstr::FrameDestroy); ++ } ++ } ++#endif + // Pop EBP. + BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), + MachineFramePtr) +@@ -1993,8 +2033,33 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots( + + if (hasFP(MF)) { + // emitPrologue always spills frame register the first thing. ++#ifdef ARK_GC_SUPPORT ++ if (MF.getFunction().hasFnAttribute("js-stub-call")) { ++ int64_t marker = 0x0; ++ MF.getFunction() ++ .getFnAttribute("js-stub-call") ++ .getValueAsString() ++ .getAsInteger(10, marker);//marker 1 break frame ++ if (marker == JS_ENTRY_FRAME_MARK) { ++ SpillSlotOffset -= 3 * SlotSize; // add type and thread.fp ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ CalleeSavedFrameSize += (2 * SlotSize); ++ } else { ++ SpillSlotOffset -= 2 * SlotSize; // add type ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ CalleeSavedFrameSize += SlotSize; ++ } ++ } else { ++ SpillSlotOffset -= SlotSize; // add type and thread.fp ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ } ++#else + SpillSlotOffset -= SlotSize; + MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++#endif + + // Since emitPrologue and emitEpilogue will handle spilling and restoring of + // the frame register, we can delete it from CSI list and not have to worry +diff --git a/llvm/lib/Target/X86/X86FrameLowering.h b/llvm/lib/Target/X86/X86FrameLowering.h +index 2103d6471ea..3fd89b0d9ee 100644 +--- a/llvm/lib/Target/X86/X86FrameLowering.h ++++ b/llvm/lib/Target/X86/X86FrameLowering.h +@@ -15,6 +15,8 @@ + + #include "llvm/CodeGen/TargetFrameLowering.h" + ++#define JS_ENTRY_FRAME_MARK 1 ++ + namespace llvm { + + class MachineInstrBuilder; diff --git a/ecmascript/compiler/llvm_stackmap_parse.cpp b/ecmascript/compiler/llvm/llvm_stackmap_parser.cpp similarity index 47% rename from ecmascript/compiler/llvm_stackmap_parse.cpp rename to ecmascript/compiler/llvm/llvm_stackmap_parser.cpp index e49ed47e66b5370bfebfda2ef42d32b6d604c164..df7c4527e43ef49ae10df39df416c471433fd27b 100644 --- a/ecmascript/compiler/llvm_stackmap_parse.cpp +++ b/ecmascript/compiler/llvm/llvm_stackmap_parser.cpp @@ -13,15 +13,15 @@ * limitations under the License. */ -#include "ecmascript/compiler/llvm_stackmap_parse.h" +#include "llvm_stackmap_parser.h" #include #include #include namespace kungfu { -std::string LocationTy::TypeToString(Kind location) const +std::string LocationTy::TypeToString(Kind loc) const { - switch (location) { + switch (loc) { case Kind::REGISTER: return "Register Reg Value in a register"; case Kind::DIRECT: @@ -37,48 +37,86 @@ std::string LocationTy::TypeToString(Kind location) const } } -bool LLVMStackMapParse::StackMapByAddr(uintptr_t funcAddr, DwarfRegAndOffsetType &info) +bool LLVMStackMapParser::StackMapByAddr(uintptr_t funcAddr, DwarfRegAndOffsetTypeVector &infos) { + bool found = false; for (auto it: callSiteInfos_) { +#ifndef NDEBUG + LOG_ECMA(INFO) << __FUNCTION__ << std::hex << " addr:" << it.first << std::endl; +#endif if (it.first == funcAddr) { - info = it.second; - return true; + DwarfRegAndOffsetType info = it.second; +#ifndef NDEBUG + LOG_ECMA(INFO) << __FUNCTION__ << " info <" << info.first << " ," << info.second << " >" << std::endl; +#endif + infos.push_back(info); + found = true; } } - return false; + return found; } -void LLVMStackMapParse::CalcCallSite() +bool LLVMStackMapParser::StackMapByFuncAddrFp(uintptr_t funcAddr, uintptr_t frameFp, + std::set &slotAddrs) +{ + DwarfRegAndOffsetTypeVector infos; + if (!StackMapByAddr(funcAddr, infos)) { + return false; + } + uintptr_t *fp = reinterpret_cast(frameFp); + uintptr_t **address = nullptr; + for (auto &info: infos) { + if (info.first == SP_DWARF_REG_NUM) { + uintptr_t *rsp = fp + SP_OFFSET; + address = reinterpret_cast(reinterpret_cast(rsp) + info.second); + } else if (info.first == FP_DWARF_REG_NUM) { + fp = reinterpret_cast(*fp); + address = reinterpret_cast(reinterpret_cast(fp) + info.second); + } else { + address = nullptr; + abort(); + } +#ifndef NDEBUG + LOG_ECMA(INFO) << std::hex << "stackMap ref addr:" << address; + LOG_ECMA(INFO) << " value:" << *address; + LOG_ECMA(INFO) << " *value :" << **address << std::endl; +#endif + slotAddrs.insert(reinterpret_cast(address)); + } + return true; +} + +void LLVMStackMapParser::CalcCallSite() { uint64_t recordNum = 0; + auto calStkMapRecordFunc = [this, &recordNum](uintptr_t address, int recordId) { + struct StkMapRecordHeadTy recordHead = llvmStackMap_.StkMapRecord[recordNum + recordId].head; + for (int j = 0; j < recordHead.NumLocations; j++) { + struct LocationTy loc = llvmStackMap_.StkMapRecord[recordNum + recordId].Locations[j]; + uint32_t instructionOffset = recordHead.InstructionOffset; + uintptr_t callsite = address + instructionOffset; + if (loc.location == LocationTy::Kind::INDIRECT) { + DwarfRegAndOffsetType info(loc.DwarfRegNum, loc.OffsetOrSmallConstant); + Fun2InfoType callSiteInfo {callsite, info}; + callSiteInfos_.push_back(callSiteInfo); + } + } + }; for (size_t i = 0; i < llvmStackMap_.StkSizeRecords.size(); i++) { uintptr_t address = llvmStackMap_.StkSizeRecords[i].functionAddress; - std::cout << std::hex << "address " << address << std::endl; uint64_t recordCount = llvmStackMap_.StkSizeRecords[i].recordCount; - std::cout << std::hex << "recordCount " << recordCount << std::endl; - recordNum += recordCount; - std::cout << std::hex << "recordNum " << recordNum << std::endl; - struct StkMapRecordHeadTy recordHead = llvmStackMap_.StkMapRecord[recordNum - 1].head; - uint32_t instructionOffset = recordHead.InstructionOffset; - std::cout << std::hex << "instructionOffset " << instructionOffset << std::endl; - uintptr_t callsite = address + instructionOffset; - - for (int j = 0; j < recordHead.NumLocations; j++) { - struct LocationTy loc = llvmStackMap_.StkMapRecord[recordNum - 1].Locations[j]; - if (loc.location == LocationTy::Kind::INDIRECT) { - DwarfRegAndOffsetType info(loc.DwarfRegNum, loc.OffsetOrSmallConstant); - Fun2InfoType callSiteInfo {callsite, info}; - callSiteInfos_.push_back(callSiteInfo); - } + for (uint64_t k = 0; k < recordCount; k++) { + calStkMapRecordFunc(address, k); } + recordNum += recordCount; } } -bool LLVMStackMapParse::CalculateStackMap(const uint8_t *stackMapAddr) +bool LLVMStackMapParser::CalculateStackMap(const uint8_t *stackMapAddr) { stackMapAddr_ = stackMapAddr; if (!stackMapAddr_) { - std::cerr << "stackMapAddr_ nullptr error ! " << std::endl; + LOG_ECMA(ERROR) << "stackMapAddr_ nullptr error ! " << std::endl; return false; } dataInfo_ = std::make_unique(stackMapAddr_); @@ -122,4 +160,29 @@ bool LLVMStackMapParse::CalculateStackMap(const uint8_t *stackMapAddr) CalcCallSite(); return true; } -} // namespace kungfu \ No newline at end of file + +bool LLVMStackMapParser::CalculateStackMap(const uint8_t *stackMapAddr, + uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr) +{ + bool ret = CalculateStackMap(stackMapAddr); + if (!ret) { + return ret; + } + // update functionAddress from host side to device side +#ifndef NDEBUG + LOG_ECMA(INFO) << "stackmap calculate update funcitonaddress " << std::endl; +#endif + for (size_t i = 0; i < llvmStackMap_.StkSizeRecords.size(); i++) { + uintptr_t hostAddr = llvmStackMap_.StkSizeRecords[i].functionAddress; + uintptr_t deviceAddr = hostAddr - hostCodeSectionAddr + deviceCodeSectionAddr; + llvmStackMap_.StkSizeRecords[i].functionAddress = deviceAddr; +#ifndef NDEBUG + LOG_ECMA(INFO) << std::dec << i << "th function " << std::hex << hostAddr << " ---> " << deviceAddr + << std::endl; +#endif + } + callSiteInfos_.clear(); + CalcCallSite(); + return true; +} +} // namespace kungfu diff --git a/ecmascript/compiler/llvm_stackmap_parse.h b/ecmascript/compiler/llvm/llvm_stackmap_parser.h similarity index 54% rename from ecmascript/compiler/llvm_stackmap_parse.h rename to ecmascript/compiler/llvm/llvm_stackmap_parser.h index e22e55499681784950a835350311ba45f32d16e8..37b4afb4c937bcfcb405c44ffcec4d5a27366190 100644 --- a/ecmascript/compiler/llvm_stackmap_parse.h +++ b/ecmascript/compiler/llvm/llvm_stackmap_parser.h @@ -18,13 +18,26 @@ #include #include -#include #include +#include +#include "ecmascript/common.h" +#include "ecmascript/ecma_macros.h" + +#ifdef PANDA_TARGET_AMD64 +#define SP_DWARF_REG_NUM 7 +#define FP_DWARF_REG_NUM 6 +#define SP_OFFSET 2 +#else +#define SP_DWARF_REG_NUM 0 +#define FP_DWARF_REG_NUM 0 +#define SP_OFFSET 0 +#endif namespace kungfu { using OffsetType = int32_t; using DwarfRegType = uint16_t; using DwarfRegAndOffsetType = std::pair; +using DwarfRegAndOffsetTypeVector = std::vector; using Fun2InfoType = std::pair; struct Header { @@ -33,9 +46,9 @@ struct Header { uint16_t Reserved1; // Reserved (expected to be 0) void Print() const { - std::cout << "----- head ----" << std::endl; - std::cout << " version:" << stackmapversion << std::endl; - std::cout << "+++++ head ++++" << std::endl; + LOG_ECMA(INFO) << "----- head ----" << std::endl; + LOG_ECMA(INFO) << " version:" << static_cast(stackmapversion) << std::endl; + LOG_ECMA(INFO) << "+++++ head ++++" << std::endl; } }; @@ -45,9 +58,9 @@ struct StkSizeRecordTy { uint64_t recordCount; void Print() const { - std::cout << " functionAddress:0x" << std::hex << functionAddress << std::endl; - std::cout << " stackSize:" << std::dec << stackSize << std::endl; - std::cout << " recordCount:" << std::dec << recordCount << std::endl; + LOG_ECMA(INFO) << " functionAddress:0x" << std::hex << functionAddress << std::endl; + LOG_ECMA(INFO) << " stackSize:" << std::dec << stackSize << std::endl; + LOG_ECMA(INFO) << " recordCount:" << std::dec << recordCount << std::endl; } }; @@ -55,7 +68,7 @@ struct ConstantsTy { uint64_t LargeConstant; void Print() const { - std::cout << " LargeConstant:" << LargeConstant << std::endl; + LOG_ECMA(INFO) << " LargeConstant:" << LargeConstant << std::endl; } }; @@ -66,14 +79,14 @@ struct StkMapRecordHeadTy { uint16_t NumLocations; void Print() const { - std::cout << " PatchPointID:" << std::hex << PatchPointID << std::endl; - std::cout << " instructionOffset:" << std::hex << InstructionOffset << std::endl; - std::cout << " Reserved:" << Reserved << std::endl; - std::cout << " NumLocations:" << NumLocations << std::endl; + LOG_ECMA(INFO) << " PatchPointID:" << std::hex << PatchPointID << std::endl; + LOG_ECMA(INFO) << " instructionOffset:" << std::hex << InstructionOffset << std::endl; + LOG_ECMA(INFO) << " Reserved:" << Reserved << std::endl; + LOG_ECMA(INFO) << " NumLocations:" << NumLocations << std::endl; } }; -struct LocationTy { +struct LocationTy { enum class Kind: uint8_t { REGISTER = 1, DIRECT = 2, @@ -88,14 +101,14 @@ struct LocationTy { uint16_t Reserved_1; OffsetType OffsetOrSmallConstant; - std::string TypeToString(Kind location) const; + std::string PUBLIC_API TypeToString(Kind loc) const; void Print() const { - std::cout << TypeToString(location); - std::cout << ", size:" << std::dec << LocationSize; - std::cout << "\tDwarfRegNum:" << DwarfRegNum; - std::cout << "\t OffsetOrSmallConstant:" << OffsetOrSmallConstant << std::endl; + LOG_ECMA(INFO) << TypeToString(location); + LOG_ECMA(INFO) << ", size:" << std::dec << LocationSize; + LOG_ECMA(INFO) << "\tDwarfRegNum:" << DwarfRegNum; + LOG_ECMA(INFO) << "\t OffsetOrSmallConstant:" << OffsetOrSmallConstant << std::endl; } }; @@ -105,9 +118,9 @@ struct LiveOutsTy { uint8_t SizeinBytes; void Print() const { - std::cout << " Dwarf RegNum:" << DwarfRegNum << std::endl; - std::cout << " Reserved:" << Reserved << std::endl; - std::cout << " SizeinBytes:" << SizeinBytes << std::endl; + LOG_ECMA(INFO) << " Dwarf RegNum:" << DwarfRegNum << std::endl; + LOG_ECMA(INFO) << " Reserved:" << Reserved << std::endl; + LOG_ECMA(INFO) << " SizeinBytes:" << SizeinBytes << std::endl; } }; @@ -120,38 +133,38 @@ struct StkMapRecordTy { head.Print(); auto size = Locations.size(); for (size_t i = 0; i < size; i++) { - std::cout << " #" << std::dec << i << ":"; + LOG_ECMA(INFO) << " #" << std::dec << i << ":"; Locations[i].Print(); } size = LiveOuts.size(); for (size_t i = 0; i < size; i++) { - std::cout << " liveOuts[" << i << "] info:" << std::endl; + LOG_ECMA(INFO) << " liveOuts[" << i << "] info:" << std::endl; } } }; class DataInfo { public: - explicit DataInfo(const uint8_t* data): data_(data), offset(0) {} + explicit DataInfo(const uint8_t *data): data_(data), offset_(0) {} ~DataInfo() { data_ = nullptr; - offset = 0; + offset_ = 0; } template T Read() { - T t = *reinterpret_cast(data_ + offset); - offset += sizeof(T); + T t = *reinterpret_cast(data_ + offset_); + offset_ += sizeof(T); return t; } unsigned int GetOffset() const { - return offset; + return offset_; } private: - const uint8_t* data_; - unsigned int offset; + const uint8_t *data_; + unsigned int offset_; }; struct LLVMStackMap { @@ -163,41 +176,45 @@ struct LLVMStackMap { { head.Print(); for (size_t i = 0; i < StkSizeRecords.size(); i++) { - std::cout << "stkSizeRecord[" << i << "] info:" << std::endl; + LOG_ECMA(INFO) << "stkSizeRecord[" << i << "] info:" << std::endl; StkSizeRecords[i].Print(); } for (size_t i = 0; i < Constants.size(); i++) { - std::cout << "constants[" << i << "] info:" << std::endl; + LOG_ECMA(INFO) << "constants[" << i << "] info:" << std::endl; Constants[i].Print(); } for (size_t i = 0; i < StkMapRecord.size(); i++) { - std::cout << "StkMapRecord[" << i << "] info:" << std::endl; + LOG_ECMA(INFO) << "StkMapRecord[" << i << "] info:" << std::endl; StkMapRecord[i].Print(); } } }; -class LLVMStackMapParse { +class LLVMStackMapParser { public: - static LLVMStackMapParse& GetInstance() + static LLVMStackMapParser& GetInstance() { - static LLVMStackMapParse instance; + static LLVMStackMapParser instance; return instance; } - bool CalculateStackMap(const uint8_t *stackMapAddr); - void Print() const + bool PUBLIC_API CalculateStackMap(const uint8_t *stackMapAddr); + bool PUBLIC_API CalculateStackMap(const uint8_t *stackMapAddr, + uintptr_t hostCodeSectionAddr, uintptr_t deviceCodeSectionAddr); + void PUBLIC_API Print() const { llvmStackMap_.Print(); } - bool StackMapByAddr(uintptr_t funcAddr, DwarfRegAndOffsetType &info); + bool StackMapByAddr(uintptr_t funcAddr, DwarfRegAndOffsetTypeVector &infos); + bool StackMapByFuncAddrFp(uintptr_t funcAddr, uintptr_t frameFp, + std::set &slotAddrs); private: - LLVMStackMapParse() + LLVMStackMapParser() { stackMapAddr_ = nullptr; callSiteInfos_.clear(); dataInfo_ = nullptr; } - ~LLVMStackMapParse() + ~LLVMStackMapParser() { stackMapAddr_ = nullptr; callSiteInfos_.clear(); diff --git a/ecmascript/compiler/llvm_codegen.cpp b/ecmascript/compiler/llvm_codegen.cpp index f58bef33abafa3372e9b0865dffeefa0f2ccee83..973343fe5118f78b977de04186e143fe1d0114aa 100644 --- a/ecmascript/compiler/llvm_codegen.cpp +++ b/ecmascript/compiler/llvm_codegen.cpp @@ -14,8 +14,40 @@ */ #include "llvm_codegen.h" +#include #include "ecmascript/object_factory.h" #include "stub_descriptor.h" +#include "ecmascript/ecma_macros.h" +#include "llvm/ADT/APInt.h" +#include "llvm/CodeGen/BuiltinGCs.h" +#include "llvm/ExecutionEngine/ExecutionEngine.h" +#include "llvm/ExecutionEngine/GenericValue.h" +#include "llvm/IR/Argument.h" +#include "llvm/IR/BasicBlock.h" +#include "llvm/IR/Constants.h" +#include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/InstrTypes.h" +#include "llvm/IR/Instructions.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/Module.h" +#include "llvm/IR/Type.h" +#include "llvm/IR/Verifier.h" +#include "llvm/IRReader/IRReader.h" +#include "llvm/Transforms/Scalar.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Host.h" +#include "llvm/Support/TargetSelect.h" +#include "llvm/llvm_stackmap_parser.h" +#include "llvm-c/Analysis.h" +#include "llvm-c/Core.h" +#include "llvm-c/Disassembler.h" +#include "llvm-c/DisassemblerTypes.h" +#include "llvm-c/Target.h" +#include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm-c/Transforms/Scalar.h" using namespace panda::ecmascript; namespace kungfu { @@ -32,23 +64,206 @@ void LLVMModuleAssembler::AssembleModule() assembler_.Run(); } -void LLVMModuleAssembler::CopyAssembleCodeToModule(StubModule *module) +void LLVMModuleAssembler::AssembleStubModule(StubModule *module) { - auto codeBuff = reinterpret_cast
(assembler_.GetCodeBuffer()); + auto codeBuff = reinterpret_cast(assembler_.GetCodeBuffer()); auto engine = assembler_.GetEngine(); + std::map addr2name; for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) { auto stubfunction = stubmodule_->GetStubFunction(i); +#ifndef NDEBUG + LOG_ECMA(INFO) << " AssembleStubModule :" << i << " th " << std::endl; +#endif if (stubfunction != nullptr) { - Address stubEntry = reinterpret_cast
(LLVMGetPointerToGlobal(engine, stubfunction)); + uintptr_t stubEntry = reinterpret_cast(LLVMGetPointerToGlobal(engine, stubfunction)); module->SetStubEntry(i, stubEntry - codeBuff); + addr2name[stubEntry] = FastStubDescriptors::GetInstance().GetStubDescriptor(i)->GetName(); +#ifndef NDEBUG + LOG_ECMA(INFO) << "name : " << addr2name[codeBuff] << std::endl; +#endif } } + module->SetHostCodeSectionAddr(codeBuff); + // stackmaps ptr and size + module->SetStackMapAddr(reinterpret_cast(assembler_.GetStackMapsSection())); + module->SetStackMapSize(assembler_.GetStackMapsSize()); +#ifndef NDEBUG + assembler_.Disassemble(addr2name); +#endif +} + +static uint8_t *RoundTripAllocateCodeSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment, + [[maybe_unused]] unsigned sectionID, const char *sectionName) +{ + LOG_ECMA(INFO) << "RoundTripAllocateCodeSection object " << object << " - "; + struct CodeInfo& state = *static_cast(object); + uint8_t *addr = state.AllocaCodeSection(size, sectionName); + LOG_ECMA(INFO) << "RoundTripAllocateCodeSection addr:" << std::hex << reinterpret_cast(addr) << + addr << " size:0x" << size << " + "; + return addr; +} + +static uint8_t *RoundTripAllocateDataSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment, + [[maybe_unused]] unsigned sectionID, const char *sectionName, + [[maybe_unused]] LLVMBool isReadOnly) +{ + struct CodeInfo& state = *static_cast(object); + return state.AllocaDataSection(size, sectionName); +} + +static LLVMBool RoundTripFinalizeMemory(void *object, [[maybe_unused]] char **errMsg) +{ + LOG_ECMA(INFO) << "RoundTripFinalizeMemory object " << object << " - "; + return 0; +} + +static void RoundTripDestroy(void *object) +{ + LOG_ECMA(INFO) << "RoundTripDestroy object " << object << " - "; +} + +void LLVMAssembler::UseRoundTripSectionMemoryManager() +{ + auto sectionMemoryManager = std::make_unique(); + options_.MCJMM = + LLVMCreateSimpleMCJITMemoryManager(&codeInfo_, RoundTripAllocateCodeSection, + RoundTripAllocateDataSection, RoundTripFinalizeMemory, RoundTripDestroy); +} + +bool LLVMAssembler::BuildMCJITEngine() +{ + LOG_ECMA(INFO) << " BuildMCJITEngine - "; + LLVMBool ret = LLVMCreateMCJITCompilerForModule(&engine_, module_, &options_, sizeof(options_), &error_); + if (ret) { + LOG_ECMA(ERROR) << "error_ : " << error_; + return false; + } + LOG_ECMA(INFO) << " BuildMCJITEngine + "; + return true; +} + +void LLVMAssembler::BuildAndRunPasses() const +{ + LOG_ECMA(INFO) << "BuildAndRunPasses - "; + LLVMPassManagerRef pm = LLVMCreatePassManager(); + LLVMAddConstantPropagationPass(pm); + LLVMAddInstructionCombiningPass(pm); + llvm::unwrap(pm)->add(llvm::createRewriteStatepointsForGCLegacyPass()); +#ifndef NDEBUG + char *info = LLVMPrintModuleToString(module_); + LOG_ECMA(INFO) << "Current Module: " << info; + LLVMDumpModule(module_); + LLVMDisposeMessage(info); +#endif + LLVMRunPassManager(pm, module_); + LLVMDisposePassManager(pm); + LOG_ECMA(INFO) << "BuildAndRunPasses + "; +} + +LLVMAssembler::LLVMAssembler(LLVMModuleRef module, const char* triple): module_(module), engine_(nullptr), + hostTriple_(triple), error_(nullptr) +{ + Initialize(); +} + +LLVMAssembler::~LLVMAssembler() +{ + module_ = nullptr; + if (engine_ != nullptr) { + LLVMDisposeExecutionEngine(engine_); + } + hostTriple_ = ""; + error_ = nullptr; +} + +void LLVMAssembler::Run() +{ + char *error = nullptr; + LLVMVerifyModule(module_, LLVMAbortProcessAction, &error); + LLVMDisposeMessage(error); + UseRoundTripSectionMemoryManager(); + if (!BuildMCJITEngine()) { + return; + } + BuildAndRunPasses(); +} - auto codeSize = assembler_.GetCodeSize(); +void LLVMAssembler::Initialize() +{ + if (hostTriple_.compare(AMD64_TRIPLE) == 0) { + LLVMInitializeX86TargetInfo(); + LLVMInitializeX86TargetMC(); + LLVMInitializeX86Disassembler(); + /* this method must be called, ohterwise "Target does not support MC emission" */ + LLVMInitializeX86AsmPrinter(); + LLVMInitializeX86AsmParser(); + LLVMInitializeX86Target(); + } else if (hostTriple_.compare(ARM64_TRIPLE) == 0) { + LLVMInitializeAArch64TargetInfo(); + LLVMInitializeAArch64TargetMC(); + LLVMInitializeAArch64Disassembler(); + LLVMInitializeAArch64AsmPrinter(); + LLVMInitializeAArch64AsmParser(); + LLVMInitializeAArch64Target(); + } else if (hostTriple_.compare(ARM32_TRIPLE) == 0) { + LLVMInitializeARMTargetInfo(); + LLVMInitializeARMTargetMC(); + LLVMInitializeARMDisassembler(); + LLVMInitializeARMAsmPrinter(); + LLVMInitializeARMAsmParser(); + LLVMInitializeARMTarget(); + } else { + UNREACHABLE(); + } + llvm::linkAllBuiltinGCs(); + LLVMInitializeMCJITCompilerOptions(&options_, sizeof(options_)); + options_.OptLevel = 2; // opt level 2 + // Just ensure that this field still exists. + options_.NoFramePointerElim = true; +} - MachineCode *code = reinterpret_cast(new char(sizeof(MachineCode) + codeSize)); - code->SetInstructionSizeInBytes(nullptr, JSTaggedValue(codeSize), SKIP_BARRIER); - code->SetData(reinterpret_cast(codeBuff), codeSize); - module->SetCode(code); +static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_unused]] uint64_t referenceValue, + uint64_t *referenceType, [[maybe_unused]]uint64_t referencePC, + [[maybe_unused]] const char **referenceName) +{ + *referenceType = LLVMDisassembler_ReferenceType_InOut_None; + return nullptr; +} + +void LLVMAssembler::Disassemble(std::map addr2name) const +{ + LLVMDisasmContextRef dcr = LLVMCreateDisasm(hostTriple_.c_str(), nullptr, 0, nullptr, SymbolLookupCallback); + std::cout << "========================================================================" << std::endl; + for (auto it : codeInfo_.GetCodeInfo()) { + uint8_t *byteSp; + uintptr_t numBytes; + byteSp = it.first; + numBytes = it.second; + std::cout << " byteSp:" << std::hex << reinterpret_cast(byteSp) << " numBytes:0x" << numBytes + << std::endl; + + unsigned pc = 0; + const char outStringSize = 100; + char outString[outStringSize]; + while (numBytes != 0) { + size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize); + if (InstSize == 0) { + fprintf(stderr, "%08x: %08x maybe constant\n", pc, *reinterpret_cast(byteSp)); + pc += 4; // 4 pc length + byteSp += 4; // 4 sp offset + numBytes -= 4; // 4 num bytes + } + uint64_t addr = reinterpret_cast(byteSp); + if (addr2name.find(addr) != addr2name.end()) { + std::cout << addr2name[addr].c_str() << ":" << std::endl; + } + (void)fprintf(stderr, "%08x: %08x %s\n", pc, *reinterpret_cast(byteSp), outString); + pc += InstSize; + byteSp += InstSize; + numBytes -= InstSize; + } + } + std::cout << "========================================================================" << std::endl; + LLVMDisasmDispose(dcr); } } // namespace kungfu diff --git a/ecmascript/compiler/llvm_codegen.h b/ecmascript/compiler/llvm_codegen.h index f55463005b7d77852781413f352afa22d68b9784..a4f1b8979d370c8805455199ab2a41e41ac3dc5d 100644 --- a/ecmascript/compiler/llvm_codegen.h +++ b/ecmascript/compiler/llvm_codegen.h @@ -16,16 +16,180 @@ #ifndef ECMASCRIPT_COMPILER_LLVM_CODEGEN_H #define ECMASCRIPT_COMPILER_LLVM_CODEGEN_H +#include +#include +#include +#include +#include + #include "code_generator.h" #include "ecmascript/compiler/llvm_ir_builder.h" -#include "ecmascript/compiler/llvm_mcjit_engine.h" +#include "ecmascript/ecma_macros.h" #include "ecmascript/js_thread.h" #include "ecmascript/stub_module.h" #include "llvm-c/Types.h" +#include "llvm-c/Analysis.h" +#include "llvm-c/Core.h" +#include "llvm-c/ExecutionEngine.h" +#include "llvm-c/Target.h" +#include "llvm-c/Transforms/PassManagerBuilder.h" +#include "llvm-c/Transforms/Scalar.h" #include "llvm/IR/Instructions.h" #include "llvm/Support/Host.h" +#include "llvm/ExecutionEngine/Interpreter.h" +#include "llvm/ExecutionEngine/MCJIT.h" +#include "llvm/ExecutionEngine/SectionMemoryManager.h" namespace kungfu { +struct CodeInfo { + using ByteBuffer = std::vector; + using BufferList = std::list; + using StringList = std::list; + CodeInfo() : machineCode_(nullptr), codeBufferPos_(0), stackMapsSection_(nullptr) + { + Reset(); + static constexpr int prot = PROT_READ | PROT_WRITE | PROT_EXEC; // NOLINT(hicpp-signed-bitwise) + static constexpr int flags = MAP_ANONYMOUS | MAP_SHARED; // NOLINT(hicpp-signed-bitwise) + machineCode_ = static_cast(mmap(nullptr, MAX_MACHINE_CODE_SIZE, prot, flags, -1, 0)); + } + ~CodeInfo() + { + Reset(); + munmap(machineCode_, MAX_MACHINE_CODE_SIZE); + machineCode_ = nullptr; + } + uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName) + { + uint8_t *addr = nullptr; + if (codeBufferPos_ + size > MAX_MACHINE_CODE_SIZE) { + LOG_ECMA(INFO) << std::hex << "AllocaCodeSection failed alloc codeBufferPos_:" << codeBufferPos_ + << " size:" << size << " larger MAX_MACHINE_CODE_SIZE:" << MAX_MACHINE_CODE_SIZE; + return nullptr; + } + LOG_ECMA(INFO) << "AllocaCodeSection size:" << size; + std::vector codeBuffer(machineCode_[codeBufferPos_], size); + LOG_ECMA(INFO) << " codeBuffer size: " << codeBuffer.size(); + codeSectionNames_.push_back(sectionName); + addr = machineCode_ + codeBufferPos_; + LOG_ECMA(INFO) << "AllocaCodeSection addr:" << std::hex << reinterpret_cast(addr); + codeInfo_.push_back({addr, size}); + codeBufferPos_ += size; + return addr; + } + + uint8_t *AllocaDataSection(uintptr_t size, const char *sectionName) + { + uint8_t *addr = nullptr; + dataSectionList_.push_back(std::vector()); + dataSectionList_.back().resize(size); + dataSectionNames_.push_back(sectionName); + addr = static_cast(dataSectionList_.back().data()); + if (!strcmp(sectionName, ".llvm_stackmaps")) { + LOG_ECMA(INFO) << "llvm_stackmaps : " << addr << " size:" << size << std::endl; + stackMapsSection_ = addr; + stackMapsSize_ = size; + } + return addr; + } + + void Reset() + { + stackMapsSection_ = nullptr; + codeInfo_.clear(); + dataSectionList_.clear(); + dataSectionNames_.clear(); + codeSectionNames_.clear(); + codeBufferPos_ = 0; + } + + uint8_t *GetStackMapsSection() const + { + return stackMapsSection_; + } + int GetStackMapsSize() const + { + return stackMapsSize_; + } + std::vector> GetCodeInfo() const + { + return codeInfo_; + } + + int GetCodeSize() const + { + return codeBufferPos_; + } + + uint8_t *GetCodeBuff() const + { + return machineCode_; + } + +private: + BufferList dataSectionList_ {}; + StringList dataSectionNames_ {}; + StringList codeSectionNames_ {}; + uint8_t *machineCode_; + const size_t MAX_MACHINE_CODE_SIZE = (1 << 20); // 1M + int codeBufferPos_ = 0; + /* for asssembler */ + std::vector> codeInfo_ {}; + /* stack map */ + uint8_t *stackMapsSection_ {nullptr}; + int stackMapsSize_ = 0; +}; + +class LLVMAssembler { +public: + explicit LLVMAssembler(LLVMModuleRef module, const char* triple); + virtual ~LLVMAssembler(); + void Run(); + const LLVMExecutionEngineRef &GetEngine() + { + return engine_; + } + void Disassemble(std::map addr2name = std::map()) const; + uint8_t *GetStackMapsSection() const + { + return codeInfo_.GetStackMapsSection(); + } + int GetStackMapsSize() const + { + return codeInfo_.GetStackMapsSize(); + } + + int GetCodeSize() const + { + return codeInfo_.GetCodeSize(); + } + uint8_t *GetCodeBuffer() const + { + return codeInfo_.GetCodeBuff(); + } + + void *GetFuncPtrFromCompiledModule(LLVMValueRef function) + { + return LLVMGetPointerToGlobal(engine_, function); + } + const char *AMD64_TRIPLE = "x86_64-unknown-linux-gnu"; + const char *ARM64_TRIPLE = "aarch64-unknown-linux-gnu"; + const char *ARM32_TRIPLE = "arm-unknown-linux-gnu"; +private: + void UseRoundTripSectionMemoryManager(); + bool BuildMCJITEngine(); + void BuildAndRunPasses() const; + void BuildSimpleFunction(); + void Initialize(); + void InitMember(); + + LLVMMCJITCompilerOptions options_; + LLVMModuleRef module_; + LLVMExecutionEngineRef engine_; + std::string hostTriple_; + char *error_; + struct CodeInfo codeInfo_; +}; + class LLVMCodeGeneratorImpl : public CodeGeneratorImpl { public: explicit LLVMCodeGeneratorImpl(LLVMStubModule *module) : module_(module) {} @@ -38,13 +202,25 @@ private: class LLVMModuleAssembler { public: - explicit LLVMModuleAssembler(LLVMStubModule *module) : stubmodule_(module), assembler_(module->GetModule()) {} + explicit LLVMModuleAssembler(LLVMStubModule *module, const char* triple) + : stubmodule_(module), assembler_(module->GetModule(), triple) {} void AssembleModule(); - void CopyAssembleCodeToModule(panda::ecmascript::StubModule *module); - + void AssembleStubModule(panda::ecmascript::StubModule *module); + int GetCodeSize() const + { + return assembler_.GetCodeSize(); + } + int GetStackMapsSize() const + { + return assembler_.GetStackMapsSize(); + } + void CopyAssemblerToCode(panda::ecmascript::MachineCode *code) + { + code->SetData(reinterpret_cast(assembler_.GetCodeBuffer()), assembler_.GetCodeSize()); + } private: LLVMStubModule *stubmodule_; LLVMAssembler assembler_; }; } // namespace kungfu -#endif // ECMASCRIPT_COMPILER_LLVM_CODEGEN_H \ No newline at end of file +#endif // ECMASCRIPT_COMPILER_LLVM_CODEGEN_H diff --git a/ecmascript/compiler/llvm_ir_builder.cpp b/ecmascript/compiler/llvm_ir_builder.cpp index 388aed1e90bc7dc1f42f16bcf19e5c5b46ed1fb0..d8756c04833a40a80c52ca7b413c01e145c9606c 100644 --- a/ecmascript/compiler/llvm_ir_builder.cpp +++ b/ecmascript/compiler/llvm_ir_builder.cpp @@ -14,9 +14,8 @@ */ #include "ecmascript/compiler/llvm_ir_builder.h" - +#include #include - #include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/fast_stub.h" #include "ecmascript/compiler/gate.h" @@ -25,48 +24,30 @@ #include "ecmascript/js_thread.h" #include "llvm/IR/Instructions.h" #include "llvm/Support/Host.h" -#include "llvm_mcjit_engine.h" #include "securec.h" #include "utils/logger.h" namespace kungfu { std::unordered_map g_values = {}; -LLVMIRBuilder::LLVMIRBuilder(const std::vector> *schedule, const Circuit *circuit) - : schedule_(schedule), circuit_(circuit) -{ - module_ = LLVMModuleCreateWithName("simple_module"); - LLVMSetTarget(module_, "x86_64-unknown-linux-gnu"); - builder_ = LLVMCreateBuilder(); - context_ = LLVMGetGlobalContext(); - LLVMTypeRef paramTys[] = { - LLVMInt32Type(), - }; - function_ = LLVMAddFunction(module_, "foo", LLVMFunctionType(LLVMInt32Type(), paramTys, 1, 0)); - bbIdMapBb_.clear(); -} - -LLVMIRBuilder::LLVMIRBuilder(const std::vector> *schedule, const Circuit *circuit, - LLVMModuleRef module, LLVMValueRef function) - : schedule_(schedule), circuit_(circuit), module_(module), function_(function) -{ - LLVMSetTarget(module_, "x86_64-unknown-linux-gnu"); - builder_ = LLVMCreateBuilder(); - context_ = LLVMGetGlobalContext(); - bbIdMapBb_.clear(); -} - LLVMIRBuilder::LLVMIRBuilder(const std::vector> *schedule, const Circuit *circuit, LLVMStubModule *module, LLVMValueRef function) : schedule_(schedule), circuit_(circuit), module_(module->GetModule()), function_(function), stubModule_(module) { - LLVMSetTarget(module_, "x86_64-unknown-linux-gnu"); builder_ = LLVMCreateBuilder(); context_ = LLVMGetGlobalContext(); + LLVMSetGC(function_, "statepoint-example"); bbIdMapBb_.clear(); } +LLVMIRBuilder::~LLVMIRBuilder() +{ + if (builder_ != nullptr) { + LLVMDisposeBuilder(builder_); + } +} + int LLVMIRBuilder::FindBasicBlock(AddrShift gate) const { for (size_t bbIdx = 0; bbIdx < schedule_->size(); bbIdx++) { @@ -80,6 +61,104 @@ int LLVMIRBuilder::FindBasicBlock(AddrShift gate) const return -1; } +void LLVMIRBuilder::AssignHandleMap() +{ + opCodeHandleMap_ = {{OpCode::STATE_ENTRY, &LLVMIRBuilder::HandleGoto}, + {OpCode::RETURN, &LLVMIRBuilder::HandleReturn}, + {OpCode::IF_BRANCH, &LLVMIRBuilder::HandleBranch}, {OpCode::SWITCH_BRANCH, &LLVMIRBuilder::HandleSwitch}, + {OpCode::ORDINARY_BLOCK, &LLVMIRBuilder::HandleGoto}, {OpCode::IF_TRUE, &LLVMIRBuilder::HandleGoto}, + {OpCode::IF_FALSE, &LLVMIRBuilder::HandleGoto}, {OpCode::SWITCH_CASE, &LLVMIRBuilder::HandleGoto}, + {OpCode::MERGE, &LLVMIRBuilder::HandleGoto}, {OpCode::DEFAULT_CASE, &LLVMIRBuilder::HandleGoto}, + {OpCode::LOOP_BEGIN, &LLVMIRBuilder::HandleGoto}, {OpCode::LOOP_BACK, &LLVMIRBuilder::HandleGoto}, + {OpCode::VALUE_SELECTOR_INT1, &LLVMIRBuilder::HandlePhi}, + {OpCode::VALUE_SELECTOR_INT32, &LLVMIRBuilder::HandlePhi}, + {OpCode::VALUE_SELECTOR_INT64, &LLVMIRBuilder::HandlePhi}, + {OpCode::VALUE_SELECTOR_FLOAT64, &LLVMIRBuilder::HandlePhi}, + {OpCode::CALL, &LLVMIRBuilder::HandleCall}, {OpCode::INT1_CALL, &LLVMIRBuilder::HandleCall}, + {OpCode::INT32_CALL, &LLVMIRBuilder::HandleCall}, {OpCode::FLOAT64_CALL, &LLVMIRBuilder::HandleCall}, + {OpCode::INT64_CALL, &LLVMIRBuilder::HandleCall}, {OpCode::ALLOCA, &LLVMIRBuilder::HandleAlloca}, + {OpCode::INT1_ARG, &LLVMIRBuilder::HandleParameter}, {OpCode::INT32_ARG, &LLVMIRBuilder::HandleParameter}, + {OpCode::INT64_ARG, &LLVMIRBuilder::HandleParameter}, + {OpCode::INT32_CONSTANT, &LLVMIRBuilder::HandleInt32Constant}, + {OpCode::JS_CONSTANT, &LLVMIRBuilder::HandleInt64Constant}, + {OpCode::INT64_CONSTANT, &LLVMIRBuilder::HandleInt64Constant}, + {OpCode::FLOAT64_CONSTANT, &LLVMIRBuilder::HandleFloat64Constant}, + {OpCode::ZEXT_INT1_TO_INT32, &LLVMIRBuilder::HandleZExtInt}, + {OpCode::ZEXT_INT8_TO_INT32, &LLVMIRBuilder::HandleZExtInt}, + {OpCode::ZEXT_INT16_TO_INT32, &LLVMIRBuilder::HandleZExtInt}, + {OpCode::ZEXT_INT32_TO_INT64, &LLVMIRBuilder::HandleZExtInt}, + {OpCode::ZEXT_INT1_TO_INT64, &LLVMIRBuilder::HandleZExtInt}, + {OpCode::SEXT_INT1_TO_INT32, &LLVMIRBuilder::HandleSExtInt}, + {OpCode::SEXT_INT1_TO_INT64, &LLVMIRBuilder::HandleSExtInt}, + {OpCode::SEXT_INT32_TO_INT64, &LLVMIRBuilder::HandleSExtInt}, + {OpCode::TRUNC_INT64_TO_INT1, &LLVMIRBuilder::HandleCastIntXToIntY}, + {OpCode::TRUNC_INT32_TO_INT1, &LLVMIRBuilder::HandleCastIntXToIntY}, + {OpCode::TRUNC_INT64_TO_INT32, &LLVMIRBuilder::HandleCastIntXToIntY}, + {OpCode::INT32_REV, &LLVMIRBuilder::HandleIntRev}, + {OpCode::INT64_REV, &LLVMIRBuilder::HandleIntRev}, + {OpCode::INT32_ADD, &LLVMIRBuilder::HandleIntAdd}, + {OpCode::INT64_ADD, &LLVMIRBuilder::HandleIntAdd}, + {OpCode::FLOAT64_ADD, &LLVMIRBuilder::HandleFloatAdd}, + {OpCode::FLOAT64_SUB, &LLVMIRBuilder::HandleFloatSub}, + {OpCode::FLOAT64_MUL, &LLVMIRBuilder::HandleFloatMul}, + {OpCode::FLOAT64_DIV, &LLVMIRBuilder::HandleFloatDiv}, + {OpCode::INT32_SUB, &LLVMIRBuilder::HandleIntSub}, + {OpCode::INT64_SUB, &LLVMIRBuilder::HandleIntSub}, + {OpCode::INT32_MUL, &LLVMIRBuilder::HandleIntMul}, + {OpCode::INT64_MUL, &LLVMIRBuilder::HandleIntMul}, + {OpCode::INT32_AND, &LLVMIRBuilder::HandleIntAnd}, + {OpCode::INT64_AND, &LLVMIRBuilder::HandleIntAnd}, + {OpCode::INT32_OR, &LLVMIRBuilder::HandleIntOr}, + {OpCode::INT64_OR, &LLVMIRBuilder::HandleIntOr}, + {OpCode::INT64_XOR, &LLVMIRBuilder::HandleIntXor}, + {OpCode::INT32_LSR, &LLVMIRBuilder::HandleIntLsr}, + {OpCode::INT64_LSR, &LLVMIRBuilder::HandleIntLsr}, + {OpCode::INT32_SLT, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT64_SLT, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT32_ULT, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT64_ULT, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT32_SLE, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT64_SLE, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT32_SGT, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT64_SGT, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT32_SGE, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT64_SGE, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT32_EQ, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT64_EQ, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::FLOAT64_EQ, &LLVMIRBuilder::HandleFloatOrDoubleCmp}, + {OpCode::INT32_NE, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT64_NE, &LLVMIRBuilder::HandleIntOrUintCmp}, + {OpCode::INT8_LOAD, &LLVMIRBuilder::HandleLoad}, + {OpCode::INT16_LOAD, &LLVMIRBuilder::HandleLoad}, + {OpCode::INT32_LOAD, &LLVMIRBuilder::HandleLoad}, + {OpCode::INT64_LOAD, &LLVMIRBuilder::HandleLoad}, + {OpCode::INT32_STORE, &LLVMIRBuilder::HandleStore}, + {OpCode::INT64_STORE, &LLVMIRBuilder::HandleStore}, + {OpCode::INT32_TO_FLOAT64, &LLVMIRBuilder::HandleChangeInt32ToDouble}, + {OpCode::FLOAT64_TO_INT32, &LLVMIRBuilder::HandleChangeDoubleToInt32}, + {OpCode::BITCAST_INT64_TO_FLOAT64, &LLVMIRBuilder::HandleCastInt64ToDouble}, + {OpCode::BITCAST_FLOAT64_TO_INT64, &LLVMIRBuilder::HandleCastDoubleToInt}, + {OpCode::INT32_LSL, &LLVMIRBuilder::HandleIntLsl}, + {OpCode::INT64_LSL, &LLVMIRBuilder::HandleIntLsl}, + {OpCode::FLOAT64_SMOD, &LLVMIRBuilder::HandleFloatMod}, + {OpCode::INT32_SMOD, &LLVMIRBuilder::HandleIntMod}, + {OpCode::TAGGED_POINTER_CALL, &LLVMIRBuilder::HandleCall}, + + }; + opCodeHandleIgnore= {OpCode::NOP, OpCode::CIRCUIT_ROOT, OpCode::DEPEND_ENTRY, + OpCode::FRAMESTATE_ENTRY, OpCode::RETURN_LIST, OpCode::THROW_LIST, + OpCode::CONSTANT_LIST, OpCode::ARG_LIST, OpCode::THROW, + OpCode::DEPEND_SELECTOR, OpCode::DEPEND_RELAY, OpCode::DEPEND_AND}; +} + +std::string LLVMIRBuilder::LLVMValueToString(LLVMValueRef val) const +{ + char* msg = LLVMPrintValueToString(val); + std::string str(msg); + LLVMDisposeMessage(msg); + return str; +} + void LLVMIRBuilder::Build() { LOG_ECMA(INFO) << "LLVM IR Builder Create Id Map of Blocks..."; @@ -89,8 +168,8 @@ void LLVMIRBuilder::Build() instIdMapBbId_[gateId] = bbIdx; } } - LOG_ECMA(INFO) << "LLVM IR Builder Visit Gate..."; + AssignHandleMap(); for (size_t bbIdx = 0; bbIdx < (*schedule_).size(); bbIdx++) { OperandsVector predecessors; for (auto in : circuit_->GetInVector((*schedule_)[bbIdx][0])) { @@ -105,310 +184,16 @@ void LLVMIRBuilder::Build() AddrShift gate = (*schedule_)[bbIdx][instIdx - 1]; std::vector ins = circuit_->GetInVector(gate); std::vector outs = circuit_->GetOutVector(gate); - switch (circuit_->GetOpCode(gate)) { - case OpCode::NOP: - break; - case OpCode::CIRCUIT_ROOT: - break; - case OpCode::STATE_ENTRY: { - int block = instIdMapBbId_[circuit_->GetId(gate)]; - int bbOut = instIdMapBbId_[circuit_->GetId(outs[0])]; - VisitGoto(block, bbOut); - break; - } - case OpCode::DEPEND_ENTRY: - break; - case OpCode::FRAMESTATE_ENTRY: - break; - case OpCode::RETURN_LIST: - break; - case OpCode::THROW_LIST: - break; - case OpCode::CONSTANT_LIST: - break; - case OpCode::ARG_LIST: - break; - case OpCode::RETURN: { - // [STATE] [DEPEND] [VALUE] [RETURN_LIST] - VisitReturn(gate, 1, ins); - break; - } - case OpCode::THROW: - break; - case OpCode::IF_BRANCH: { - AddrShift bTrue = (circuit_->GetOpCode(outs[0]) == OpCode::IF_TRUE) ? outs[0] : outs[1]; - AddrShift bFalse = (circuit_->GetOpCode(outs[0]) == OpCode::IF_FALSE) ? outs[0] : outs[1]; - int bbTrue = instIdMapBbId_[circuit_->GetId(bTrue)]; - int bbFalse = instIdMapBbId_[circuit_->GetId(bFalse)]; - VisitBranch(gate, ins[1], bbTrue, bbFalse); - break; - } - case OpCode::SWITCH_BRANCH: { - VisitSwitch(gate, ins[1], outs); - break; - } - case OpCode::ORDINARY_BLOCK: - case OpCode::IF_TRUE: - case OpCode::IF_FALSE: - case OpCode::SWITCH_CASE: - case OpCode::DEFAULT_CASE: { - int block = instIdMapBbId_[circuit_->GetId(gate)]; - int bbOut = instIdMapBbId_[circuit_->GetId(outs[0])]; - VisitGoto(block, bbOut); - break; - } - case OpCode::MERGE: { - int block = instIdMapBbId_[circuit_->GetId(gate)]; - int bbOut; - for (int i = 0; i < static_cast(outs.size()); i++) { - bbOut = instIdMapBbId_[circuit_->GetId(outs[i])]; - VisitGoto(block, bbOut); - } - break; - } - case OpCode::LOOP_BEGIN: { - int block = instIdMapBbId_[circuit_->GetId(gate)]; - int bbOut; - for (int i = 0; i < static_cast(outs.size()); i++) { - bbOut = instIdMapBbId_[circuit_->GetId(outs[i])]; - VisitGoto(block, bbOut); - } - break; - } - case OpCode::LOOP_BACK: { - int block = instIdMapBbId_[circuit_->GetId(gate)]; - int bbOut = instIdMapBbId_[circuit_->GetId(outs[0])]; - VisitGoto(block, bbOut); - break; - } - case OpCode::VALUE_SELECTOR_INT1: { - VisitPhi(gate, ins, MachineRep::K_BIT); - break; - } - case OpCode::VALUE_SELECTOR_INT32: { - VisitPhi(gate, ins, MachineRep::K_WORD32); - break; - } - case OpCode::VALUE_SELECTOR_INT64: { - VisitPhi(gate, ins, MachineRep::K_WORD64); - break; - } - case OpCode::VALUE_SELECTOR_FLOAT64: { - VisitPhi(gate, ins, MachineRep::K_FLOAT64); - break; - } - case OpCode::DEPEND_SELECTOR: - break; - case OpCode::DEPEND_RELAY: - break; - case OpCode::CALL: - case OpCode::INT1_CALL: - case OpCode::INT32_CALL: - case OpCode::INT64_CALL: { - VisitCall(gate, ins); - break; - } - case OpCode::ALLOCA: { - VisitAlloca(gate); - break; - } - case OpCode::INT1_ARG: // no break, fall through - case OpCode::INT32_ARG: // no break, fall through - case OpCode::INT64_ARG: { - VisitParameter(gate); - break; - } - case OpCode::INT32_CONSTANT: { - int32_t value = circuit_->GetBitField(gate); - VisitInt32Constant(gate, value); - break; - } - case OpCode::JS_CONSTANT: // no break, fall through - case OpCode::INT64_CONSTANT: { - int64_t value = circuit_->GetBitField(gate); - VisitInt64Constant(gate, value); - break; - } - case OpCode::FLOAT64_CONSTANT: { - int64_t value = circuit_->GetBitField(gate); - double doubleValue = bit_cast(value); // actual double value - VisitFloat64Constant(gate, doubleValue); - break; - } - case OpCode::ZEXT_INT1_TO_INT32: { - VisitZExtInt(gate, ins[0], MachineRep::K_WORD32); - break; - } - case OpCode::ZEXT_INT32_TO_INT64: // no break, fall through - case OpCode::ZEXT_INT1_TO_INT64: { - VisitZExtInt(gate, ins[0], MachineRep::K_WORD64); - break; - } - case OpCode::SEXT_INT1_TO_INT32: { - VisitSExtInt(gate, ins[0], MachineRep::K_WORD32); - break; - } - case OpCode::SEXT_INT1_TO_INT64: // no break, fall through - case OpCode::SEXT_INT32_TO_INT64: { - VisitSExtInt(gate, ins[0], MachineRep::K_WORD64); - break; - } - case OpCode::TRUNC_INT64_TO_INT1: - case OpCode::TRUNC_INT32_TO_INT1: { - VisitCastIntXToIntY(gate, ins[0], MachineRep::K_BIT); - break; - } - case OpCode::TRUNC_INT64_TO_INT32: { - VisitCastIntXToIntY(gate, ins[0], MachineRep::K_WORD32); - break; - } - case OpCode::INT32_REV: // no break, fall through - case OpCode::INT64_REV: { - VisitIntRev(gate, ins[0]); - break; - } - case OpCode::INT32_ADD: { - VisitIntAdd(gate, ins[0], ins[1], MachineRep::K_WORD32); - break; - } - case OpCode::INT64_ADD: { - VisitIntAdd(gate, ins[0], ins[1], MachineRep::K_WORD64); - break; - } - case OpCode::FLOAT64_ADD: { - VisitFloatAdd(gate, ins[0], ins[1]); - break; - } - case OpCode::FLOAT64_SUB: { - VisitFloatSub(gate, ins[0], ins[1]); - break; - } - case OpCode::FLOAT64_MUL: { - VisitFloatMul(gate, ins[0], ins[1]); - break; - } - case OpCode::FLOAT64_DIV: { - VisitFloatDiv(gate, ins[0], ins[1]); - break; - } - case OpCode::INT32_SUB: // no break, fall through - case OpCode::INT64_SUB: { - VisitIntSub(gate, ins[0], ins[1]); - break; - } - case OpCode::INT32_MUL: // no break, fall through - case OpCode::INT64_MUL: { - VisitIntMul(gate, ins[0], ins[1]); - break; - } - case OpCode::INT32_AND: // no break, fall through - case OpCode::INT64_AND: { - VisitIntAnd(gate, ins[0], ins[1]); - break; - } - case OpCode::INT32_OR: // no break, fall through - case OpCode::INT64_OR: { - VisitIntOr(gate, ins[0], ins[1]); - break; - } - case OpCode::INT64_XOR: { - VisitIntXor(gate, ins[0], ins[1]); - break; - } - case OpCode::INT32_LSR: // no break, fall through - case OpCode::INT64_LSR: { - VisitIntLsr(gate, ins[0], ins[1]); - break; - } - case OpCode::INT32_LSL: // no break, fall through - case OpCode::INT64_LSL: { - VisitIntLsl(gate, ins[0], ins[1]); - break; - } - case OpCode::INT32_SLT: // no break, fall through - case OpCode::INT64_SLT: { - VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSLT); - break; - } - case OpCode::INT32_ULT: // no break, fall through - case OpCode::INT64_ULT: { - VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntULT); - break; - } - case OpCode::INT32_SLE: // no break, fall through - case OpCode::INT64_SLE: { - VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSLE); - break; - } - case OpCode::INT32_SGT: // no break, fall through - case OpCode::INT64_SGT: { - VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSGT); - break; - } - case OpCode::INT32_SGE: // no break, fall through - case OpCode::INT64_SGE: { - VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSGE); - break; - } - case OpCode::INT32_EQ: // no break, fall through - case OpCode::INT64_EQ: { - VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntEQ); - break; - } - case OpCode::FLOAT64_EQ: { - VisitFloatOrDoubleCmp(gate, ins[0], ins[1], LLVMRealOEQ); - break; - } - case OpCode::INT32_NE: // no break, fall through - case OpCode::INT64_NE: { - VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntNE); - break; - } - case OpCode::INT32_LOAD: { - AddrShift base = ins[1]; - VisitLoad(gate, MachineRep::K_WORD32, base); - break; - } - case OpCode::INT64_LOAD: { - AddrShift base = ins[1]; - VisitLoad(gate, MachineRep::K_WORD64, base); - break; - } - case OpCode::INT32_STORE: { - VisitStore(gate, MachineRep::K_WORD32, ins[2], ins[1]); // 2:baseAddr gate, 1:data gate - break; - } - case OpCode::INT64_STORE: { - VisitStore(gate, MachineRep::K_WORD64, ins[2], ins[1]); // 2:baseAddr gate, 1:data gate - break; - } - case OpCode::INT32_TO_FLOAT64: { - VisitCastInt32ToDouble(gate, ins[0]); - break; - } - case OpCode::INT64_TO_FLOAT64: { - VisitCastInt64ToDouble(gate, ins[0]); - break; - } - case OpCode::FLOAT64_TO_INT64: { - VisitCastDoubleToInt(gate, ins[0]); - break; - } - case OpCode::DEPEND_AND: - break; - case OpCode::INT32_SMOD: { - VisitIntMod(gate, ins[0], ins[1]); - break; - } - case OpCode::FLOAT64_SMOD: { - VisitFloatMod(gate, ins[0], ins[1]); - break; - } - default: { - LOG_ECMA(ERROR) << "The gate below need to be translated "; - circuit_->Print(gate); - UNREACHABLE(); - } + circuit_->Print(gate); + auto found = opCodeHandleMap_.find(circuit_->GetOpCode(gate)); + if (found != opCodeHandleMap_.end()) { + (this->*(found->second))(gate); + continue; + } + if (opCodeHandleIgnore.find(circuit_->GetOpCode(gate)) == opCodeHandleIgnore.end()) { + LOG_ECMA(ERROR) << "The gate below need to be translated "; + circuit_->Print(gate); + UNREACHABLE(); } } } @@ -507,7 +292,7 @@ void LLVMIRBuilder::PrologueHandle(LLVMModuleRef &module, LLVMBuilderRef &builde return; } - LLVMValueRef baseAddr = LLVMCallingFp(module_, builder_); + LLVMValueRef llvmFpAddr = LLVMCallingFp(module_, builder_); /* current frame 0 pre rbp <-- rbp -8 type @@ -521,7 +306,8 @@ void LLVMIRBuilder::PrologueHandle(LLVMModuleRef &module, LLVMBuilderRef &builde LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, rtbaseoffset, LLVMPointerType(LLVMInt64Type(), 0), ""); LLVMValueRef threadFpValue = LLVMBuildLoad(builder_, rtbaseAddr, ""); - LLVMValueRef value = LLVMBuildStore(builder_, threadFpValue, baseAddr); + LLVMValueRef value = LLVMBuildStore(builder_, threadFpValue, + LLVMBuildIntToPtr(builder_, llvmFpAddr, LLVMPointerType(LLVMInt64Type(), 0), "cast")); LOG_ECMA(INFO) << "store value:" << value << " " << "value type" << LLVMTypeOf(value); } @@ -553,6 +339,7 @@ LLVMBasicBlockRef LLVMIRBuilder::EnsureLLVMBB(BasicBlock *bb) const if (impl->llvm_bb_) { return impl->llvm_bb_; } + std::string buf = "B" + std::to_string(bb->GetId()); LLVMBasicBlockRef llvmBB = LLVMAppendBasicBlock(function_, buf.c_str()); impl->llvm_bb_ = llvmBB; @@ -572,6 +359,9 @@ LLVMTypeRef LLVMIRBuilder::GetMachineRepType(MachineRep rep) const case MachineRep::K_WORD8: dstType = LLVMInt8TypeInContext(context_); break; + case MachineRep::K_WORD16: + dstType = LLVMInt16TypeInContext(context_); + break; case MachineRep::K_WORD32: dstType = LLVMInt32TypeInContext(context_); break; @@ -585,38 +375,58 @@ LLVMTypeRef LLVMIRBuilder::GetMachineRepType(MachineRep rep) const return dstType; } +void LLVMIRBuilder::HandleCall(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::CALL: + case OpCode::INT1_CALL: + case OpCode::INT32_CALL: + case OpCode::FLOAT64_CALL: + case OpCode::INT64_CALL: { + VisitCall(gate, ins); + break; + } + default: { + break; + } + } +} + void LLVMIRBuilder::VisitCall(AddrShift gate, const std::vector &inList) { int paraStartIndex = 2; int index = circuit_->GetBitField(inList[1]); ASSERT(stubModule_ != nullptr); LLVMValueRef callee; + LLVMValueRef rtoffset; StubDescriptor *callee_descriptor = FastStubDescriptors::GetInstance().GetStubDescriptor(index); + LLVMTypeRef rtfuncType = stubModule_->GetStubFunctionType(index); + LLVMTypeRef rtfuncTypePtr = LLVMPointerType(rtfuncType, 0); + LLVMValueRef thread = g_values[inList[2]]; // 2 : 2 means skip two input gates (target thread) // runtime case if (callee_descriptor->GetStubKind() == StubDescriptor::CallStubKind::RUNTIME_STUB) { - LLVMTypeRef rtfuncType = stubModule_->GetExternalFunctionType(index); - LLVMTypeRef rtfuncTypePtr = LLVMPointerType(rtfuncType, 0); - LLVMValueRef thread = g_values[inList[2]]; // 2 : 2 means skip two input gates (target thread ) - LLVMValueRef rtoffset = LLVMConstInt(LLVMInt64Type(), - panda::ecmascript::JSThread::GetRuntimeFunctionsOffset() + - (index - FAST_STUB_MAXCOUNT) * sizeof(uintptr_t), - 0); - LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, thread, rtoffset, ""); - LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, rtbaseoffset, LLVMPointerType(LLVMInt64Type(), 0), ""); - LLVMValueRef llvmAddr = LLVMBuildLoad(builder_, rtbaseAddr, ""); - callee = LLVMBuildIntToPtr(builder_, llvmAddr, rtfuncTypePtr, "cast"); - paraStartIndex += 1; + rtoffset = LLVMConstInt(LLVMInt64Type(), + panda::ecmascript::JSThread::GetRuntimeFunctionsOffset() + + (index - FAST_STUB_MAXCOUNT) * sizeof(uintptr_t), 0); } else { - callee = stubModule_->GetStubFunction(index); + rtoffset = LLVMConstInt(LLVMInt64Type(), + panda::ecmascript::JSThread::GetFastStubEntryOffset() + + (index) * sizeof(uintptr_t), 0); } + LLVMValueRef rtbaseoffset = LLVMBuildAdd(builder_, thread, rtoffset, ""); + LLVMValueRef rtbaseAddr = LLVMBuildIntToPtr(builder_, rtbaseoffset, LLVMPointerType(LLVMInt64Type(), 0), ""); + LLVMValueRef llvmAddr = LLVMBuildLoad(builder_, rtbaseAddr, ""); + callee = LLVMBuildIntToPtr(builder_, llvmAddr, rtfuncTypePtr, "cast"); + paraStartIndex += 1; // 16 : params limit LLVMValueRef params[16]; for (size_t paraIdx = paraStartIndex; paraIdx < inList.size(); ++paraIdx) { AddrShift gateTmp = inList[paraIdx]; params[paraIdx - paraStartIndex] = g_values[gateTmp]; circuit_->Print(gateTmp); - LOG_ECMA(INFO) << "arg" << paraIdx - paraStartIndex << ": " - << LLVMPrintValueToString(params[paraIdx - paraStartIndex]); + LOG_ECMA(INFO) << "arg" << paraIdx - paraStartIndex << ": " << + LLVMValueToString(params[paraIdx - paraStartIndex]); } if (callee == nullptr) { LOG_ECMA(ERROR) << "callee nullptr"; @@ -626,6 +436,11 @@ void LLVMIRBuilder::VisitCall(AddrShift gate, const std::vector &inLi return; } +void LLVMIRBuilder::HandleAlloca(AddrShift gate) +{ + return VisitAlloca(gate); +} + void LLVMIRBuilder::VisitAlloca(AddrShift gate) { uint64_t sizeEnum = circuit_->GetBitField(gate); @@ -636,6 +451,32 @@ void LLVMIRBuilder::VisitAlloca(AddrShift gate) return; } +void LLVMIRBuilder::HandlePhi(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::VALUE_SELECTOR_INT1: { + VisitPhi(gate, ins, MachineRep::K_BIT); + break; + } + case OpCode::VALUE_SELECTOR_INT32: { + VisitPhi(gate, ins, MachineRep::K_WORD32); + break; + } + case OpCode::VALUE_SELECTOR_INT64: { + VisitPhi(gate, ins, MachineRep::K_WORD64); + break; + } + case OpCode::VALUE_SELECTOR_FLOAT64: { + VisitPhi(gate, ins, MachineRep::K_FLOAT64); + break; + } + default: { + break; + } + } +} + void LLVMIRBuilder::VisitPhi(AddrShift gate, const std::vector &srcGates, MachineRep rep) { LLVMTypeRef type = GetMachineRepType(rep); @@ -690,10 +531,16 @@ void LLVMIRBuilder::VisitReturn(AddrShift gate, AddrShift popCount, const std::v LOG_ECMA(INFO) << " gate: " << gate << " popCount: " << popCount; LOG_ECMA(INFO) << " return: " << operand << " gateId: " << circuit_->GetId(operand); LLVMValueRef returnValue = g_values[operand]; - LOG_ECMA(INFO) << LLVMPrintValueToString(returnValue); + LOG_ECMA(INFO) << LLVMValueToString(returnValue); LLVMBuildRet(builder_, returnValue); } +void LLVMIRBuilder::HandleReturn(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitReturn(gate, 1, ins); +} + void LLVMIRBuilder::VisitBlock(int gate, const OperandsVector &predecessors) // NOLINTNEXTLINE(misc-unused-parameters) { LOG_ECMA(INFO) << " BBIdx:" << gate; @@ -721,6 +568,27 @@ void LLVMIRBuilder::VisitBlock(int gate, const OperandsVector &predecessors) // } } +void LLVMIRBuilder::HandleGoto(AddrShift gate) +{ + std::vector outs = circuit_->GetOutVector(gate); + int block = instIdMapBbId_[circuit_->GetId(gate)]; + int bbOut = instIdMapBbId_[circuit_->GetId(outs[0])]; + switch (circuit_->GetOpCode(gate)) { + case OpCode::MERGE: + case OpCode::LOOP_BEGIN: { + for (int i = 0; i < static_cast(outs.size()); i++) { + bbOut = instIdMapBbId_[circuit_->GetId(outs[i])]; + VisitGoto(block, bbOut); + } + break; + } + default: { + VisitGoto(block, bbOut); + break; + } + } +} + void LLVMIRBuilder::VisitGoto(int block, int bbOut) { if (block == bbOut) { @@ -737,37 +605,92 @@ void LLVMIRBuilder::VisitGoto(int block, int bbOut) EndCurrentBlock(); } +void LLVMIRBuilder::HandleInt32Constant(AddrShift gate) +{ + int32_t value = circuit_->GetBitField(gate); + VisitInt32Constant(gate, value); +} + +void LLVMIRBuilder::HandleInt64Constant(AddrShift gate) +{ + int64_t value = circuit_->GetBitField(gate); + VisitInt64Constant(gate, value); +} + +void LLVMIRBuilder::HandleFloat64Constant(AddrShift gate) +{ + int64_t value = circuit_->GetBitField(gate); + double doubleValue = bit_cast(value); // actual double value + VisitFloat64Constant(gate, doubleValue); +} + +void LLVMIRBuilder::HandleZExtInt(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::ZEXT_INT8_TO_INT32: // no break, fall through + case OpCode::ZEXT_INT16_TO_INT32: + case OpCode::ZEXT_INT1_TO_INT32: { + VisitZExtInt(gate, ins[0], MachineRep::K_WORD32); + break; + } + case OpCode::ZEXT_INT32_TO_INT64: // no break, fall through + case OpCode::ZEXT_INT1_TO_INT64: { + VisitZExtInt(gate, ins[0], MachineRep::K_WORD64); + break; + } + default: { + break; + } + } +} + +void LLVMIRBuilder::HandleSExtInt(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::SEXT_INT1_TO_INT32: { + VisitSExtInt(gate, ins[0], MachineRep::K_WORD32); + break; + } + case OpCode::SEXT_INT1_TO_INT64: // no break, fall through + case OpCode::SEXT_INT32_TO_INT64: { + VisitSExtInt(gate, ins[0], MachineRep::K_WORD64); + break; + } + default: { + break; + } + } +} + void LLVMIRBuilder::VisitInt32Constant(AddrShift gate, int32_t value) const { LLVMValueRef llvmValue = LLVMConstInt(LLVMInt32Type(), value, 0); - LLVMTFBuilderBasicBlockImpl *impl = currentBb_->GetImpl(); - impl->values_[gate] = llvmValue; g_values[gate] = llvmValue; - char *str = LLVMPrintValueToString(llvmValue); LOG_ECMA(INFO) << "VisitInt32Constant set gate:" << gate << " value:" << value; - LOG_ECMA(INFO) << "VisitInt32Constant " << str; + LOG_ECMA(INFO) << "VisitInt32Constant " << LLVMValueToString(llvmValue); } void LLVMIRBuilder::VisitInt64Constant(AddrShift gate, int64_t value) const { LLVMValueRef llvmValue = LLVMConstInt(LLVMInt64Type(), value, 0); - LLVMTFBuilderBasicBlockImpl *impl = currentBb_->GetImpl(); - impl->values_[gate] = llvmValue; g_values[gate] = llvmValue; - char *str = LLVMPrintValueToString(llvmValue); LOG_ECMA(INFO) << "VisitInt64Constant set gate:" << gate << " value:" << value; - LOG_ECMA(INFO) << "VisitInt64Constant " << str; + LOG_ECMA(INFO) << "VisitInt64Constant " << LLVMValueToString(llvmValue); } void LLVMIRBuilder::VisitFloat64Constant(AddrShift gate, double value) const { LLVMValueRef llvmValue = LLVMConstReal(LLVMDoubleType(), value); - LLVMTFBuilderBasicBlockImpl *impl = currentBb_->GetImpl(); - impl->values_[gate] = llvmValue; g_values[gate] = llvmValue; - char *str = LLVMPrintValueToString(llvmValue); LOG_ECMA(INFO) << "VisitFloat64Constant set gate:" << gate << " value:" << value; - LOG_ECMA(INFO) << "VisitFloat64Constant " << str; + LOG_ECMA(INFO) << "VisitFloat64Constant " << LLVMValueToString(llvmValue); +} + +void LLVMIRBuilder::HandleParameter(AddrShift gate) +{ + return VisitParameter(gate); } void LLVMIRBuilder::VisitParameter(AddrShift gate) const @@ -775,8 +698,6 @@ void LLVMIRBuilder::VisitParameter(AddrShift gate) const int argth = circuit_->LoadGatePtrConst(gate)->GetBitField(); LOG_ECMA(INFO) << " Parameter value" << argth; LLVMValueRef value = LLVMGetParam(function_, argth); - LLVMTFBuilderBasicBlockImpl *impl = currentBb_->GetImpl(); - impl->values_[gate] = value; g_values[gate] = value; LOG_ECMA(INFO) << "VisitParameter set gate:" << gate << " value:" << value; // NOTE: caller put args, otherwise crash @@ -784,15 +705,60 @@ void LLVMIRBuilder::VisitParameter(AddrShift gate) const LOG_ECMA(ERROR) << "generate LLVM IR for para: " << argth << "fail"; return; } - char *str = LLVMPrintValueToString(value); - LOG_ECMA(INFO) << "para arg:" << argth << "value IR:" << str; + LOG_ECMA(INFO) << "para arg:" << argth << "value IR:" << LLVMValueToString(value); +} + +void LLVMIRBuilder::HandleBranch(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + AddrShift bTrue = (circuit_->GetOpCode(outs[0]) == OpCode::IF_TRUE) ? outs[0] : outs[1]; + AddrShift bFalse = (circuit_->GetOpCode(outs[0]) == OpCode::IF_FALSE) ? outs[0] : outs[1]; + int bbTrue = instIdMapBbId_[circuit_->GetId(bTrue)]; + int bbFalse = instIdMapBbId_[circuit_->GetId(bFalse)]; + VisitBranch(gate, ins[1], bbTrue, bbFalse); +} + +void LLVMIRBuilder::HandleIntMod(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitIntMod(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::VisitIntMod(AddrShift gate, AddrShift e1, AddrShift e2) const +{ + LOG_ECMA(INFO) << "int mod gate:" << gate; + LLVMValueRef e1Value = g_values[e1]; + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); + LLVMValueRef e2Value = g_values[e2]; + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); + LLVMValueRef result = LLVMBuildSRem(builder_, e1Value, e2Value, ""); + g_values[gate] = result; + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleFloatMod(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitFloatMod(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::VisitFloatMod(AddrShift gate, AddrShift e1, AddrShift e2) const +{ + LOG_ECMA(INFO) << "float mod gate:" << gate; + LLVMValueRef e1Value = g_values[e1]; + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); + LLVMValueRef e2Value = g_values[e2]; + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); + LLVMValueRef result = LLVMBuildFRem(builder_, e1Value, e2Value, ""); + g_values[gate] = result; + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitBranch(AddrShift gate, AddrShift cmp, int btrue, int bfalse) { LOG_ECMA(INFO) << "cmp gate:" << cmp; - LLVMTFBuilderBasicBlockImpl *impl = EnsureLLVMBBImpl(currentBb_); - if ((impl->values_.count(cmp) == 0) && (g_values.count(cmp) == 0)) { + if (g_values.count(cmp) == 0) { LOG_ECMA(ERROR) << "Branch condition gate is nullptr!"; return; } @@ -810,6 +776,13 @@ void LLVMIRBuilder::VisitBranch(AddrShift gate, AddrShift cmp, int btrue, int bf g_values[gate] = result; } +void LLVMIRBuilder::HandleSwitch(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitSwitch(gate, ins[1], outs); +} + void LLVMIRBuilder::VisitSwitch(AddrShift gate, AddrShift input, const std::vector &outList) { LLVMValueRef cond = g_values[input]; @@ -869,273 +842,503 @@ void LLVMIRBuilder::VisitIntOrUintCmp(AddrShift gate, AddrShift e1, AddrShift e2 { LOG_ECMA(INFO) << "cmp gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildICmp(builder_, opcode, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitFloatOrDoubleCmp(AddrShift gate, AddrShift e1, AddrShift e2, LLVMRealPredicate opcode) const { LOG_ECMA(INFO) << "cmp gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildFCmp(builder_, opcode, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleIntRev(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitIntRev(gate, ins[0]); } void LLVMIRBuilder::VisitIntRev(AddrShift gate, AddrShift e1) const { LOG_ECMA(INFO) << "int sign invert gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); - LLVMValueRef result = LLVMBuildNeg(builder_, e1Value, ""); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); + LLVMValueRef result = LLVMBuildNot(builder_, e1Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleIntAdd(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::INT32_ADD: { + VisitIntAdd(gate, ins[0], ins[1], MachineRep::K_WORD32); + break; + } + case OpCode::INT64_ADD: { + VisitIntAdd(gate, ins[0], ins[1], MachineRep::K_WORD64); + break; + } + default: { + break; + } + } } void LLVMIRBuilder::VisitIntAdd(AddrShift gate, AddrShift e1, AddrShift e2, MachineRep rep) const { LOG_ECMA(INFO) << "int add gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); if (LLVMGetTypeKind(LLVMTypeOf(e1Value)) == LLVMPointerTypeKind) { // for scenario: pointer + offset e1Value = LLVMBuildPtrToInt(builder_, e1Value, GetMachineRepType(rep), ""); } LLVMValueRef result = LLVMBuildAdd(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleFloatAdd(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitFloatAdd(gate, ins[0], ins[1]); } void LLVMIRBuilder::VisitFloatAdd(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "float add gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildFAdd(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleFloatSub(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitFloatSub(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleFloatMul(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitFloatMul(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleFloatDiv(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitFloatDiv(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleIntSub(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitIntSub(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleIntMul(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitIntMul(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleIntOr(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitIntOr(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleIntXor(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitIntXor(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleIntLsr(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitIntLsr(gate, ins[0], ins[1]); +} + +void LLVMIRBuilder::HandleIntOrUintCmp(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::INT32_SLT: // no break, fall through + case OpCode::INT64_SLT: { + VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSLT); + break; + } + case OpCode::INT32_ULT: // no break, fall through + case OpCode::INT64_ULT: { + VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntULT); + break; + } + case OpCode::INT32_SLE: // no break, fall through + case OpCode::INT64_SLE: { + VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSLE); + break; + } + case OpCode::INT32_SGT: // no break, fall through + case OpCode::INT64_SGT: { + VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSGT); + break; + } + case OpCode::INT32_SGE: // no break, fall through + case OpCode::INT64_SGE: { + VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntSGE); + break; + } + case OpCode::INT32_EQ: // no break, fall through + case OpCode::INT64_EQ: { + VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntEQ); + break; + } + case OpCode::INT32_NE: // no break, fall through + case OpCode::INT64_NE: { + VisitIntOrUintCmp(gate, ins[0], ins[1], LLVMIntNE); + break; + } + default: { + break; + } + } +} + +void LLVMIRBuilder::HandleFloatOrDoubleCmp(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + VisitFloatOrDoubleCmp(gate, ins[0], ins[1], LLVMRealOEQ); +} + +void LLVMIRBuilder::HandleLoad(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::INT8_LOAD: { + AddrShift base = ins[1]; + VisitLoad(gate, MachineRep::K_WORD8, base); + break; + } + case OpCode::INT16_LOAD: { + AddrShift base = ins[1]; + VisitLoad(gate, MachineRep::K_WORD16, base); + break; + } + case OpCode::INT32_LOAD: { + AddrShift base = ins[1]; + VisitLoad(gate, MachineRep::K_WORD32, base); + break; + } + case OpCode::INT64_LOAD: { + AddrShift base = ins[1]; + VisitLoad(gate, MachineRep::K_WORD64, base); + break; + } + default: { + break; + } + } +} + +void LLVMIRBuilder::HandleStore(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + std::vector outs = circuit_->GetOutVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::INT32_STORE: { + VisitStore(gate, MachineRep::K_WORD32, ins[2], ins[1]); // 2:baseAddr gate, 1:data gate + break; + } + case OpCode::INT64_STORE: { + VisitStore(gate, MachineRep::K_WORD64, ins[2], ins[1]); // 2:baseAddr gate, 1:data gate + break; + } + default: { + break; + } + } +} + +void LLVMIRBuilder::HandleChangeInt32ToDouble(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitChangeInt32ToDouble(gate, ins[0]); +} + +void LLVMIRBuilder::HandleChangeDoubleToInt32(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitChangeDoubleToInt32(gate, ins[0]); } void LLVMIRBuilder::VisitFloatSub(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "float sub gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildFSub(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitFloatMul(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "float mul gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildFMul(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitFloatDiv(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "float div gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildFDiv(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitIntSub(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "int sub gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildSub(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitIntMul(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "int mul gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildMul(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); -} - -void LLVMIRBuilder::VisitIntMod(AddrShift gate, AddrShift e1, AddrShift e2) const -{ - LOG_ECMA(INFO) << "int mod gate:" << gate; - LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); - LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); - LLVMValueRef result = LLVMBuildSRem(builder_, e1Value, e2Value, ""); - g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); -} - -void LLVMIRBuilder::VisitFloatMod(AddrShift gate, AddrShift e1, AddrShift e2) const -{ - LOG_ECMA(INFO) << "float mod gate:" << gate; - LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); - LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); - LLVMValueRef result = LLVMBuildFRem(builder_, e1Value, e2Value, ""); - g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitIntOr(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "int or gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildOr(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleIntAnd(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitIntAnd(gate, ins[0], ins[1]); } void LLVMIRBuilder::VisitIntAnd(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "int and gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildAnd(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitIntXor(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "int xor gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildXor(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitIntLsr(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "int lsr gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildLShr(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleIntLsl(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitIntLsl(gate, ins[0], ins[1]); } void LLVMIRBuilder::VisitIntLsl(AddrShift gate, AddrShift e1, AddrShift e2) const { LOG_ECMA(INFO) << "int lsl gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef e2Value = g_values[e2]; - LOG_ECMA(INFO) << "operand 1: " << LLVMPrintValueToString(e2Value); + LOG_ECMA(INFO) << "operand 1: " << LLVMValueToString(e2Value); LLVMValueRef result = LLVMBuildShl(builder_, e1Value, e2Value, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitZExtInt(AddrShift gate, AddrShift e1, MachineRep rep) const { LOG_ECMA(INFO) << "int zero extension gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef result = LLVMBuildZExt(builder_, e1Value, GetMachineRepType(rep), ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } void LLVMIRBuilder::VisitSExtInt(AddrShift gate, AddrShift e1, MachineRep rep) const { LOG_ECMA(INFO) << "int sign extension gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef result = LLVMBuildSExt(builder_, e1Value, GetMachineRepType(rep), ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleCastIntXToIntY(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + switch (circuit_->GetOpCode(gate)) { + case OpCode::TRUNC_INT64_TO_INT1: + case OpCode::TRUNC_INT32_TO_INT1: { + VisitCastIntXToIntY(gate, ins[0], MachineRep::K_BIT); + break; + } + case OpCode::TRUNC_INT64_TO_INT32: { + VisitCastIntXToIntY(gate, ins[0], MachineRep::K_WORD32); + break; + } + default: { + break; + } + } } void LLVMIRBuilder::VisitCastIntXToIntY(AddrShift gate, AddrShift e1, MachineRep rep) const { LOG_ECMA(INFO) << "int cast2 int gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef result = LLVMBuildIntCast2(builder_, e1Value, GetMachineRepType(rep), 1, ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } -void LLVMIRBuilder::VisitCastInt32ToDouble(AddrShift gate, AddrShift e1) const +void LLVMIRBuilder::VisitChangeInt32ToDouble(AddrShift gate, AddrShift e1) const { LOG_ECMA(INFO) << "int cast2 double gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef result = LLVMBuildSIToFP(builder_, e1Value, LLVMDoubleType(), ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::VisitChangeDoubleToInt32(AddrShift gate, AddrShift e1) const +{ + LOG_ECMA(INFO) << "double cast2 int32 gate:" << gate; + LLVMValueRef e1Value = g_values[e1]; + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); + LLVMValueRef result = LLVMBuildFPToSI(builder_, e1Value, LLVMInt32Type(), ""); + g_values[gate] = result; + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleCastInt64ToDouble(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitCastInt64ToDouble(gate, ins[0]); } void LLVMIRBuilder::VisitCastInt64ToDouble(AddrShift gate, AddrShift e1) const { LOG_ECMA(INFO) << "int cast2 double gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef result = LLVMBuildBitCast(builder_, e1Value, LLVMDoubleType(), ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); +} + +void LLVMIRBuilder::HandleCastDoubleToInt(AddrShift gate) +{ + std::vector ins = circuit_->GetInVector(gate); + VisitCastDoubleToInt(gate, ins[0]); } void LLVMIRBuilder::VisitCastDoubleToInt(AddrShift gate, AddrShift e1) const { LOG_ECMA(INFO) << "double cast2 int gate:" << gate; LLVMValueRef e1Value = g_values[e1]; - LOG_ECMA(INFO) << "operand 0: " << LLVMPrintValueToString(e1Value); + LOG_ECMA(INFO) << "operand 0: " << LLVMValueToString(e1Value); LLVMValueRef result = LLVMBuildBitCast(builder_, e1Value, LLVMInt64Type(), ""); g_values[gate] = result; - LOG_ECMA(INFO) << "result: " << LLVMPrintValueToString(result); + LOG_ECMA(INFO) << "result: " << LLVMValueToString(result); } -LLVMStubModule::LLVMStubModule(const char *name) +LLVMStubModule::LLVMStubModule(const char *name, const char *triple) { - module_ = LLVMModuleCreateWithName("fast_stubs"); -#ifdef PANDA_TARGET_AMD64 - LLVMSetTarget(module_, "x86_64-unknown-linux-gnu"); -#endif + module_ = LLVMModuleCreateWithName(name); + LLVMSetTarget(module_, triple); } void LLVMStubModule::Initialize() @@ -1147,10 +1350,16 @@ void LLVMStubModule::Initialize() stubFunctions_[i] = GetLLVMFunctionByStubDescriptor(stubDescriptor); } } - for (i = 0; i < MAX_EXTERNAL_FUNCTION_COUNT; i++) { - auto externalDescriptor = FastStubDescriptors::GetInstance().GetStubDescriptor(i + EXTERNAL_FUNCTION_OFFSET); - if (!externalDescriptor->GetName().empty()) { - externalFuctionType_[i] = GetLLVMFunctionTypeStubDescriptor(externalDescriptor); + for (i = 0; i < MAX_STUB_FUNCTION_COUNT; i++) { + auto stubDescriptor = FastStubDescriptors::GetInstance().GetStubDescriptor(i); + if (!stubDescriptor->GetName().empty()) { + stubFunctionType_[i] = GetLLVMFunctionTypeStubDescriptor(stubDescriptor); + } + } + for (i = 0; i < MAX_TEST_FUNCTION_COUNT; i++) { + auto testFuncDescriptor = FastStubDescriptors::GetInstance().GetStubDescriptor(i + TEST_FUNCTION_OFFSET); + if (!testFuncDescriptor->GetName().empty()) { + testFunctions_[i] = GetLLVMFunctionByStubDescriptor(testFuncDescriptor); } } } @@ -1177,18 +1386,20 @@ LLVMTypeRef LLVMStubModule::GetLLVMFunctionTypeStubDescriptor(StubDescriptor *st LLVMTypeRef LLVMStubModule::ConvertLLVMTypeFromMachineType(MachineType type) { static std::map machineTypeMap = { - {MachineType::NONE_TYPE, LLVMVoidType()}, - {MachineType::BOOL_TYPE, LLVMInt1Type()}, - {MachineType::INT8_TYPE, LLVMInt8Type()}, - {MachineType::INT16_TYPE, LLVMInt16Type()}, - {MachineType::INT32_TYPE, LLVMInt32Type()}, - {MachineType::INT64_TYPE, LLVMInt64Type()}, - {MachineType::UINT8_TYPE, LLVMInt8Type()}, - {MachineType::UINT16_TYPE, LLVMInt16Type()}, - {MachineType::UINT32_TYPE, LLVMInt32Type()}, - {MachineType::UINT64_TYPE, LLVMInt64Type()}, - {MachineType::FLOAT32_TYPE, LLVMFloatType()}, - {MachineType::FLOAT64_TYPE, LLVMDoubleType()}, + {MachineType::NONE_TYPE, LLVMVoidType()}, + {MachineType::BOOL_TYPE, LLVMInt1Type()}, + {MachineType::INT8_TYPE, LLVMInt8Type()}, + {MachineType::INT16_TYPE, LLVMInt16Type()}, + {MachineType::INT32_TYPE, LLVMInt32Type()}, + {MachineType::INT64_TYPE, LLVMInt64Type()}, + {MachineType::UINT8_TYPE, LLVMInt8Type()}, + {MachineType::UINT16_TYPE, LLVMInt16Type()}, + {MachineType::UINT32_TYPE, LLVMInt32Type()}, + {MachineType::UINT64_TYPE, LLVMInt64Type()}, + {MachineType::FLOAT32_TYPE, LLVMFloatType()}, + {MachineType::FLOAT64_TYPE, LLVMDoubleType()}, + {MachineType::TAGGED_POINTER_TYPE, LLVMPointerType(LLVMInt64Type(), 1)}, + {MachineType::TAGGED_TYPE, LLVMInt64Type()}, }; return machineTypeMap[type]; } diff --git a/ecmascript/compiler/llvm_ir_builder.h b/ecmascript/compiler/llvm_ir_builder.h index cd703fd7e3fac8cbf432c7787c183e803a7fddcb..9191be54b75caa53eff2c42e2e3b64e41831ee01 100644 --- a/ecmascript/compiler/llvm_ir_builder.h +++ b/ecmascript/compiler/llvm_ir_builder.h @@ -31,6 +31,8 @@ namespace kungfu { using OperandsVector = std::set; class BasicBlock; using BasicBlockMap = std::map>; +class LLVMIRBuilder; +typedef void (LLVMIRBuilder::*HandleType)(AddrShift gate); enum class MachineRep { K_NONE, @@ -96,7 +98,6 @@ struct NotMergedPhiDesc { struct LLVMTFBuilderBasicBlockImpl { LLVMBasicBlockRef llvm_bb_ = nullptr; LLVMBasicBlockRef continuation = nullptr; - std::unordered_map values_ = {}; bool started = false; bool ended = false; std::vector not_merged_phis; @@ -104,7 +105,7 @@ struct LLVMTFBuilderBasicBlockImpl { class LLVMStubModule { public: - explicit LLVMStubModule(const char *name); + explicit LLVMStubModule(const char *name, const char *triple); ~LLVMStubModule() = default; void Initialize(); @@ -114,10 +115,10 @@ public: return module_; } - LLVMTypeRef GetExternalFunctionType(uint32_t index) const + LLVMTypeRef GetStubFunctionType(uint32_t index) const { - ASSERT(index - EXTERNAL_FUNCTION_OFFSET < MAX_EXTERNAL_FUNCTION_COUNT); - return externalFuctionType_[index - EXTERNAL_FUNCTION_OFFSET]; + ASSERT(index < MAX_STUB_FUNCTION_COUNT); + return stubFunctionType_[index]; } LLVMValueRef GetStubFunction(uint32_t index) @@ -126,69 +127,83 @@ public: return stubFunctions_[index]; } + LLVMValueRef GetTestFunction(uint32_t index) + { + ASSERT(index - TEST_FUNCTION_OFFSET < MAX_TEST_FUNCTION_COUNT); + return testFunctions_[index - TEST_FUNCTION_OFFSET]; + } + private: LLVMValueRef GetLLVMFunctionByStubDescriptor(StubDescriptor *stubDescriptor); LLVMTypeRef GetLLVMFunctionTypeStubDescriptor(StubDescriptor *stubDescriptor); LLVMTypeRef ConvertLLVMTypeFromMachineType(MachineType type); - static constexpr uint32_t MAX_EXTERNAL_FUNCTION_COUNT = - kungfu::EXTERN_RUNTIME_STUB_MAXCOUNT - kungfu::EXTERNAL_RUNTIME_STUB_BEGIN - 1; - static constexpr uint32_t EXTERNAL_FUNCTION_OFFSET = kungfu::EXTERNAL_RUNTIME_STUB_BEGIN + 1; + static constexpr uint32_t MAX_STUB_FUNCTION_COUNT = kungfu::EXTERN_RUNTIME_STUB_MAXCOUNT; + static constexpr uint32_t MAX_TEST_FUNCTION_COUNT = kungfu::TEST_FUNC_MAXCOUNT - kungfu::TEST_FUNC_BEGIN - 1; + static constexpr uint32_t TEST_FUNCTION_OFFSET = kungfu::TEST_FUNC_BEGIN + 1; std::array stubFunctions_ {nullptr}; - std::array externalFuctionType_ {nullptr}; + std::array stubFunctionType_ {nullptr}; + std::array testFunctions_ {nullptr}; LLVMModuleRef module_; }; +#define OPCODES(V) \ + V(Call, (AddrShift gate, const std::vector &inList)) \ + V(Alloca, (AddrShift gate)) \ + V(Block, (int id, const OperandsVector &predecessors)) \ + V(Goto, (int block, int bbout)) \ + V(Parameter, (AddrShift gate) const ) \ + V(Int32Constant, (AddrShift gate, int32_t value) const ) \ + V(Int64Constant, (AddrShift gate, int64_t value) const ) \ + V(Float64Constant, (AddrShift gate, double value) const ) \ + V(ZExtInt, (AddrShift gate, AddrShift e1, MachineRep rep) const ) \ + V(SExtInt, (AddrShift gate, AddrShift e1, MachineRep rep) const ) \ + V(Load, (AddrShift gate, MachineRep rep, AddrShift base) const ) \ + V(Store, (AddrShift gate, MachineRep rep, AddrShift base, AddrShift value) const ) \ + V(IntRev, (AddrShift gate, AddrShift e1) const ) \ + V(IntAdd, (AddrShift gate, AddrShift e1, AddrShift e2, MachineRep rep) const ) \ + V(FloatAdd, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(FloatSub, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(FloatMul, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(FloatDiv, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(IntSub, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(IntMul, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(IntOr, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(IntAnd, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(IntXor, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(IntLsr, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(Int32LessThanOrEqual, (AddrShift gate, AddrShift e1, AddrShift e2) const ) \ + V(IntOrUintCmp, (AddrShift gate, AddrShift e1, AddrShift e2, LLVMIntPredicate opcode) const ) \ + V(FloatOrDoubleCmp, (AddrShift gate, AddrShift e1, AddrShift e2, LLVMRealPredicate opcode) const ) \ + V(Branch, (AddrShift gate, AddrShift cmp, AddrShift btrue, AddrShift bfalse)) \ + V(Switch, (AddrShift gate, AddrShift input, const std::vector &outList)) \ + V(SwitchCase, (AddrShift gate, AddrShift switchBranch, AddrShift out)) \ + V(Phi, (AddrShift gate, const std::vector &srcGates, MachineRep rep)) \ + V(Return, (AddrShift gate, AddrShift popCount, const std::vector &operands) const ) \ + V(CastIntXToIntY, (AddrShift gate, AddrShift e1, MachineRep rep) const ) \ + V(ChangeInt32ToDouble, (AddrShift gate, AddrShift e1) const ) \ + V(ChangeDoubleToInt32, (AddrShift gate, AddrShift e1) const ) \ + V(CastInt64ToDouble, (AddrShift gate, AddrShift e1) const ) \ + V(CastDoubleToInt, (AddrShift gate, AddrShift e1) const ) \ + V(CastInt64ToPointer, (AddrShift gate, AddrShift e1) const ) \ + V(IntLsl, (AddrShift gate, AddrShift e1, AddrShift e2) const) \ + V(IntMod, (AddrShift gate, AddrShift e1, AddrShift e2) const) \ + V(FloatMod, (AddrShift gate, AddrShift e1, AddrShift e2) const) \ + + class LLVMIRBuilder { public: - explicit LLVMIRBuilder(const std::vector> *schedule, const Circuit *circuit); - explicit LLVMIRBuilder(const std::vector> *schedule, const Circuit *circuit, - LLVMModuleRef module, LLVMValueRef function); explicit LLVMIRBuilder(const std::vector> *schedule, const Circuit *circuit, LLVMStubModule *module, LLVMValueRef function); + ~LLVMIRBuilder(); void Build(); - ~LLVMIRBuilder() = default; private: - void VisitCall(AddrShift gate, const std::vector &inList); - void VisitAlloca(AddrShift gate); - void VisitBlock(int id, const OperandsVector &predecessors); - void VisitGoto(int block, int bbout); - void VisitParameter(AddrShift gate) const; - void VisitInt32Constant(AddrShift gate, int32_t value) const; - void VisitInt64Constant(AddrShift gate, int64_t value) const; - void VisitFloat64Constant(AddrShift gate, double value) const; - void VisitZExtInt(AddrShift gate, AddrShift e1, MachineRep rep) const; - void VisitSExtInt(AddrShift gate, AddrShift e1, MachineRep rep) const; - void VisitLoad(AddrShift gate, MachineRep rep, AddrShift base) const; - void VisitStore(AddrShift gate, MachineRep rep, AddrShift base, AddrShift value) const; - void VisitIntRev(AddrShift gate, AddrShift e1) const; - void VisitIntAdd(AddrShift gate, AddrShift e1, AddrShift e2, MachineRep rep) const; - void VisitFloatAdd(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitFloatSub(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitFloatMul(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitFloatDiv(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntSub(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntMul(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntOr(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntAnd(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntXor(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntLsr(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntLsl(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitInt32LessThanOrEqual(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitIntOrUintCmp(AddrShift gate, AddrShift e1, AddrShift e2, LLVMIntPredicate opcode) const; - void VisitFloatOrDoubleCmp(AddrShift gate, AddrShift e1, AddrShift e2, LLVMRealPredicate opcode) const; - void VisitBranch(AddrShift gate, AddrShift cmp, AddrShift btrue, AddrShift bfalse); - void VisitSwitch(AddrShift gate, AddrShift input, const std::vector &outList); - void VisitSwitchCase(AddrShift gate, AddrShift switchBranch, AddrShift out); - void VisitPhi(AddrShift gate, const std::vector &srcGates, MachineRep rep); - void VisitReturn(AddrShift gate, AddrShift popCount, const std::vector &operands) const; - void VisitCastIntXToIntY(AddrShift gate, AddrShift e1, MachineRep rep) const; - void VisitCastInt32ToDouble(AddrShift gate, AddrShift e1) const; - void VisitCastInt64ToDouble(AddrShift gate, AddrShift e1) const; - void VisitCastDoubleToInt(AddrShift gate, AddrShift e1) const; - void VisitCastInt64ToPointer(AddrShift gate, AddrShift e1) const; - void VisitIntMod(AddrShift gate, AddrShift e1, AddrShift e2) const; - void VisitFloatMod(AddrShift gate, AddrShift e1, AddrShift e2) const; + #define DECLAREVISITOPCODE(name, signature) void Visit##name signature; + OPCODES(DECLAREVISITOPCODE) + #undef DECLAREVISITOPCODE + #define DECLAREHANDLEOPCODE(name, ignore) void Handle##name(AddrShift gate); + OPCODES(DECLAREHANDLEOPCODE) + #undef DECLAREHANDLEOPCODE BasicBlock *EnsurBasicBlock(int id); LLVMValueRef LLVMCallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder); @@ -203,6 +218,8 @@ private: void End(); void ProcessPhiWorkList(); + void AssignHandleMap(); + std::string LLVMValueToString(LLVMValueRef val) const; private: const std::vector> *schedule_ {nullptr}; @@ -219,6 +236,8 @@ private: std::vector phiRebuildWorklist_; LLVMStubModule *stubModule_ {nullptr}; + std::unordered_map opCodeHandleMap_; + std::set opCodeHandleIgnore; }; } // namespace kungfu #endif // PANDA_RUNTIME_ECMASCRIPT_COMPILER_LLVM_IR_BUILDER_H \ No newline at end of file diff --git a/ecmascript/compiler/llvm_mcjit_engine.cpp b/ecmascript/compiler/llvm_mcjit_engine.cpp deleted file mode 100644 index 7d00ed89f9e68ec0bd859ed11517ce2cb32d88ea..0000000000000000000000000000000000000000 --- a/ecmascript/compiler/llvm_mcjit_engine.cpp +++ /dev/null @@ -1,210 +0,0 @@ -/* - * Copyright (c) 2021 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 "llvm_mcjit_engine.h" - -#include - -#include "ecmascript/ecma_macros.h" -#include "llvm/ADT/APInt.h" -#include "llvm/CodeGen/BuiltinGCs.h" -#include "llvm/ExecutionEngine/ExecutionEngine.h" -#include "llvm/ExecutionEngine/GenericValue.h" -#include "llvm/IR/Argument.h" -#include "llvm/IR/BasicBlock.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DerivedTypes.h" -#include "llvm/IR/Function.h" -#include "llvm/IR/InstrTypes.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LegacyPassManager.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/IR/Module.h" -#include "llvm/IR/Type.h" -#include "llvm/IR/Verifier.h" -#include "llvm/IRReader/IRReader.h" -#include "llvm/Transforms/Scalar.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/Host.h" -#include "llvm/Support/TargetSelect.h" -#include "llvm-c/Analysis.h" -#include "llvm-c/Core.h" -#include "llvm-c/Disassembler.h" -#include "llvm-c/DisassemblerTypes.h" -#include "llvm-c/Target.h" -#include "llvm-c/Transforms/PassManagerBuilder.h" -#include "llvm-c/Transforms/Scalar.h" - -namespace kungfu { -static uint8_t *RoundTripAllocateCodeSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment, - [[maybe_unused]] unsigned sectionID, const char *sectionName) -{ - std::cout << "RoundTripAllocateCodeSection object " << object << " - " << std::endl; - struct CodeInfo& state = *static_cast(object); - uint8_t *addr = state.AllocaCodeSection(size, sectionName); - std::cout << "RoundTripAllocateCodeSection addr:" << std::hex << reinterpret_cast(addr) << addr - << " size:0x" << size << " +" << std::endl; - return addr; -} - -static uint8_t *RoundTripAllocateDataSection(void *object, uintptr_t size, [[maybe_unused]] unsigned alignment, - [[maybe_unused]] unsigned sectionID, const char *sectionName, - [[maybe_unused]] LLVMBool isReadOnly) -{ - struct CodeInfo& state = *static_cast(object); - return state.AllocaDataSection(size, sectionName); -} - -static LLVMBool RoundTripFinalizeMemory(void *object, [[maybe_unused]] char **errMsg) -{ - std::cout << "RoundTripFinalizeMemory object " << object << " - " << std::endl; - return 0; -} - -static void RoundTripDestroy(void *object) -{ - std::cout << "RoundTripDestroy object " << object << " - " << std::endl; - delete static_cast(object); -} - -void LLVMAssembler::UseRoundTripSectionMemoryManager() -{ - auto sectionMemoryManager = std::make_unique(); - options_.MCJMM = - LLVMCreateSimpleMCJITMemoryManager(&codeInfo_, RoundTripAllocateCodeSection, - RoundTripAllocateDataSection, RoundTripFinalizeMemory, RoundTripDestroy); -} - -bool LLVMAssembler::BuildMCJITEngine() -{ - std::cout << " BuildMCJITEngine - " << std::endl; - LLVMBool ret = LLVMCreateMCJITCompilerForModule(&engine_, module_, &options_, sizeof(options_), &error_); - std::cout << " engine_ " << engine_ << std::endl; - if (ret) { - std::cout << "error_ : " << error_ << std::endl; - return false; - } - std::cout << " BuildMCJITEngine ++++++++++++ " << std::endl; - return true; -} - -void LLVMAssembler::BuildAndRunPasses() const -{ - std::cout << "BuildAndRunPasses - " << std::endl; - LLVMPassManagerRef pass = LLVMCreatePassManager(); - LLVMAddConstantPropagationPass(pass); - LLVMAddInstructionCombiningPass(pass); - llvm::unwrap(pass)->add(llvm::createRewriteStatepointsForGCLegacyPass()); - LOG_ECMA(INFO) << "Current Module: " << LLVMPrintModuleToString(module_); - LLVMRunPassManager(pass, module_); - LLVMDisposePassManager(pass); - std::cout << "BuildAndRunPasses + " << std::endl; -} - -LLVMAssembler::LLVMAssembler(LLVMModuleRef module): module_(module), engine_(nullptr), - hostTriple_(""), error_(nullptr) -{ - Initialize(); - InitMember(); -} - -LLVMAssembler::~LLVMAssembler() -{ - module_ = nullptr; - engine_ = nullptr; - hostTriple_ = ""; - error_ = nullptr; -} - -void LLVMAssembler::Run() -{ - UseRoundTripSectionMemoryManager(); - if (!BuildMCJITEngine()) { - return; - } - BuildAndRunPasses(); -} - -void LLVMAssembler::Initialize() -{ -#if defined(PANDA_TARGET_AMD64) - LLVMInitializeX86TargetInfo(); - LLVMInitializeX86TargetMC(); - LLVMInitializeX86Disassembler(); - /* this method must be called, ohterwise "Target does not support MC emission" */ - LLVMInitializeX86AsmPrinter(); - LLVMInitializeX86AsmParser(); - LLVMInitializeX86Target(); -#endif - llvm::linkAllBuiltinGCs(); - LLVMInitializeMCJITCompilerOptions(&options_, sizeof(options_)); - options_.OptLevel = 2; // opt level 2 - // Just ensure that this field still exists. - options_.NoFramePointerElim = true; -} - -static const char *SymbolLookupCallback([[maybe_unused]] void *disInfo, [[maybe_unused]] uint64_t referenceValue, - uint64_t *referenceType, [[maybe_unused]]uint64_t referencePC, - [[maybe_unused]] const char **referenceName) -{ - *referenceType = LLVMDisassembler_ReferenceType_InOut_None; - return nullptr; -} - -void LLVMAssembler::Disassemble(std::map addr2name) const -{ - LLVMDisasmContextRef dcr = LLVMCreateDisasm("x86_64-unknown-linux-gnu", nullptr, 0, nullptr, SymbolLookupCallback); - std::cout << "========================================================================" << std::endl; - for (auto it : codeInfo_.GetCodeInfo()) { - uint8_t *byteSp; - uintptr_t numBytes; - byteSp = it.first; - numBytes = it.second; - std::cout << " byteSp:" << std::hex << reinterpret_cast(byteSp) << " numBytes:0x" << numBytes - << std::endl; - - unsigned pc = 0; - const char outStringSize = 100; - char outString[outStringSize]; - while (numBytes != 0) { - size_t InstSize = LLVMDisasmInstruction(dcr, byteSp, numBytes, pc, outString, outStringSize); - if (InstSize == 0) { - fprintf(stderr, "%08x: %08x maybe constant\n", pc, *reinterpret_cast(byteSp)); - pc += 4; // 4 pc length - byteSp += 4; // 4 sp offset - numBytes -= 4; // 4 num bytes - } - uint64_t addr = reinterpret_cast(byteSp); - if (addr2name.find(addr) != addr2name.end()) { - std::cout << addr2name[addr].c_str() << ":" << std::endl; - } - (void)fprintf(stderr, "%08x: %08x %s\n", pc, *reinterpret_cast(byteSp), outString); - pc += InstSize; - byteSp += InstSize; - numBytes -= InstSize; - } - } - std::cout << "========================================================================" << std::endl; -} - -void LLVMAssembler::InitMember() -{ - if (module_ == nullptr) { - module_ = LLVMModuleCreateWithName("simple_module"); - LLVMSetTarget(module_, "x86_64-unknown-linux-gnu"); - } -} -} // namespace kungfu diff --git a/ecmascript/compiler/llvm_mcjit_engine.h b/ecmascript/compiler/llvm_mcjit_engine.h deleted file mode 100644 index 3eaafb206b59a784256b55d05f8687304a4e758c..0000000000000000000000000000000000000000 --- a/ecmascript/compiler/llvm_mcjit_engine.h +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (c) 2021 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_LLVM_MCJINT_ENGINE_H -#define ECMASCRIPT_COMPILER_LLVM_MCJINT_ENGINE_H - -#include -#include -#include -#include -#include - -#include "llvm/ExecutionEngine/Interpreter.h" -#include "llvm/ExecutionEngine/MCJIT.h" -#include "llvm/ExecutionEngine/SectionMemoryManager.h" - -#include "llvm-c/Analysis.h" -#include "llvm-c/Core.h" -#include "llvm-c/ExecutionEngine.h" -#include "llvm-c/Target.h" -#include "llvm-c/Transforms/PassManagerBuilder.h" -#include "llvm-c/Transforms/Scalar.h" - -namespace kungfu { -struct CodeInfo { - using ByteBuffer = std::vector; - using BufferList = std::list; - using StringList = std::list; - CodeInfo() : machineCode(nullptr), codeBufferPos(0), stackMapsSection_(nullptr) - { - Reset(); - static constexpr int prot = PROT_READ | PROT_WRITE | PROT_EXEC; // NOLINT(hicpp-signed-bitwise) - static constexpr int flags = MAP_ANONYMOUS | MAP_SHARED; // NOLINT(hicpp-signed-bitwise) - machineCode = static_cast(mmap(nullptr, MAX_MACHINE_CODE_SIZE, prot, flags, -1, 0)); - std::cerr << std::hex << "machineCode : " << reinterpret_cast(machineCode) << std::endl; - } - ~CodeInfo() - { - Reset(); - munmap(machineCode, MAX_MACHINE_CODE_SIZE); - } - uint8_t *AllocaCodeSection(uintptr_t size, const char *sectionName) - { - uint8_t *addr = nullptr; - if (codeBufferPos + size > MAX_MACHINE_CODE_SIZE) { - std::cerr << std::hex << "AllocaCodeSection failed alloc codeBufferPos:" << codeBufferPos - << " size:" << size << " larger MAX_MACHINE_CODE_SIZE:" << MAX_MACHINE_CODE_SIZE << std::endl; - return nullptr; - } - std::cout << "AllocaCodeSection size:" << size << std::endl; - std::vector codeBuffer(machineCode[codeBufferPos], size); - std::cout << " codeBuffer size: " << codeBuffer.size() << std::endl; - codeSectionNames_.push_back(sectionName); - addr = machineCode + codeBufferPos; - std::cout << "AllocaCodeSection addr:" << std::hex << reinterpret_cast(addr) << std::endl; - codeInfo_.push_back({addr, size}); - codeBufferPos += size; - return addr; - } - - uint8_t *AllocaDataSection(uintptr_t size, const char *sectionName) - { - uint8_t *addr = nullptr; - dataSectionList_.push_back(std::vector()); - dataSectionList_.back().resize(size); - dataSectionNames_.push_back(sectionName); - addr = static_cast(dataSectionList_.back().data()); - if (!strcmp(sectionName, ".llvm_stackmaps")) { - std::cout << "llvm_stackmaps : " << addr << std::endl; - stackMapsSection_ = addr; - } - return addr; - } - - void Reset() - { - stackMapsSection_ = nullptr; - codeInfo_.clear(); - dataSectionList_.clear(); - dataSectionNames_.clear(); - codeSectionNames_.clear(); - codeBufferPos = 0; - } - - uint8_t *GetStackMapsSection() const - { - return stackMapsSection_; - } - std::vector> GetCodeInfo() const - { - return codeInfo_; - } - - int GetCodeSize() const - { - return codeBufferPos; - } - - uint8_t *GetCodeBuff() const - { - return machineCode; - } - -private: - BufferList dataSectionList_ {}; - StringList dataSectionNames_ {}; - StringList codeSectionNames_ {}; - uint8_t *machineCode; - const size_t MAX_MACHINE_CODE_SIZE = (1 << 20); // 1M - int codeBufferPos = 0; - /* for asssembler */ - std::vector> codeInfo_ {}; - /* stack map */ - uint8_t *stackMapsSection_ {nullptr}; -}; -class LLVMAssembler { -public: - explicit LLVMAssembler(LLVMModuleRef module); - virtual ~LLVMAssembler(); - void Run(); - const LLVMExecutionEngineRef &GetEngine() - { - return engine_; - } - void Disassemble(std::map addr2name = std::map()) const; - uint8_t *GetStackMapsSection() const - { - return codeInfo_.GetStackMapsSection(); - } - - int GetCodeSize() const - { - return codeInfo_.GetCodeSize(); - } - uint8_t *GetCodeBuffer() const - { - return codeInfo_.GetCodeBuff(); - } - -private: - void UseRoundTripSectionMemoryManager(); - bool BuildMCJITEngine(); - void BuildAndRunPasses() const; - void BuildSimpleFunction(); - void Initialize(); - void InitMember(); - - LLVMMCJITCompilerOptions options_; - LLVMModuleRef module_; - LLVMExecutionEngineRef engine_; - std::string hostTriple_; - char *error_; - struct CodeInfo codeInfo_; -}; -} // namespace kungfu -#endif // ECMASCRIPT_COMPILER_LLVM_MCJINT_ENGINE_H diff --git a/ecmascript/compiler/machine_type.h b/ecmascript/compiler/machine_type.h index 3530cd14dd56c19fae70e3e1ef5147d28c7bd7da..f17f60808da0ea1a4d9d5393e8162113b815844a 100644 --- a/ecmascript/compiler/machine_type.h +++ b/ecmascript/compiler/machine_type.h @@ -17,7 +17,7 @@ #define ECMASCRIPT_COMPILER_MACHINE_TYPE_H namespace kungfu { -enum MachineType { +enum class MachineType { NONE_TYPE, BOOL_TYPE, INT8_TYPE, diff --git a/ecmascript/compiler/options.h.erb b/ecmascript/compiler/options.h.erb new file mode 100644 index 0000000000000000000000000000000000000000..55988ac120897155a28c9fc032aadc13b600b578 --- /dev/null +++ b/ecmascript/compiler/options.h.erb @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2021 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. + */ + +// Autogenerated file -- DO NOT EDIT! + +#ifndef PANDA_<%= Common::module.name.upcase %>_OPTIONS_GEN_H_ +#define PANDA_<%= Common::module.name.upcase %>_OPTIONS_GEN_H_ + +#include "utils/pandargs.h" + +#include +#include +#include +#include + +namespace <%= Common::module.namespace %> { + +class <%= Common::module.name %>_Options { +public: + class Error { + public: + explicit Error(std::string msg) : msg_(std::move(msg)) {} + + std::string GetMessage() { + return msg_; + } + private: + std::string msg_; + }; + + explicit <%= Common::module.name %>_Options(const std::string &exe_path) : exe_dir_(GetExeDir(exe_path)) {} + + void AddOptions(PandArgParser *parser) { +% Common::options.each do |op| + parser->Add(&<%= op.field_name %>); +% end + } + +% Common::options.each do |op| + <%= op.type %> <%= op.getter_name %>() const { + return <%= op.field_name %>.GetValue(); + } + + void <%= op.setter_name %>(<%= op.type %> value) { + <%= op.field_name %>.SetValue(<%= op.type == 'std::string' || op.type == 'arg_list_t' ? 'std::move(value)' : 'value' %>); + } + + bool WasSet<%= op.name.split(Regexp.union(['-','.'])).map(&:capitalize).join %>() const { + return <%= op.field_name %>.WasSet(); + } + +% end +// NOLINTNEXTLINE(readability-function-size) + std::optional Validate() const { +% Common::options.each do |op| +% next unless defined? op.possible_values +% is_string = op.type == 'std::string' || op.type == 'arg_list_t' +% possible_values = op.possible_values.map { |e| is_string ? Common::to_raw(e) : e }.join(', ') + { + std::unordered_set<<%= is_string ? "std::string" : op.type %>> possible_values{<%= possible_values %>}; +% if op.type != 'arg_list_t' + std::vector<<%= op.type %>> values{<%= op.field_name %>.GetValue()}; +% else + const auto &values = <%= op.field_name %>.GetValue(); +% end + for (const auto &value : values) { + if (possible_values.find(value) == possible_values.cend()) { + return Error("argument --<%= op.name %>: invalid value: '" + <%= is_string ? "value" : "std::to_string(value)" %> + \ + R"('. Possible values: <%= op.possible_values %>)"); + } + } + } +% end + return {}; + } + +private: + static std::string GetExeDir(const std::string &exe_path) { + auto pos = exe_path.find_last_of('/'); + return exe_path.substr(0, pos); + } + +% Common::options.each do |op| +% next unless op.need_default_constant + static constexpr <%= op.type %> <%= op.default_constant_name %> = <%= op.default %>; + +% end + std::string exe_dir_; +% Common::options.each do |op| +% if defined? op.delimiter + PandArg<<%= op.type %>> <%= op.field_name %>{"<%= op.name %>", <%= op.default_value %>, <%= op.full_description %>, "<%= op.delimiter %>"}; +% elsif defined? op.range +% min, max = op.range.match('(\d+)\D*(\d+)').captures; +% if op.default.to_i > max.to_i || op.default.to_i < min.to_i +% abort "FAILED: Default value of argument " + op.name + " has out of range default parameter" +% end + PandArg<<%= op.type %>> <%= op.field_name %>{"<%= op.name %>", <%= op.default_value %>, <%= op.full_description %>, <%= min.to_i %>, <%= max.to_i %>}; +% else + PandArg<<%= op.type %>> <%= op.field_name %>{"<%= op.name %>", <%= op.default_value %>, <%= op.full_description %>}; +% end +% end +}; + +} // namespace <%= Common::module.namespace %> + +#endif // PANDA_<%= Common::module.name.upcase %>_OPTIONS_GEN_H_ diff --git a/ecmascript/compiler/stub.cpp b/ecmascript/compiler/stub.cpp index 4f9a0eeb822ae9ebd1864f0031869ce3e2a43b5b..0e9264dafcb8a8f3f651361a680036cd4a278a7d 100644 --- a/ecmascript/compiler/stub.cpp +++ b/ecmascript/compiler/stub.cpp @@ -34,10 +34,11 @@ AddrShift Stub::Variable::AddPhiOperand(AddrShift val) Label label = env_->GetLabelFromSelector(val); size_t idx = 0; for (auto pred : label.GetPredecessors()) { + auto preVal = pred.ReadVariable(this); + ASSERT(!env_->GetCircuit()->GetOpCode(preVal).IsNop()); idx++; - val = AddOperandToSelector(val, idx, pred.ReadVariable(this)); + val = AddOperandToSelector(val, idx, preVal); } - return TryRemoveTrivialPhi(val); } @@ -66,6 +67,7 @@ AddrShift Stub::Variable::TryRemoveTrivialPhi(AddrShift phiVal) // the phi is unreachable or in the start block same = env_->GetCircuit()->LoadGatePtr(env_->GetCircuitBuilder().UndefineConstant()); } + auto same_addr_shift = env_->GetCircuit()->SaveGatePtr(same); // remove the trivial phi // get all users of phi except self @@ -92,10 +94,13 @@ AddrShift Stub::Variable::TryRemoveTrivialPhi(AddrShift phiVal) for (auto out : outs) { if (IsSelector(out->GetGate())) { auto out_addr_shift = env_->GetCircuit()->SaveGatePtr(out->GetGate()); - TryRemoveTrivialPhi(out_addr_shift); + auto result = TryRemoveTrivialPhi(out_addr_shift); + if (same_addr_shift == out_addr_shift) { + same_addr_shift = result; + } } } - return env_->GetCircuit()->SaveGatePtr(same); + return same_addr_shift; } void Stub::Variable::RerouteOuts(const std::vector &outs, Gate *newGate) @@ -123,7 +128,10 @@ void LabelImpl::WriteVariable(Variable *var, AddrShift value) AddrShift LabelImpl::ReadVariable(Variable *var) { if (valueMap_.find(var) != valueMap_.end()) { - return valueMap_.at(var); + auto result = valueMap_.at(var); + if (!env_->GetCircuit()->GetOpCode(result).IsNop()) { + return result; + } } return ReadVariableRecursive(var); } @@ -358,7 +366,7 @@ AddrShift Stub::FixLoadType(AddrShift x) AddrShift Stub::LoadFromObject(MachineType type, AddrShift object, AddrShift offset) { - AddrShift elementsOffset = GetInteger32Constant(panda::ecmascript::JSObject::ELEMENTS_OFFSET); + AddrShift elementsOffset = GetInt32Constant(panda::ecmascript::JSObject::ELEMENTS_OFFSET); if (PtrValueCode() == ValueCode::INT64) { elementsOffset = SExtInt32ToInt64(elementsOffset); } @@ -366,8 +374,8 @@ AddrShift Stub::LoadFromObject(MachineType type, AddrShift object, AddrShift off AddrShift elements = Load(MachineType::UINT64_TYPE, object, elementsOffset); // load index in tagged array AddrShift dataOffset = - Int32Add(GetInteger32Constant(panda::coretypes::Array::GetDataOffset()), - Int32Mul(offset, GetInteger32Constant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()))); + Int32Add(GetInt32Constant(panda::coretypes::Array::GetDataOffset()), + Int32Mul(offset, GetInt32Constant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()))); if (PtrValueCode() == ValueCode::INT64) { dataOffset = SExtInt32ToInt64(dataOffset); } @@ -378,23 +386,23 @@ AddrShift Stub::FindElementFromNumberDictionary(AddrShift thread, AddrShift elem { auto env = GetEnvironment(); Label subentry(env); - [[maybe_unused]] SubCircuitScope subCircuit(env, &subentry); - DEFVARIABLE(result, INT32_TYPE, GetInteger32Constant(-1)); + env->PushCurrentLabel(&subentry); + DEFVARIABLE(result, MachineType::INT32_TYPE, GetInt32Constant(-1)); Label exit(env); AddrShift capcityoffset = PtrMul(GetPtrConstant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()), GetPtrConstant(panda::ecmascript::TaggedHashTable::SIZE_INDEX)); AddrShift dataoffset = GetPtrConstant(panda::coretypes::Array::GetDataOffset()); - AddrShift capacity = TaggedCastToInt32(Load(TAGGED_TYPE, elements, PtrAdd(dataoffset, capcityoffset))); - DEFVARIABLE(count, INT32_TYPE, GetInteger32Constant(1)); + AddrShift capacity = TaggedCastToInt32(Load(MachineType::TAGGED_TYPE, elements, PtrAdd(dataoffset, capcityoffset))); + DEFVARIABLE(count, MachineType::INT32_TYPE, GetInt32Constant(1)); AddrShift pKey = Alloca(static_cast(MachineRep::K_WORD32)); - AddrShift keyStore = Store(INT32_TYPE, pKey, GetPtrConstant(0), TaggedCastToInt32(key)); + AddrShift keyStore = Store(MachineType::INT32_TYPE, pKey, GetPtrConstant(0), TaggedCastToInt32(key)); StubDescriptor *getHash32Descriptor = GET_STUBDESCRIPTOR(GetHash32); - AddrShift len = GetInteger32Constant(sizeof(int) / sizeof(uint8_t)); + AddrShift len = GetInt32Constant(sizeof(int) / sizeof(uint8_t)); AddrShift hash = CallRuntime(getHash32Descriptor, thread, GetWord64Constant(FAST_STUB_ID(GetHash32)), keyStore, {pKey, len}); - DEFVARIABLE(entry, INT32_TYPE, Word32And(hash, Int32Sub(capacity, GetInteger32Constant(1)))); + DEFVARIABLE(entry, MachineType::INT32_TYPE, Word32And(hash, Int32Sub(capacity, GetInt32Constant(1)))); Label loopHead(env); Label loopEnd(env); Label afterLoop(env); @@ -411,7 +419,7 @@ AddrShift Stub::FindElementFromNumberDictionary(AddrShift thread, AddrShift elem Label notUndefined(env); Branch(TaggedIsUndefined(element), &isUndefined, ¬Undefined); Bind(&isUndefined); - result = GetInteger32Constant(-1); + result = GetInt32Constant(-1); Jump(&exit); Bind(¬Undefined); Label isMatch(env); @@ -423,20 +431,22 @@ AddrShift Stub::FindElementFromNumberDictionary(AddrShift thread, AddrShift elem Bind(¬Match); Jump(&loopEnd); Bind(&loopEnd); - entry = Word32And(Int32Add(*entry, *count), Int32Sub(capacity, GetInteger32Constant(1))); - count = Int32Add(*count, GetInteger32Constant(1)); + entry = GetNextPositionForHash(*entry, *count, capacity); + count = Int32Add(*count, GetInt32Constant(1)); LoopEnd(&loopHead); Bind(&exit); - return *result; + auto ret = *result; + env->PopCurrentLabel(); + return ret; } AddrShift Stub::IsMatchInNumberDictionary(AddrShift key, AddrShift other) { auto env = GetEnvironment(); Label entry(env); - [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + env->PushCurrentLabel(&entry); Label exit(env); - DEFVARIABLE(result, BOOL_TYPE, FalseConstant()); + DEFVARIABLE(result, MachineType::BOOL_TYPE, FalseConstant()); Label isHole(env); Label notHole(env); Label isUndefined(env); @@ -464,25 +474,28 @@ AddrShift Stub::IsMatchInNumberDictionary(AddrShift key, AddrShift other) Bind(&keyNotInt); Jump(&exit); Bind(&exit); - return *result; + auto ret = *result; + env->PopCurrentLabel(); + return ret; } AddrShift Stub::GetKeyFromNumberDictionary(AddrShift elements, AddrShift entry) { auto env = GetEnvironment(); Label subentry(env); - [[maybe_unused]] SubCircuitScope subCircuit(env, &subentry); + env->PushCurrentLabel(&subentry); Label exit(env); - DEFVARIABLE(result, TAGGED_TYPE, GetUndefinedConstant()); + DEFVARIABLE(result, MachineType::TAGGED_TYPE, GetUndefinedConstant()); Label ltZero(env); Label notLtZero(env); Label gtLength(env); Label notGtLength(env); - AddrShift dictionaryLength = Load(INT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); + AddrShift dictionaryLength = + Load(MachineType::INT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); AddrShift arrayIndex = - Int32Add(GetInteger32Constant(panda::ecmascript::NumberDictionary::TABLE_HEADER_SIZE), - Int32Mul(entry, GetInteger32Constant(panda::ecmascript::NumberDictionary::ENTRY_SIZE))); - Branch(Int32LessThan(arrayIndex, GetInteger32Constant(0)), <Zero, ¬LtZero); + Int32Add(GetInt32Constant(panda::ecmascript::NumberDictionary::TABLE_HEADER_SIZE), + Int32Mul(entry, GetInt32Constant(panda::ecmascript::NumberDictionary::ENTRY_SIZE))); + Branch(Int32LessThan(arrayIndex, GetInt32Constant(0)), <Zero, ¬LtZero); Bind(<Zero); Jump(&exit); Bind(¬LtZero); @@ -493,7 +506,9 @@ AddrShift Stub::GetKeyFromNumberDictionary(AddrShift elements, AddrShift entry) result = GetValueFromTaggedArray(elements, arrayIndex); Jump(&exit); Bind(&exit); - return *result; + auto ret = *result; + env->PopCurrentLabel(); + return ret; } // int TaggedHashTable::FindEntry(const JSTaggedValue &key) in tagged_hash_table-inl.h @@ -501,16 +516,16 @@ AddrShift Stub::FindEntryFromNameDictionary(AddrShift thread, AddrShift elements { auto env = GetEnvironment(); Label funcEntry(env); - [[maybe_unused]] SubCircuitScope subCircuit(env, &funcEntry); + env->PushCurrentLabel(&funcEntry); Label exit(env); - DEFVARIABLE(result, INT32_TYPE, GetInteger32Constant(-1)); + DEFVARIABLE(result, MachineType::INT32_TYPE, GetInt32Constant(-1)); AddrShift capcityoffset = PtrMul(GetPtrConstant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()), GetPtrConstant(panda::ecmascript::TaggedHashTable::SIZE_INDEX)); AddrShift dataoffset = GetPtrConstant(panda::coretypes::Array::GetDataOffset()); - AddrShift capacity = TaggedCastToInt32(Load(TAGGED_TYPE, elements, PtrAdd(dataoffset, capcityoffset))); - DEFVARIABLE(count, INT32_TYPE, GetInteger32Constant(1)); - DEFVARIABLE(hash, INT32_TYPE, GetInteger32Constant(0)); + AddrShift capacity = TaggedCastToInt32(Load(MachineType::TAGGED_TYPE, elements, PtrAdd(dataoffset, capcityoffset))); + DEFVARIABLE(count, MachineType::INT32_TYPE, GetInt32Constant(1)); + DEFVARIABLE(hash, MachineType::INT32_TYPE, GetInt32Constant(0)); // NameDictionary::hash Label isSymbol(env); Label notSymbol(env); @@ -521,7 +536,8 @@ AddrShift Stub::FindEntryFromNameDictionary(AddrShift thread, AddrShift elements Branch(IsSymbol(key), &isSymbol, ¬Symbol); Bind(&isSymbol); { - hash = TaggedCastToInt32(Load(TAGGED_TYPE, key, GetPtrConstant(panda::ecmascript::JSSymbol::HASHFIELD_OFFSET))); + hash = TaggedCastToInt32(Load(MachineType::TAGGED_TYPE, key, + GetPtrConstant(panda::ecmascript::JSSymbol::HASHFIELD_OFFSET))); Jump(&beforeDefineHash); } Bind(¬Symbol); @@ -542,7 +558,7 @@ AddrShift Stub::FindEntryFromNameDictionary(AddrShift thread, AddrShift elements } Bind(&beforeDefineHash); // GetFirstPosition(hash, size) - DEFVARIABLE(entry, INT32_TYPE, Word32And(*hash, Int32Sub(capacity, GetInteger32Constant(1)))); + DEFVARIABLE(entry, MachineType::INT32_TYPE, Word32And(*hash, Int32Sub(capacity, GetInt32Constant(1)))); Jump(&loopHead); LoopBegin(&loopHead); { @@ -563,7 +579,7 @@ AddrShift Stub::FindEntryFromNameDictionary(AddrShift thread, AddrShift elements { Bind(&isUndefined); { - result = GetInteger32Constant(-1); + result = GetInt32Constant(-1); Jump(&exit); } Bind(¬Undefined); @@ -588,22 +604,24 @@ AddrShift Stub::FindEntryFromNameDictionary(AddrShift thread, AddrShift elements } Bind(&loopEnd); { - entry = Word32And(Int32Add(*entry, *count), Int32Sub(capacity, GetInteger32Constant(1))); - count = Int32Add(*count, GetInteger32Constant(1)); + entry = GetNextPositionForHash(*entry, *count, capacity); + count = Int32Add(*count, GetInt32Constant(1)); LoopEnd(&loopHead); } } Bind(&exit); - return *result; + auto ret = *result; + env->PopCurrentLabel(); + return ret; } AddrShift Stub::JSObjectGetProperty(AddrShift obj, AddrShift hClass, AddrShift attr) { auto env = GetEnvironment(); Label entry(env); - [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + env->PushCurrentLabel(&entry); Label exit(env); - DEFVARIABLE(result, TAGGED_TYPE, GetUndefinedConstant()); + DEFVARIABLE(result, MachineType::TAGGED_TYPE, GetUndefinedConstant()); Label inlinedProp(env); Label notInlinedProp(env); AddrShift attrOffset = PropAttrGetOffset(attr); @@ -616,29 +634,32 @@ AddrShift Stub::JSObjectGetProperty(AddrShift obj, AddrShift hClass, AddrShift a AddrShift propOffset = Int32Sub( ChangeInt64ToInt32(hClassObjectSize), Int32Mul(Int32Sub( - GetInteger32Constant(panda::ecmascript::JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS), attrOffset), - GetInteger32Constant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()))); - result = Int64BuildTagged(Load(UINT64_TYPE, obj, ZExtInt32ToInt64(propOffset))); + GetInt32Constant(panda::ecmascript::JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS), attrOffset), + GetInt32Constant(panda::ecmascript::JSTaggedValue::TaggedTypeSize()))); + result = Load(MachineType::UINT64_TYPE, obj, ZExtInt32ToInt64(propOffset)); Jump(&exit); } Bind(¬InlinedProp); { // compute outOfLineProp offset, get it and return - AddrShift array = Load(UINT64_TYPE, obj, GetPtrConstant(panda::ecmascript::JSObject::PROPERTIES_OFFSET)); + AddrShift array = + Load(MachineType::UINT64_TYPE, obj, GetPtrConstant(panda::ecmascript::JSObject::PROPERTIES_OFFSET)); result = GetValueFromTaggedArray(array, Int32Sub(attrOffset, - GetInteger32Constant(panda::ecmascript::JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS))); + GetInt32Constant(panda::ecmascript::JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS))); Jump(&exit); } } Bind(&exit); - return *result; + auto ret = *result; + env->PopCurrentLabel(); + return ret; } void Stub::ThrowTypeAndReturn(AddrShift thread, int messageId, AddrShift val) { StubDescriptor *throwTypeError = GET_STUBDESCRIPTOR(ThrowTypeError); - AddrShift taggedId = IntBuildTagged(GetInteger32Constant(messageId)); - CallStub(throwTypeError, GetWord64Constant(FAST_STUB_ID(ThrowTypeError)), {thread, taggedId}); + AddrShift msgIntId = GetInt32Constant(messageId); + CallRuntime(throwTypeError, thread, GetWord64Constant(FAST_STUB_ID(ThrowTypeError)), {thread, msgIntId}); Return(val); } @@ -646,9 +667,9 @@ AddrShift Stub::TaggedToRepresentation(AddrShift value) { auto env = GetEnvironment(); Label entry(env); - [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + env->PushCurrentLabel(&entry); Label exit(env); - DEFVARIABLE(resultRep, INT64_TYPE, + DEFVARIABLE(resultRep, MachineType::INT64_TYPE, GetWord64Constant(static_cast(panda::ecmascript::Representation::OBJECT))); Label isInt(env); Label notInt(env); @@ -676,16 +697,18 @@ AddrShift Stub::TaggedToRepresentation(AddrShift value) } } Bind(&exit); - return *resultRep; + auto ret = *resultRep; + env->PopCurrentLabel(); + return ret; } AddrShift Stub::UpdateRepresention(AddrShift oldRep, AddrShift value) { auto env = GetEnvironment(); Label entry(env); - [[maybe_unused]] SubCircuitScope subCircuit(env, &entry); + env->PushCurrentLabel(&entry); Label exit(env); - DEFVARIABLE(resultRep, INT64_TYPE, oldRep); + DEFVARIABLE(resultRep, MachineType::INT64_TYPE, oldRep); Label isMixedRep(env); Label notMiexedRep(env); Branch(Word64Equal(oldRep, GetWord64Constant(static_cast(panda::ecmascript::Representation::MIXED))), @@ -770,12 +793,306 @@ AddrShift Stub::UpdateRepresention(AddrShift oldRep, AddrShift value) } } Bind(&exit); - return *resultRep; + auto ret = *resultRep; + env->PopCurrentLabel(); + return ret; +} + +AddrShift Stub::Store(MachineType type, AddrShift thread, AddrShift base, AddrShift offset, AddrShift value) +{ + auto depend = env_.GetCurrentLabel()->GetDepend(); + AddrShift result; + if (PtrValueCode() == ValueCode::INT64) { + AddrShift ptr = Int64Add(base, offset); + result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); + env_.GetCurrentLabel()->SetDepend(result); + } else if (PtrValueCode() == ValueCode::INT32) { + AddrShift ptr = Int32Add(base, offset); + result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); + env_.GetCurrentLabel()->SetDepend(result); + } else { + UNREACHABLE(); + } + // write barrier will implemented in IR later + if (type == MachineType::TAGGED_POINTER_TYPE || type == MachineType::TAGGED_TYPE) { + StubDescriptor *setValueWithBarrier = GET_STUBDESCRIPTOR(SetValueWithBarrier); + CallRuntime(setValueWithBarrier, thread, GetWord64Constant(FAST_STUB_ID(SetValueWithBarrier)), + {thread, base, offset, value}); + } + + return result; +} + +AddrShift Stub::Store(MachineType type, AddrShift base, AddrShift offset, AddrShift value) +{ + auto depend = env_.GetCurrentLabel()->GetDepend(); + AddrShift result; + if (PtrValueCode() == ValueCode::INT64) { + AddrShift ptr = Int64Add(base, offset); + result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); + env_.GetCurrentLabel()->SetDepend(result); + } else if (PtrValueCode() == ValueCode::INT32) { + AddrShift ptr = Int32Add(base, offset); + result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); + env_.GetCurrentLabel()->SetDepend(result); + } else { + UNREACHABLE(); + } + return result; +} + +AddrShift Stub::TaggedIsString(AddrShift obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->PushCurrentLabel(&entry); + Label exit(env); + DEFVARIABLE(result, MachineType::BOOL_TYPE, FalseConstant()); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); + Bind(&isHeapObject); + { + result = Word32Equal(GetObjectType(LoadHClass(obj)), + GetInt32Constant(static_cast(panda::ecmascript::JSType::STRING))); + Jump(&exit); + } + Bind(&exit); + auto ret = *result; + env->PopCurrentLabel(); + return ret; +} + +AddrShift Stub::TaggedIsStringOrSymbol(AddrShift obj) +{ + auto env = GetEnvironment(); + Label entry(env); + env->PushCurrentLabel(&entry); + Label exit(env); + DEFVARIABLE(result, MachineType::BOOL_TYPE, FalseConstant()); + Label isHeapObject(env); + Branch(TaggedIsHeapObject(obj), &isHeapObject, &exit); + Bind(&isHeapObject); + { + AddrShift objType = GetObjectType(LoadHClass(obj)); + result = Word32Equal(objType, + GetInt32Constant(static_cast(panda::ecmascript::JSType::STRING))); + Label isString(env); + Label notString(env); + Branch(*result, &exit, ¬String); + Bind(¬String); + { + result = Word32Equal(objType, + GetInt32Constant(static_cast(panda::ecmascript::JSType::SYMBOL))); + Jump(&exit); + } + } + Bind(&exit); + auto ret = *result; + env->PopCurrentLabel(); + return ret; +} + +AddrShift Stub::IsUtf16String(AddrShift string) +{ + // compressedStringsEnabled fixed to true constant + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + return Word32Equal( + Word32And(len, GetInt32Constant(panda::ecmascript::EcmaString::STRING_COMPRESSED_BIT)), + GetInt32Constant(panda::ecmascript::EcmaString::STRING_UNCOMPRESSED)); +} + +AddrShift Stub::IsUtf8String(AddrShift string) +{ + // compressedStringsEnabled fixed to true constant + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + return Word32Equal( + Word32And(len, GetInt32Constant(panda::ecmascript::EcmaString::STRING_COMPRESSED_BIT)), + GetInt32Constant(panda::ecmascript::EcmaString::STRING_COMPRESSED)); +} + +AddrShift Stub::IsInternalString(AddrShift string) +{ + // compressedStringsEnabled fixed to true constant + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + return Word32NotEqual( + Word32And(len, GetInt32Constant(panda::ecmascript::EcmaString::STRING_INTERN_BIT)), + GetInt32Constant(0)); +} + +AddrShift Stub::IsDigit(AddrShift ch) +{ + return TruncInt32ToInt1( + Word32And(SExtInt1ToInt32(Int32LessThanOrEqual(ch, GetInt32Constant('9'))), + SExtInt1ToInt32(Int32GreaterThanOrEqual(ch, GetInt32Constant('0'))))); +} + +AddrShift Stub::StringToElementIndex(AddrShift string) +{ + auto env = GetEnvironment(); + Label entry(env); + env->PushCurrentLabel(&entry); + Label exit(env); + DEFVARIABLE(result, MachineType::INT32_TYPE, GetInt32Constant(-1)); + Label greatThanZero(env); + Label inRange(env); + AddrShift len = Load(MachineType::UINT32_TYPE, string, + GetPtrConstant(panda::ecmascript::EcmaString::GetLengthOffset())); + len = Word32LSR(len, GetInt32Constant(2)); // 2 : 2 means len must be right shift 2 bits + Branch(Word32Equal(len, GetInt32Constant(0)), &exit, &greatThanZero); + Bind(&greatThanZero); + Branch(Int32GreaterThan(len, GetInt32Constant(panda::ecmascript::MAX_INDEX_LEN)), &exit, &inRange); + Bind(&inRange); + { + AddrShift dataUtf16 = PtrAdd(string, GetPtrConstant(panda::ecmascript::EcmaString::GetDataOffset())); + DEFVARIABLE(c, MachineType::UINT32_TYPE, GetInt32Constant(0)); + Label isUtf16(env); + Label isUtf8(env); + Label getChar1(env); + AddrShift isUtf16String = IsUtf16String(string); + Branch(isUtf16String, &isUtf16, &isUtf8); + Bind(&isUtf16); + { + c = ZExtInt16ToInt32(Load(MachineType::INT16_TYPE, dataUtf16)); + Jump(&getChar1); + } + Bind(&isUtf8); + { + c = ZExtInt8ToInt32(Load(MachineType::INT8_TYPE, dataUtf16)); + Jump(&getChar1); + } + Bind(&getChar1); + { + Label isDigitZero(env); + Label notDigitZero(env); + Branch(Word32Equal(*c, GetInt32Constant('0')), &isDigitZero, ¬DigitZero); + Bind(&isDigitZero); + { + Label lengthIsOne(env); + Branch(Word32Equal(len, GetInt32Constant(1)), &lengthIsOne, &exit); + Bind(&lengthIsOne); + { + result = GetInt32Constant(0); + Jump(&exit); + } + } + Bind(¬DigitZero); + { + Label isDigit(env); + DEFVARIABLE(i, MachineType::UINT32_TYPE, GetInt32Constant(1)); + DEFVARIABLE(n, MachineType::UINT32_TYPE, Int32Sub(*c, GetInt32Constant('0'))); + Branch(IsDigit(*c), &isDigit, &exit); + Label loopHead(env); + Label loopEnd(env); + Label afterLoop(env); + Bind(&isDigit); + Branch(Int32LessThan(*i, len), &loopHead, &afterLoop); + LoopBegin(&loopHead); + { + Label isUtf16(env); + Label notUtf16(env); + Label getChar2(env); + Branch(isUtf16String, &isUtf16, ¬Utf16); + Bind(&isUtf16); + { + // 2 : 2 means utf16 char width is two bytes + auto charOffset = PtrMul(ChangeInt32ToPointer(*i), GetPtrConstant(2)); + c = ZExtInt16ToInt32(Load(MachineType::INT16_TYPE, dataUtf16, charOffset)); + Jump(&getChar2); + } + Bind(¬Utf16); + { + c = ZExtInt8ToInt32(Load(MachineType::INT8_TYPE, dataUtf16, ChangeInt32ToPointer(*i))); + Jump(&getChar2); + } + Bind(&getChar2); + { + Label isDigit2(env); + Label notDigit2(env); + Branch(IsDigit(*c), &isDigit2, ¬Digit2); + Bind(&isDigit2); + { + // 10 means the base of digit is 10. + n = Int32Add(Int32Mul(*n, GetInt32Constant(10)), + Int32Sub(*c, GetInt32Constant('0'))); + i = Int32Add(*i, GetInt32Constant(1)); + Branch(Int32LessThan(*i, len), &loopEnd, &afterLoop); + } + Bind(¬Digit2); + Jump(&exit); + } + } + Bind(&loopEnd); + LoopEnd(&loopHead); + Bind(&afterLoop); + { + Label lessThanMaxIndex(env); + Branch(Word32LessThan(*n, GetInt32Constant(panda::ecmascript::JSObject::MAX_ELEMENT_INDEX)), + &lessThanMaxIndex, &exit); + Bind(&lessThanMaxIndex); + { + result = *n; + Jump(&exit); + } + } + } + } + } + Bind(&exit); + auto ret = *result; + env->PopCurrentLabel(); + return ret; } -void Stub::UpdateAndStoreRepresention(AddrShift hclass, AddrShift value) +AddrShift Stub::TryToElementsIndex(AddrShift key) { - AddrShift newRep = UpdateRepresention(GetElementRepresentation(hclass), value); - SetElementRepresentation(hclass, newRep); + auto env = GetEnvironment(); + Label entry(env); + env->PushCurrentLabel(&entry); + Label exit(env); + Label isKeyInt(env); + Label notKeyInt(env); + + DEFVARIABLE(resultKey, MachineType::INT32_TYPE, GetInt32Constant(-1)); + Branch(TaggedIsInt(key), &isKeyInt, ¬KeyInt); + Bind(&isKeyInt); + { + resultKey = TaggedCastToInt32(key); + Jump(&exit); + } + Bind(¬KeyInt); + { + Label isString(env); + Label notString(env); + Branch(TaggedIsString(key), &isString, ¬String); + Bind(&isString); + { + resultKey = StringToElementIndex(key); + Jump(&exit); + } + Bind(¬String); + { + Label isDouble(env); + Branch(TaggedIsDouble(key), &isDouble, &exit); + Bind(&isDouble); + { + AddrShift number = TaggedCastToDouble(key); + AddrShift integer = ChangeFloat64ToInt32(number); + Label isEqual(env); + Branch(DoubleEqual(number, ChangeInt32ToFloat64(integer)), &isEqual, &exit); + Bind(&isEqual); + { + resultKey = integer; + Jump(&exit); + } + } + } + } + Bind(&exit); + auto ret = *resultKey; + env->PopCurrentLabel(); + return ret; } -} // namespace kungfu \ No newline at end of file +} // namespace kungfu diff --git a/ecmascript/compiler/stub.h b/ecmascript/compiler/stub.h index 1260e34bb681ab99c7c9d6aabc655fec551dde4d..6bce838ef160cd62dde1860afc8183220a9e0774 100644 --- a/ecmascript/compiler/stub.h +++ b/ecmascript/compiler/stub.h @@ -21,10 +21,13 @@ #include "ecmascript/compiler/circuit.h" #include "ecmascript/compiler/circuit_builder.h" #include "ecmascript/compiler/gate.h" +#include "ecmascript/compiler/machine_type.h" #include "ecmascript/compiler/stub_descriptor.h" +#include "ecmascript/js_function.h" #include "ecmascript/js_object.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/layout_info.h" +#include "ecmascript/message_string.h" #include "ecmascript/tagged_dictionary.h" namespace kungfu { @@ -242,19 +245,19 @@ public: Label GetLabelFromSelector(AddrShift sel) { - LabelImpl *rawlabel = phi_to_labels[sel]; + LabelImpl *rawlabel = phi_to_labels_[sel]; return Label(rawlabel); } void AddSelectorToLabel(AddrShift sel, Label label) { - phi_to_labels[sel] = label.GetRawLabel(); + phi_to_labels_[sel] = label.GetRawLabel(); } LabelImpl *NewLabel(Environment *env, AddrShift control = -1) { auto impl = new LabelImpl(env, control); - rawlabels_.push_back(impl); + rawlabels_.emplace_back(impl); return impl; } @@ -282,11 +285,16 @@ public: } } + void SetFrameType(panda::ecmascript::FrameType type) + { + circuit_->SetFrameType(type); + } + private: Label *currentLabel_ {nullptr}; Circuit *circuit_; CircuitBuilder builder_; - std::unordered_map phi_to_labels; + std::unordered_map phi_to_labels_; std::vector arguments_; Label entry_; std::vector rawlabels_; @@ -388,7 +396,7 @@ public: return &env_; } // constant - AddrShift GetInteger32Constant(int32_t value) + AddrShift GetInt32Constant(int32_t value) { return env_.GetCircuitBuilder().NewIntegerConstant(value); }; @@ -403,13 +411,13 @@ public: return GetWord64Constant(value); #endif #ifdef PANDA_TARGET_X86 - return GetInteger32Constant(value); + return GetInt32Constant(value); #endif #ifdef PANDA_TARGET_ARM64 return GetWord64Constant(value); #endif #ifdef PANDA_TARGET_ARM32 - return GetInteger32Constant(value); + return GetInt32Constant(value); #endif } @@ -431,12 +439,12 @@ public: AddrShift TrueConstant() { - return TruncInt32ToInt1(GetInteger32Constant(1)); + return TruncInt32ToInt1(GetInt32Constant(1)); } AddrShift FalseConstant() { - return TruncInt32ToInt1(GetInteger32Constant(0)); + return TruncInt32ToInt1(GetInt32Constant(0)); } AddrShift GetBooleanConstant(bool value) @@ -548,17 +556,18 @@ public: void LoopEnd(Label *loopHead); // call operation - AddrShift CallStub(StubDescriptor *descriptor, AddrShift target, std::initializer_list args) + AddrShift CallStub(StubDescriptor *descriptor, AddrShift thread, AddrShift target, + std::initializer_list args) { auto depend = env_.GetCurrentLabel()->GetDepend(); - AddrShift result = env_.GetCircuitBuilder().NewCallGate(descriptor, target, depend, args); + AddrShift result = env_.GetCircuitBuilder().NewCallGate(descriptor, thread, target, depend, args); env_.GetCurrentLabel()->SetDepend(result); return result; } - AddrShift CallStub(StubDescriptor *descriptor, AddrShift target, AddrShift depend, + AddrShift CallStub(StubDescriptor *descriptor, AddrShift thread, AddrShift target, AddrShift depend, std::initializer_list args) { - AddrShift result = env_.GetCircuitBuilder().NewCallGate(descriptor, target, depend, args); + AddrShift result = env_.GetCircuitBuilder().NewCallGate(descriptor, thread, target, depend, args); env_.GetCurrentLabel()->SetDepend(result); return result; } @@ -567,7 +576,7 @@ public: std::initializer_list args) { auto depend = env_.GetCurrentLabel()->GetDepend(); - AddrShift result = env_.GetCircuitBuilder().NewCallRuntimeGate(descriptor, thread, target, depend, args); + AddrShift result = env_.GetCircuitBuilder().NewCallGate(descriptor, thread, target, depend, args); env_.GetCurrentLabel()->SetDepend(result); return result; } @@ -575,7 +584,7 @@ public: AddrShift CallRuntime(StubDescriptor *descriptor, AddrShift thread, AddrShift target, AddrShift depend, std::initializer_list args) { - AddrShift result = env_.GetCircuitBuilder().NewCallRuntimeGate(descriptor, thread, target, depend, args); + AddrShift result = env_.GetCircuitBuilder().NewCallGate(descriptor, thread, target, depend, args); env_.GetCurrentLabel()->SetDepend(result); return result; } @@ -609,23 +618,9 @@ public: AddrShift LoadFromObject(MachineType type, AddrShift object, AddrShift offset); - AddrShift Store(MachineType type, AddrShift base, AddrShift offset, AddrShift value) - { - auto depend = env_.GetCurrentLabel()->GetDepend(); - if (PtrValueCode() == ValueCode::INT64) { - AddrShift ptr = Int64Add(base, offset); - AddrShift result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); - env_.GetCurrentLabel()->SetDepend(result); - return result; - } - if (PtrValueCode() == ValueCode::INT32) { - AddrShift ptr = Int32Add(base, offset); - AddrShift result = env_.GetCircuitBuilder().NewStoreGate(type, ptr, value, depend); - env_.GetCurrentLabel()->SetDepend(result); - return result; - } - UNREACHABLE(); - } + AddrShift Store(MachineType type, AddrShift thread, AddrShift base, AddrShift offset, AddrShift value); + + AddrShift Store(MachineType type, AddrShift base, AddrShift offset, AddrShift value); // arithmetic AddrShift Int32Add(AddrShift x, AddrShift y) @@ -693,7 +688,16 @@ public: { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::FLOAT64_DIV), x, y); } - AddrShift Int32Div(AddrShift x, AddrShift y); + AddrShift Int32Div(AddrShift x, AddrShift y) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT32_SDIV), x, y); + } + + AddrShift Word32Div(AddrShift x, AddrShift y) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT32_UDIV), x, y); + } + AddrShift Int64Div(AddrShift x, AddrShift y); AddrShift Int32Mod(AddrShift x, AddrShift y) @@ -716,6 +720,12 @@ public: { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT32_AND), x, y); } + + AddrShift Word32Not(AddrShift x) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT32_REV), x); + } + AddrShift Word32Xor(AddrShift x, AddrShift y); AddrShift FixLoadType(AddrShift x); @@ -735,27 +745,11 @@ public: return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT64_XOR), x, y); } - AddrShift Word32Not(AddrShift x); AddrShift Word64Not(AddrShift x) { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT64_REV), x); } - AddrShift WordLogicOr(AddrShift x, AddrShift y) - { - return env_.GetCircuitBuilder().NewLogicGate(OpCode(OpCode::INT32_OR), x, y); - } - - AddrShift WordLogicAnd(AddrShift x, AddrShift y) - { - return env_.GetCircuitBuilder().NewLogicGate(OpCode(OpCode::INT32_AND), x, y); - } - - AddrShift WordLogicNot(AddrShift x) - { - return env_.GetCircuitBuilder().NewLogicGate(OpCode(OpCode::INT32_REV), x); - } - AddrShift Word32LSL(AddrShift x, AddrShift y) { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT32_LSL), x, y); @@ -782,8 +776,8 @@ public: AddrShift TaggedIsDouble(AddrShift x) { - return Word32Equal(WordLogicOr(SExtInt1ToInt32(TaggedIsInt(x)), SExtInt1ToInt32(TaggedIsObject(x))), - GetInteger32Constant(0)); + return Word32Equal(Word32Or(SExtInt1ToInt32(TaggedIsInt(x)), SExtInt1ToInt32(TaggedIsObject(x))), + GetInt32Constant(0)); } AddrShift TaggedIsObject(AddrShift x) @@ -794,7 +788,7 @@ public: AddrShift TaggedIsNumber(AddrShift x) { - return TruncInt32ToInt1(WordLogicOr(SExtInt1ToInt32(TaggedIsInt(x)), SExtInt1ToInt32(TaggedIsDouble(x)))); + return TruncInt32ToInt1(Word32Or(SExtInt1ToInt32(TaggedIsInt(x)), SExtInt1ToInt32(TaggedIsDouble(x)))); } AddrShift TaggedIsHole(AddrShift x) @@ -814,25 +808,37 @@ public: AddrShift TaggedIsSpecial(AddrShift x) { - return TruncInt32ToInt1(WordLogicAnd( + return TruncInt32ToInt1(Word32And( SExtInt1ToInt32( Word64Equal(Word64And(x, GetWord64Constant(~panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)), GetWord64Constant(0))), - WordLogicOr(SExtInt1ToInt32(Word64NotEqual( - Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)), + Word32Or(SExtInt1ToInt32(Word64NotEqual( + Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_VALUE)), GetWord64Constant(0))), SExtInt1ToInt32(TaggedIsHole(x))))); } AddrShift TaggedIsHeapObject(AddrShift x) { return TruncInt32ToInt1( - WordLogicAnd(SExtInt1ToInt32(TaggedIsObject(x)), WordLogicNot(SExtInt1ToInt32(TaggedIsSpecial(x))))); + Word32And(SExtInt1ToInt32(TaggedIsObject(x)), + SExtInt1ToInt32(Word32Equal(SExtInt1ToInt32(TaggedIsSpecial(x)), GetInt32Constant(0))))); + } + + AddrShift TaggedIsString(AddrShift obj); + + AddrShift TaggedIsStringOrSymbol(AddrShift obj); + + AddrShift GetNextPositionForHash(AddrShift last, AddrShift count, AddrShift size) + { + auto nextOffset = Word32LSR(Int32Mul(count, Int32Add(count, GetInt32Constant(1))), + GetInt32Constant(1)); + return Word32And(Int32Add(last, nextOffset), Int32Sub(size, GetInt32Constant(1))); } AddrShift DoubleIsNAN(AddrShift x) { AddrShift diff = DoubleEqual(x, x); - return Word32Equal(SExtInt1ToInt32(diff), GetInteger32Constant(0)); + return Word32Equal(SExtInt1ToInt32(diff), GetInt32Constant(0)); } AddrShift DoubleIsINF(AddrShift x) @@ -841,8 +847,33 @@ public: AddrShift negativeInfinity = GetDoubleConstant(-base::POSITIVE_INFINITY); AddrShift diff1 = DoubleEqual(x, infinity); AddrShift diff2 = DoubleEqual(x, negativeInfinity); - return Word32Or(Word32Equal(SExtInt1ToInt32(diff1), GetInteger32Constant(1)), - Word32Equal(SExtInt1ToInt32(diff2), GetInteger32Constant(1))); + return TruncInt32ToInt1(Word32Or(Word32Equal(SExtInt1ToInt32(diff1), GetInt32Constant(1)), + Word32Equal(SExtInt1ToInt32(diff2), GetInt32Constant(1)))); + } + + AddrShift TaggedIsNull(AddrShift x) + { + return Word64Equal(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_NULL)); + } + + AddrShift TaggedIsUndefinedOrNull(AddrShift x) + { + return TruncInt32ToInt1(Word32Or(SExtInt1ToInt32(TaggedIsUndefined(x)), SExtInt1ToInt32(TaggedIsNull(x)))); + } + + AddrShift TaggedIsTrue(AddrShift x) + { + return Word64Equal(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_TRUE)); + } + + AddrShift TaggedIsFalse(AddrShift x) + { + return Word64Equal(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_FALSE)); + } + + AddrShift TaggedIsBoolean(AddrShift x) + { + return TruncInt32ToInt1(Word32Or(SExtInt1ToInt32(TaggedIsTrue(x)), SExtInt1ToInt32(TaggedIsFalse(x)))); } AddrShift IntBuildTagged(AddrShift x) @@ -864,7 +895,17 @@ public: AddrShift CastDoubleToInt64(AddrShift x) { - return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::FLOAT64_TO_INT64), x); + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::BITCAST_FLOAT64_TO_INT64), x); + } + + AddrShift TaggedTrue() + { + return GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_TRUE); + } + + AddrShift TaggedFalse() + { + return GetWord64Constant(panda::ecmascript::JSTaggedValue::VALUE_FALSE); } // compare operation @@ -1006,7 +1047,7 @@ public: AddrShift GetElements(AddrShift object) { - AddrShift elementsOffset = GetInteger32Constant(panda::ecmascript::JSObject::ELEMENTS_OFFSET); + AddrShift elementsOffset = GetInt32Constant(panda::ecmascript::JSObject::ELEMENTS_OFFSET); if (PtrValueCode() == ValueCode::INT64) { elementsOffset = SExtInt32ToInt64(elementsOffset); } @@ -1016,7 +1057,7 @@ public: AddrShift GetProperties(AddrShift object) { - AddrShift propertiesOffset = GetInteger32Constant(panda::ecmascript::JSObject::PROPERTIES_OFFSET); + AddrShift propertiesOffset = GetInt32Constant(panda::ecmascript::JSObject::PROPERTIES_OFFSET); if (PtrValueCode() == ValueCode::INT64) { propertiesOffset = SExtInt32ToInt64(propertiesOffset); } @@ -1024,39 +1065,57 @@ public: return Load(MachineType::UINT64_TYPE, object, propertiesOffset); } + // setProperties in js_object.h + void setProperties(AddrShift thread, AddrShift object, AddrShift value) + { + AddrShift propertiesOffset = GetInt32Constant(panda::ecmascript::JSObject::PROPERTIES_OFFSET); + if (PtrValueCode() == ValueCode::INT64) { + propertiesOffset = SExtInt32ToInt64(propertiesOffset); + } + Store(MachineType::UINT64_TYPE, thread, object, propertiesOffset, value); + } + AddrShift GetLengthofElements(AddrShift elements) { - return Load(UINT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); + return Load(MachineType::UINT32_TYPE, elements, GetPtrConstant(panda::coretypes::Array::GetLengthOffset())); } // object operation AddrShift LoadHClass(AddrShift object) { - return ChangeInt32ToPointer(Load(UINT32_TYPE, object)); + return ChangeInt32ToPointer(Load(MachineType::UINT32_TYPE, object)); } - AddrShift GetObjectType(AddrShift hclass) + AddrShift GetObjectType(AddrShift hClass) { AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); - - AddrShift bitfield = Load(INT64_TYPE, hclass, bitfieldOffset); - + AddrShift bitfield = Load(MachineType::UINT64_TYPE, hClass, bitfieldOffset); return ChangeInt64ToInt32( Word64And(bitfield, GetWord64Constant((1LLU << panda::ecmascript::JSHClass::ObjectTypeBits::SIZE) - 1))); } AddrShift IsDictionaryMode(AddrShift object) { - return Word32NotEqual(Word32And(Load(UINT32_TYPE, LoadHClass(object), GetPtrConstant(0)), - GetInteger32Constant(panda::HClass::IS_DICTIONARY_ARRAY)), - GetInteger32Constant(0)); + AddrShift objectType = GetObjectType(LoadHClass(object)); + return Word32Equal(objectType, + GetInt32Constant(static_cast(panda::ecmascript::JSType::TAGGED_DICTIONARY))); } - AddrShift IsDictionaryElement(AddrShift hclass) + AddrShift IsDictionaryModeByHClass(AddrShift hClass) { AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); + AddrShift bitfield = Load(MachineType::INT64_TYPE, hClass, bitfieldOffset); + return Word64NotEqual( + Word64And( + Word64LSR(bitfield, GetWord64Constant(panda::ecmascript::JSHClass::IsDictionaryBit::START_BIT)), + GetWord64Constant((1LLU << panda::ecmascript::JSHClass::IsDictionaryBit::SIZE) - 1)), + GetWord64Constant(0)); + } - AddrShift bitfield = Load(INT64_TYPE, hclass, bitfieldOffset); + AddrShift IsDictionaryElement(AddrShift hClass) + { + AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); + AddrShift bitfield = Load(MachineType::INT64_TYPE, hClass, bitfieldOffset); // decode return Word64NotEqual( Word64And( @@ -1065,12 +1124,41 @@ public: GetWord64Constant(0)); } - AddrShift IsExtensible(AddrShift object) + AddrShift NotBuiltinsConstructor(AddrShift object) { AddrShift hclass = LoadHClass(object); AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); - AddrShift bitfield = Load(INT64_TYPE, hclass, bitfieldOffset); + AddrShift bitfield = Load(MachineType::INT64_TYPE, hclass, bitfieldOffset); + // decode + return Word64Equal( + Word64And( + Word64LSR(bitfield, GetWord64Constant(panda::ecmascript::JSHClass::BuiltinsCtorBit::START_BIT)), + GetWord64Constant((1LLU << panda::ecmascript::JSHClass::BuiltinsCtorBit::SIZE) - 1)), + GetWord64Constant(0)); + } + + AddrShift IsClassConstructor(AddrShift object) + { + AddrShift functionInfoFlagOffset = GetPtrConstant(panda::ecmascript::JSFunction::FUNCTION_INFO_FLAG_OFFSET); + AddrShift functionInfoTaggedValue = Load(MachineType::UINT64_TYPE, object, functionInfoFlagOffset); + AddrShift functionInfoInt32 = TaggedCastToInt32(functionInfoTaggedValue); + AddrShift functionInfoFlag = ZExtInt32ToInt64(functionInfoInt32); + // decode + return Word64NotEqual( + Word64And( + Word64LSR(functionInfoFlag, + GetWord64Constant(panda::ecmascript::JSFunction::ClassConstructorBit::START_BIT)), + GetWord64Constant((1LLU << panda::ecmascript::JSFunction::ClassConstructorBit::SIZE) - 1)), + GetWord64Constant(0)); + } + + AddrShift IsExtensible(AddrShift object) + { + AddrShift hClass = LoadHClass(object); + AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); + + AddrShift bitfield = Load(MachineType::INT64_TYPE, hClass, bitfieldOffset); // decode return Word64NotEqual( Word64And(Word64LSR(bitfield, GetWord64Constant(panda::ecmascript::JSHClass::ExtensibleBit::START_BIT)), @@ -1081,70 +1169,88 @@ public: AddrShift IsSymbol(AddrShift obj) { AddrShift objectType = GetObjectType(LoadHClass(obj)); - return Word32Equal(objectType, GetInteger32Constant(static_cast(panda::ecmascript::JSType::SYMBOL))); + return Word32Equal(objectType, GetInt32Constant(static_cast(panda::ecmascript::JSType::SYMBOL))); } AddrShift IsString(AddrShift obj) { AddrShift objectType = GetObjectType(LoadHClass(obj)); - return Word32Equal(objectType, GetInteger32Constant(static_cast(panda::ecmascript::JSType::STRING))); + return Word32Equal(objectType, GetInt32Constant(static_cast(panda::ecmascript::JSType::STRING))); } AddrShift IsJsProxy(AddrShift obj) { AddrShift objectType = GetObjectType(LoadHClass(obj)); - return Word32Equal(objectType, GetInteger32Constant(static_cast(panda::ecmascript::JSType::JS_PROXY))); + return Word32Equal(objectType, GetInt32Constant(static_cast(panda::ecmascript::JSType::JS_PROXY))); + } + + AddrShift IsJsArray(AddrShift obj) + { + AddrShift objectType = GetObjectType(LoadHClass(obj)); + return Word32Equal(objectType, GetInt32Constant(static_cast(panda::ecmascript::JSType::JS_ARRAY))); } AddrShift IsWritable(AddrShift attr) { return Word32NotEqual( Word32And( - Word32LSR(attr, GetInteger32Constant(panda::ecmascript::PropertyAttributes::WritableField::START_BIT)), - GetInteger32Constant((1LLU << panda::ecmascript::PropertyAttributes::WritableField::SIZE) - 1)), - GetInteger32Constant(0)); + Word32LSR(attr, GetInt32Constant(panda::ecmascript::PropertyAttributes::WritableField::START_BIT)), + GetInt32Constant((1LLU << panda::ecmascript::PropertyAttributes::WritableField::SIZE) - 1)), + GetInt32Constant(0)); } AddrShift IsAccessor(AddrShift attr) { return Word32NotEqual( Word32And(Word32LSR(attr, - GetInteger32Constant(panda::ecmascript::PropertyAttributes::IsAccessorField::START_BIT)), - GetInteger32Constant((1LLU << panda::ecmascript::PropertyAttributes::IsAccessorField::SIZE) - 1)), - GetInteger32Constant(0)); + GetInt32Constant(panda::ecmascript::PropertyAttributes::IsAccessorField::START_BIT)), + GetInt32Constant((1LLU << panda::ecmascript::PropertyAttributes::IsAccessorField::SIZE) - 1)), + GetInt32Constant(0)); } AddrShift IsInlinedProperty(AddrShift attr) { return Word32NotEqual( Word32And(Word32LSR(attr, - GetInteger32Constant(panda::ecmascript::PropertyAttributes::IsInlinedPropsField::START_BIT)), - GetInteger32Constant((1LLU << panda::ecmascript::PropertyAttributes::IsInlinedPropsField::SIZE) - 1)), - GetInteger32Constant(0)); + GetInt32Constant(panda::ecmascript::PropertyAttributes::IsInlinedPropsField::START_BIT)), + GetInt32Constant((1LLU << panda::ecmascript::PropertyAttributes::IsInlinedPropsField::SIZE) - 1)), + GetInt32Constant(0)); } AddrShift PropAttrGetOffset(AddrShift attr) { return Word32And( - Word32LSR(attr, GetInteger32Constant(panda::ecmascript::PropertyAttributes::OffsetField::START_BIT)), - GetInteger32Constant((1LLU << panda::ecmascript::PropertyAttributes::OffsetField::SIZE) - 1)); + Word32LSR(attr, GetInt32Constant(panda::ecmascript::PropertyAttributes::OffsetField::START_BIT)), + GetInt32Constant((1LLU << panda::ecmascript::PropertyAttributes::OffsetField::SIZE) - 1)); + } + + // SetDictionaryOrder func in property_attribute.h + AddrShift SetDictionaryOrderFieldInPropAttr(AddrShift attr, AddrShift value) + { + AddrShift mask = Word32LSL( + GetInt32Constant((1LLU << panda::ecmascript::PropertyAttributes::DictionaryOrderField::SIZE) - 1), + GetInt32Constant(panda::ecmascript::PropertyAttributes::DictionaryOrderField::START_BIT)); + AddrShift newVal = Word32Or(Word32And(attr, Word32Not(mask)), + Word32LSL(value, GetInt32Constant(panda::ecmascript::PropertyAttributes::DictionaryOrderField::START_BIT))); + return newVal; } - AddrShift GetPrototypeFromHClass(AddrShift hclass) + AddrShift GetPrototypeFromHClass(AddrShift hClass) { AddrShift protoOffset = GetPtrConstant(panda::ecmascript::JSHClass::PROTOTYPE_OFFSET); - return Load(TAGGED_TYPE, hclass, protoOffset); + return Load(MachineType::TAGGED_TYPE, hClass, protoOffset); } - AddrShift GetAttributesFromHclass(AddrShift hclass) + AddrShift GetAttributesFromHclass(AddrShift hClass) { AddrShift attrOffset = GetPtrConstant(panda::ecmascript::JSHClass::ATTRIBUTES_OFFSET); - return Load(TAGGED_TYPE, hclass, attrOffset); + return Load(MachineType::TAGGED_TYPE, hClass, attrOffset); } - AddrShift GetPropertiesNumberFromHClass(AddrShift hclass) + AddrShift GetPropertiesNumberFromHClass(AddrShift hClass) { - AddrShift bitfield = Load(INT64_TYPE, hclass, GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET)); + AddrShift bitfield = Load(MachineType::INT64_TYPE, hClass, + GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET)); AddrShift unusedNonInlinedProps = Word64And(Word64LSR(bitfield, GetWord64Constant(panda::ecmascript::JSHClass::NumberOfUnusedNonInlinedPropsBits::START_BIT)), GetWord64Constant((1LLU << panda::ecmascript::JSHClass::NumberOfUnusedNonInlinedPropsBits::SIZE) - 1)); @@ -1157,9 +1263,17 @@ public: unusedInlinedProps); } - AddrShift GetObjectSizeFromHClass(AddrShift hclass) // NOTE: need to add special case for string and TAGGED_ARRAY + AddrShift GetObjectSizeFromHClass(AddrShift hClass) // NOTE: need to add special case for string and TAGGED_ARRAY { - return Load(UINT64_TYPE, hclass, GetPtrConstant(panda::ecmascript::JSHClass::OBJECT_SIZE_OFFSET)); + return Load(MachineType::UINT64_TYPE, hClass, GetPtrConstant(panda::ecmascript::JSHClass::OBJECT_SIZE_OFFSET)); + } + + void StoreElement(AddrShift thread, AddrShift elements, AddrShift index, AddrShift value) + { + AddrShift offset = + PtrMul(ChangeInt32ToPointer(index), GetPtrConstant(panda::ecmascript::JSTaggedValue::TaggedTypeSize())); + AddrShift dataOffset = PtrAdd(offset, GetPtrConstant(panda::coretypes::Array::GetDataOffset())); + Store(MachineType::TAGGED_TYPE, thread, elements, dataOffset, value); } void StoreElement(AddrShift elements, AddrShift index, AddrShift value) @@ -1167,7 +1281,7 @@ public: AddrShift offset = PtrMul(ChangeInt32ToPointer(index), GetPtrConstant(panda::ecmascript::JSTaggedValue::TaggedTypeSize())); AddrShift dataOffset = PtrAdd(offset, GetPtrConstant(panda::coretypes::Array::GetDataOffset())); - Store(TAGGED_TYPE, elements, dataOffset, value); + Store(MachineType::TAGGED_TYPE, elements, dataOffset, value); } void ThrowTypeAndReturn(AddrShift thread, int messageId, AddrShift val); @@ -1177,40 +1291,41 @@ public: AddrShift offset = PtrMul(ChangeInt32ToPointer(index), GetPtrConstant(panda::ecmascript::JSTaggedValue::TaggedTypeSize())); AddrShift dataOffset = PtrAdd(offset, GetPtrConstant(panda::coretypes::Array::GetDataOffset())); - return Load(TAGGED_TYPE, elements, dataOffset); + return Load(MachineType::TAGGED_TYPE, elements, dataOffset); } AddrShift TaggedToRepresentation(AddrShift value); - AddrShift GetElementRepresentation(AddrShift hclass) + AddrShift GetElementRepresentation(AddrShift hClass) { AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); - AddrShift bitfield = Load(INT64_TYPE, hclass, bitfieldOffset); + AddrShift bitfield = Load(MachineType::INT64_TYPE, hClass, bitfieldOffset); return Word64And( Word64LSR(bitfield, GetWord64Constant(panda::ecmascript::JSHClass::ElementRepresentationBits::START_BIT)), GetWord64Constant(((1LLU << panda::ecmascript::JSHClass::ElementRepresentationBits::SIZE) - 1))); } - void SetElementRepresentation(AddrShift hclass, AddrShift value) + void SetElementRepresentation(AddrShift hClass, AddrShift value) { AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); - AddrShift oldValue = Load(INT64_TYPE, hclass, bitfieldOffset); + AddrShift oldValue = Load(MachineType::INT64_TYPE, hClass, bitfieldOffset); AddrShift oldWithMask = Word64And(oldValue, GetWord64Constant(~panda::ecmascript::JSHClass::ElementRepresentationBits::Mask())); AddrShift newValue = Word64LSR(value, GetWord64Constant( panda::ecmascript::JSHClass::ElementRepresentationBits::START_BIT)); - Store(INT64_TYPE, hclass, bitfieldOffset, Word64Or(oldWithMask, newValue)); + Store(MachineType::INT64_TYPE, hClass, bitfieldOffset, Word64Or(oldWithMask, newValue)); } - void UpdateValueAndAttributes(AddrShift elements, AddrShift index, AddrShift value, AddrShift attr) + void UpdateValueAndAttributes(AddrShift thread, AddrShift elements, AddrShift index, + AddrShift value, AddrShift attr) { AddrShift arrayIndex = - Int32Add(GetInteger32Constant(panda::ecmascript::NameDictionary::TABLE_HEADER_SIZE), - Int32Mul(index, GetInteger32Constant(panda::ecmascript::NameDictionary::ENTRY_SIZE))); + Int32Add(GetInt32Constant(panda::ecmascript::NameDictionary::TABLE_HEADER_SIZE), + Int32Mul(index, GetInt32Constant(panda::ecmascript::NameDictionary::ENTRY_SIZE))); AddrShift valueIndex = - Int32Add(arrayIndex, GetInteger32Constant(panda::ecmascript::NameDictionary::ENTRY_VALUE_INDEX)); + Int32Add(arrayIndex, GetInt32Constant(panda::ecmascript::NameDictionary::ENTRY_VALUE_INDEX)); AddrShift attributesIndex = - Int32Add(arrayIndex, GetInteger32Constant(panda::ecmascript::NameDictionary::ENTRY_DETAILS_INDEX)); + Int32Add(arrayIndex, GetInt32Constant(panda::ecmascript::NameDictionary::ENTRY_DETAILS_INDEX)); StoreElement(elements, valueIndex, value); StoreElement(elements, attributesIndex, IntBuildTagged(attr)); } @@ -1218,36 +1333,36 @@ public: AddrShift IsSpecialIndexedObj(AddrShift jsType) { return Int32GreaterThan(jsType, - GetInteger32Constant(static_cast(panda::ecmascript::JSType::JS_ARRAY))); + GetInt32Constant(static_cast(panda::ecmascript::JSType::JS_ARRAY))); } AddrShift IsAccessorInternal(AddrShift value) { return Word32Equal(GetObjectType(LoadHClass(value)), - GetInteger32Constant(static_cast(panda::ecmascript::JSType::INTERNAL_ACCESSOR))); + GetInt32Constant(static_cast(panda::ecmascript::JSType::INTERNAL_ACCESSOR))); } - void UpdateAndStoreRepresention(AddrShift hclass, AddrShift value); + void UpdateAndStoreRepresention(AddrShift hClass, AddrShift value); AddrShift UpdateRepresention(AddrShift oldRep, AddrShift value); AddrShift GetAttributesFromDictionary(AddrShift elements, AddrShift entry) { AddrShift arrayIndex = - Int32Add(GetInteger32Constant(panda::ecmascript::NumberDictionary::TABLE_HEADER_SIZE), - Int32Mul(entry, GetInteger32Constant(panda::ecmascript::NumberDictionary::ENTRY_SIZE))); + Int32Add(GetInt32Constant(panda::ecmascript::NumberDictionary::TABLE_HEADER_SIZE), + Int32Mul(entry, GetInt32Constant(panda::ecmascript::NumberDictionary::ENTRY_SIZE))); AddrShift attributesIndex = - Int32Add(arrayIndex, GetInteger32Constant(panda::ecmascript::NameDictionary::ENTRY_DETAILS_INDEX)); - return GetValueFromTaggedArray(elements, attributesIndex); + Int32Add(arrayIndex, GetInt32Constant(panda::ecmascript::NameDictionary::ENTRY_DETAILS_INDEX)); + return TaggedCastToInt32(GetValueFromTaggedArray(elements, attributesIndex)); } AddrShift GetValueFromDictionary(AddrShift elements, AddrShift entry) { AddrShift arrayIndex = - Int32Add(GetInteger32Constant(panda::ecmascript::NumberDictionary::TABLE_HEADER_SIZE), - Int32Mul(entry, GetInteger32Constant(panda::ecmascript::NumberDictionary::ENTRY_SIZE))); + Int32Add(GetInt32Constant(panda::ecmascript::NumberDictionary::TABLE_HEADER_SIZE), + Int32Mul(entry, GetInt32Constant(panda::ecmascript::NumberDictionary::ENTRY_SIZE))); AddrShift valueIndex = - Int32Add(arrayIndex, GetInteger32Constant(panda::ecmascript::NameDictionary::ENTRY_VALUE_INDEX)); + Int32Add(arrayIndex, GetInt32Constant(panda::ecmascript::NameDictionary::ENTRY_VALUE_INDEX)); return GetValueFromTaggedArray(elements, valueIndex); } @@ -1256,9 +1371,9 @@ public: AddrShift GetPropAttrFromLayoutInfo(AddrShift layout, AddrShift entry) { AddrShift index = Int32Add( - Int32Add(GetInteger32Constant(panda::ecmascript::LayoutInfo::ELEMENTS_START_INDEX), - Word32LSL(entry, GetInteger32Constant(1))), - GetInteger32Constant(1)); + Int32Add(GetInt32Constant(panda::ecmascript::LayoutInfo::ELEMENTS_START_INDEX), + Word32LSL(entry, GetInt32Constant(1))), + GetInt32Constant(1)); return GetValueFromTaggedArray(layout, index); } @@ -1270,6 +1385,18 @@ public: AddrShift JSObjectGetProperty(AddrShift obj, AddrShift hClass, AddrShift propAttr); + AddrShift IsUtf16String(AddrShift string); + + AddrShift IsUtf8String(AddrShift string); + + AddrShift IsInternalString(AddrShift string); + + AddrShift IsDigit(AddrShift ch); + + AddrShift StringToElementIndex(AddrShift string); + + AddrShift TryToElementsIndex(AddrShift key); + AddrShift TaggedCastToInt64(AddrShift x) { return Word64And(x, GetWord64Constant(~panda::ecmascript::JSTaggedValue::TAG_MASK)); @@ -1286,14 +1413,19 @@ public: return CastInt64ToFloat64(val); } - AddrShift CastInt32ToFloat64(AddrShift x) + AddrShift ChangeInt32ToFloat64(AddrShift x) { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT32_TO_FLOAT64), x); } + AddrShift ChangeFloat64ToInt32(AddrShift x) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::FLOAT64_TO_INT32), x); + } + AddrShift CastInt64ToFloat64(AddrShift x) { - return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::INT64_TO_FLOAT64), x); + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::BITCAST_INT64_TO_FLOAT64), x); } AddrShift SExtInt32ToInt64(AddrShift x) @@ -1326,6 +1458,16 @@ public: return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::ZEXT_INT1_TO_INT32), x); } + AddrShift ZExtInt8ToInt32(AddrShift x) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::ZEXT_INT8_TO_INT32), x); + } + + AddrShift ZExtInt16ToInt32(AddrShift x) + { + return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::ZEXT_INT16_TO_INT32), x); + } + AddrShift TruncInt64ToInt32(AddrShift x) { return env_.GetCircuitBuilder().NewArithMeticGate(OpCode(OpCode::TRUNC_INT64_TO_INT32), x); @@ -1346,6 +1488,34 @@ public: return nextVariableId_++; } + std::string GetMethodName() const + { + return methodName_; + } + + AddrShift GetGlobalConstantAddr(AddrShift index) + { + return Int64Mul(GetWord64Constant(sizeof(JSTaggedValue)), index); + } + + AddrShift GetGlobalConstantString(ConstantIndex index) + { + return GetGlobalConstantAddr(GetWord64Constant(static_cast(index))); + } + + AddrShift IsCallable(AddrShift obj) + { + AddrShift hclass = LoadHClass(obj); + AddrShift bitfieldOffset = GetPtrConstant(panda::ecmascript::JSHClass::BIT_FIELD_OFFSET); + + AddrShift bitfield = Load(MachineType::INT64_TYPE, hclass, bitfieldOffset); + // decode + return Word64NotEqual( + Word64And(Word64LSR(bitfield, GetWord64Constant(panda::ecmascript::JSHClass::CallableBit::START_BIT)), + GetWord64Constant((1LLU << panda::ecmascript::JSHClass::CallableBit::SIZE) - 1)), + GetWord64Constant(0)); + } + private: Environment env_; std::string methodName_; diff --git a/ecmascript/compiler/stub_aot_compiler.cpp b/ecmascript/compiler/stub_aot_compiler.cpp index 530c67699dd77f3d64112f581366211cf5368d53..7403ee7d6e17bb24d763d17953a4d0612cc72e63 100644 --- a/ecmascript/compiler/stub_aot_compiler.cpp +++ b/ecmascript/compiler/stub_aot_compiler.cpp @@ -14,10 +14,14 @@ */ #include "stub_aot_compiler.h" + #include #include #include #include "fast_stub.h" +#include "generated/stub_aot_options_gen.h" +#include "libpandabase/utils/pandargs.h" +#include "libpandabase/utils/span.h" #include "llvm_codegen.h" #include "scheduler.h" #include "stub.h" @@ -99,15 +103,17 @@ public: } }; -void StubAotCompiler::BuildStubModule(panda::ecmascript::StubModule *module) +void StubAotCompiler::BuildStubModuleAndSave(const char *triple, panda::ecmascript::StubModule *module, + const std::string &filename) { - LLVMStubModule stubModule("fast_stubs"); + LLVMStubModule stubModule("fast_stubs", triple); stubModule.Initialize(); for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) { - auto Stub = stubs_[i]; - if (Stub != nullptr) { - Stub->GenerateCircuit(); - auto circuit = Stub->GetEnvironment()->GetCircuit(); + auto stub = stubs_[i]; + if (stub != nullptr) { + std::cout << "Stub Name: " << stub->GetMethodName() << std::endl; + stub->GenerateCircuit(); + auto circuit = stub->GetEnvironment()->GetCircuit(); PassPayLoad data(circuit, &stubModule); PassRunner pipeline(&data); pipeline.RunPass(); @@ -116,68 +122,84 @@ void StubAotCompiler::BuildStubModule(panda::ecmascript::StubModule *module) } } - LLVMModuleAssembler assembler(&stubModule); + LLVMModuleAssembler assembler(&stubModule, triple); assembler.AssembleModule(); - assembler.CopyAssembleCodeToModule(module); + assembler.AssembleStubModule(module); + + auto codeSize = assembler.GetCodeSize(); + panda::ecmascript::MachineCode *code = reinterpret_cast( + new uint64_t[(panda::ecmascript::MachineCode::SIZE + codeSize) / sizeof(uint64_t) + 1]); + code->SetInstructionSizeInBytes(nullptr, panda::ecmascript::JSTaggedValue(codeSize), + panda::ecmascript::SKIP_BARRIER); + + assembler.CopyAssemblerToCode(code); + + module->SetCode(code); + module->Save(filename); + + delete code; } } // namespace kungfu -int main(int argc, char *argv[]) +#define SET_STUB_TO_MODULE(module, name) \ + kungfu::Circuit name##Circuit; \ + kungfu::name##Stub name##Stub(& name##Circuit); \ + module.SetStub(FAST_STUB_ID(name), & name##Stub); +#define SET_ALL_STUB_TO_MODEULE(module) \ + SET_STUB_TO_MODULE(module, FastAdd) \ + SET_STUB_TO_MODULE(module, FastSub) \ + SET_STUB_TO_MODULE(module, FastMul) \ + SET_STUB_TO_MODULE(module, FastDiv) \ + SET_STUB_TO_MODULE(module, FastMod) \ + SET_STUB_TO_MODULE(module, FastTypeOf) \ + SET_STUB_TO_MODULE(module, FastEqual) \ + SET_STUB_TO_MODULE(module, FindOwnElement) \ + SET_STUB_TO_MODULE(module, GetElement) \ + SET_STUB_TO_MODULE(module, FindOwnElement2) \ + SET_STUB_TO_MODULE(module, SetElement) \ + SET_STUB_TO_MODULE(module, GetPropertyByIndex) \ + SET_STUB_TO_MODULE(module, SetPropertyByIndex) \ + SET_STUB_TO_MODULE(module, FunctionCallInternal) \ + SET_STUB_TO_MODULE(module, GetPropertyByName) \ + SET_STUB_TO_MODULE(module, GetPropertyByValue) + +#ifndef NDEBUG +#define SET_TEST_STUB_TO_MODEULE(module) \ + SET_STUB_TO_MODULE(module, FastMulGCTest) +#endif + +int main(const int argc, const char **argv) { - int opt; - // 3 means ark_stub_opt -f stub.m - if (argc != 3) { - std::cerr << "Usage: " << argv[0] << " -f stub.m" << std::endl; - return -1; - } - std::string moduleFilename; - while ((opt = getopt(argc, argv, "f:")) != -1) { - switch (opt) { - case 'f': - moduleFilename += optarg; - break; - default: /* '?' */ - std::cerr << "Usage: " << argv[0] << " -f stub.m" << std::endl; - return -1; - } + panda::Span sp(argv, argc); + panda::Stub_Aot_Options stubOptions(sp[0]); + panda::PandArg help("help", false, "Print this message and exit"); + panda::PandArg options("options", false, "Print compiler options"); + panda::PandArgParser paParser; + + stubOptions.AddOptions(&paParser); + paParser.Add(&help); + paParser.Add(&options); + + if (!paParser.Parse(argc, argv) || help.GetValue()) { + std::cerr << paParser.GetErrorString() << std::endl; + std::cerr << "Usage: " << "ark_stub_opt" << " [OPTIONS]" << std::endl; + std::cerr << std::endl; + std::cerr << "optional arguments:" << std::endl; + std::cerr << paParser.GetHelpString() << std::endl; + return 1; } + std::string moduleFilename = stubOptions.GetStubOutputFile(); + std::string tripes = stubOptions.GetTargetTriple(); + kungfu::StubAotCompiler mouldeBuilder; + SET_ALL_STUB_TO_MODEULE(mouldeBuilder); +#ifndef NDEBUG + SET_TEST_STUB_TO_MODEULE(mouldeBuilder); +#endif panda::ecmascript::StubModule stubModule; - /* Set Stub into module */ - kungfu::Circuit fastaddCircuit; - kungfu::FastAddStub fastaddStub(&fastaddCircuit); - mouldeBuilder.SetStub(FAST_STUB_ID(FastAdd), &fastaddStub); - - kungfu::Circuit fastsubCircuit; - kungfu::FastSubStub fastsubStub(&fastsubCircuit); - mouldeBuilder.SetStub(FAST_STUB_ID(FastSub), &fastsubStub); - - kungfu::Circuit fastmulCircuit; - kungfu::FastMulStub fastmulStub(&fastmulCircuit); - mouldeBuilder.SetStub(FAST_STUB_ID(FastMul), &fastmulStub); - - kungfu::Circuit fastdivCircuit; - kungfu::FastDivStub fastdivStub(&fastdivCircuit); - mouldeBuilder.SetStub(FAST_STUB_ID(FastDiv), &fastdivStub); - - kungfu::Circuit fastFindOwnElementCircuit; - kungfu::FastFindOwnElementStub fastFindOwnElementStub(&fastFindOwnElementCircuit); - mouldeBuilder.SetStub(FAST_STUB_ID(FindOwnElement), &fastFindOwnElementStub); - - kungfu::Circuit fastGetElementCircuit; - kungfu::FastGetElementStub fastGetElementStub(&fastGetElementCircuit); - mouldeBuilder.SetStub(FAST_STUB_ID(GetElement), &fastGetElementStub); - - kungfu::Circuit fastFindOwnElement2Circuit; - kungfu::FastFindOwnElement2Stub fastFindOwnElement2Stub(&fastFindOwnElement2Circuit); - mouldeBuilder.SetStub(FAST_STUB_ID(FindOwnElement2), &fastFindOwnElement2Stub); - - kungfu::Circuit fastSetElementCircuit; - kungfu::FastSetElementStub fastSetElementStub(&fastSetElementCircuit); - mouldeBuilder.SetStub(FAST_STUB_ID(SetElement), &fastSetElementStub); - - mouldeBuilder.BuildStubModule(&stubModule); - stubModule.Save(moduleFilename); - exit(0); + mouldeBuilder.BuildStubModuleAndSave(tripes.c_str(), &stubModule, moduleFilename); + + std::cout << "BuildStubModuleAndSave success" << std::endl; + return 0; } \ No newline at end of file diff --git a/ecmascript/compiler/stub_aot_compiler.h b/ecmascript/compiler/stub_aot_compiler.h index 736ba00287164470360b19d5290d9418039bbd4f..3588b1cea5ec123b8c2e1c4d669acac0d6ca7527 100644 --- a/ecmascript/compiler/stub_aot_compiler.h +++ b/ecmascript/compiler/stub_aot_compiler.h @@ -22,7 +22,6 @@ namespace kungfu { class Stub; class circuit; -using Address = uintptr_t; class StubAotCompiler { public: StubAotCompiler() @@ -30,9 +29,16 @@ public: for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) { stubs_[i] = nullptr; } - }; - ~StubAotCompiler() = default; - void BuildStubModule(panda::ecmascript::StubModule *module); + } + ~StubAotCompiler() + { + for (int i = 0; i < FAST_STUB_MAXCOUNT; i++) { + stubs_[i] = nullptr; + } + } + void BuildStubModuleAndSave(const char *triple, panda::ecmascript::StubModule *module, + const std::string &filename); + void SetAllStubToModule(); void SetStub(int index, Stub *optimizer) { stubs_[index] = optimizer; diff --git a/ecmascript/compiler/stub_aot_options.yaml b/ecmascript/compiler/stub_aot_options.yaml new file mode 100644 index 0000000000000000000000000000000000000000..7fb1b41ca79cc94d3dd5413e80bc85727a7e414f --- /dev/null +++ b/ecmascript/compiler/stub_aot_options.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2021 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. + +module: + name: Stub_Aot + namespace: panda + +options: +- name: stub-output-file + type: std::string + default: stub.m + description: stub aot compiler output file name + +- name: target-triple + type: std::string + default: x86_64-unknown-linux-gnu + possible_values: + - x86_64-unknown-linux-gnu + - arm-unknown-linux-gnu + - aarch64-unknown-linux-gnu + description: stub aot compiler target triple diff --git a/ecmascript/compiler/stub_descriptor.cpp b/ecmascript/compiler/stub_descriptor.cpp index 31cc658a5ac2963abab8c4d4510a84423aab2c1e..11e1768bb4976154b76317e6986d4321b92a8e1a 100644 --- a/ecmascript/compiler/stub_descriptor.cpp +++ b/ecmascript/compiler/stub_descriptor.cpp @@ -26,11 +26,10 @@ namespace kungfu { static void Initialize(StubDescriptor *descriptor); \ }; \ void Stub##name##InterfaceDescriptor::Initialize(StubDescriptor *descriptor) - CALL_STUB_INIT_DESCRIPTOR(FastAdd) { // 2 : 2 input parameters - static StubDescriptor fastAdd("FastAdd", 0, 2, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor fastAdd("FastAdd", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = fastAdd; // 2 : 2 input parameters std::array params = { @@ -43,7 +42,7 @@ CALL_STUB_INIT_DESCRIPTOR(FastAdd) CALL_STUB_INIT_DESCRIPTOR(FastSub) { // 2 : 2 input parameters - static StubDescriptor fastSub("FastSub", 0, 2, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor fastSub("FastSub", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = fastSub; // 2 : 2 input parameters std::array params = { @@ -56,7 +55,7 @@ CALL_STUB_INIT_DESCRIPTOR(FastSub) CALL_STUB_INIT_DESCRIPTOR(FastMul) { // 2 : 2 input parameters - static StubDescriptor fastMul("FastMul", 0, 2, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor fastMul("FastMul", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = fastMul; // 2 : 2 input parameters std::array params = { @@ -66,10 +65,28 @@ CALL_STUB_INIT_DESCRIPTOR(FastMul) descriptor->SetParameters(params.data()); } +#ifndef NDEBUG +CALL_STUB_INIT_DESCRIPTOR(FastMulGCTest) +{ + // 3 : 3 input parameters + StubDescriptor fastMulGC("FastMulGCTest", 0, 3, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = fastMulGC; + // 3 : 3 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} +#else +CALL_STUB_INIT_DESCRIPTOR(FastMulGCTest) {} +#endif + CALL_STUB_INIT_DESCRIPTOR(FastDiv) { // 2 : 2 input parameters - static StubDescriptor fastDiv("FastDiv", 0, 2, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor fastDiv("FastDiv", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = fastDiv; // 2 : 2 input parameters std::array params = { @@ -79,11 +96,59 @@ CALL_STUB_INIT_DESCRIPTOR(FastDiv) descriptor->SetParameters(params.data()); } -CALL_STUB_INIT_DESCRIPTOR(FastMod) {} +CALL_STUB_INIT_DESCRIPTOR(FastMod) +{ + // 3 : 3 input parameters + StubDescriptor fastMod("FastMod", 0, 3, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = fastMod; + // 3 : 3 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} -CALL_STUB_INIT_DESCRIPTOR(FastEqual) {} +CALL_STUB_INIT_DESCRIPTOR(FloatMod) +{ + // 2 : 2 input parameters + StubDescriptor floatMod("FloatMod", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::FLOAT64_TYPE); + *descriptor = floatMod; + // 2 : 2 input parameters + std::array params = { + MachineType::FLOAT64_TYPE, + MachineType::FLOAT64_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); +} -CALL_STUB_INIT_DESCRIPTOR(FastTypeOf) {} +CALL_STUB_INIT_DESCRIPTOR(FastTypeOf) +{ + // 2 input parameters + StubDescriptor fastTypeOf("FastTypeOf", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = fastTypeOf; + // 2 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} + +CALL_STUB_INIT_DESCRIPTOR(FastEqual) +{ + // 2 input parameters + StubDescriptor fastEqual("FastEqual", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = fastEqual; + // 2 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} CALL_STUB_INIT_DESCRIPTOR(FastStrictEqual) {} @@ -94,7 +159,7 @@ CALL_STUB_INIT_DESCRIPTOR(IsSpecialIndexedObjForGet) {} CALL_STUB_INIT_DESCRIPTOR(GetElement) { // 3 : 3 input parameters - static StubDescriptor getElement("GetElement", 0, 3, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor getElement("GetElement", 0, 3, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = getElement; // 3 : 3 input parameters std::array params = { @@ -108,7 +173,7 @@ CALL_STUB_INIT_DESCRIPTOR(GetElement) CALL_STUB_INIT_DESCRIPTOR(SetElement) { // 5 : 5 input parameters - static StubDescriptor setElement("SetElement", 0, 5, ArgumentsOrder::DEFAULT_ORDER, BOOL_TYPE); + StubDescriptor setElement("SetElement", 0, 5, ArgumentsOrder::DEFAULT_ORDER, MachineType::BOOL_TYPE); *descriptor = setElement; // 5 : 5 input parameters std::array params = { @@ -123,13 +188,12 @@ CALL_STUB_INIT_DESCRIPTOR(SetPropertyByName) {} CALL_STUB_INIT_DESCRIPTOR(GetPropertyByName) { // 3 : 3 input parameters - static StubDescriptor getPropertyByName("GetPropertyByName", 0, 3, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor getPropertyByName("GetPropertyByName", 0, 3, ArgumentsOrder::DEFAULT_ORDER, + MachineType::UINT64_TYPE); *descriptor = getPropertyByName; // 3 : 3 input parameters std::array params = { - MachineType::UINT64_TYPE, - MachineType::UINT64_TYPE, - MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, MachineType::UINT64_TYPE, MachineType::UINT64_TYPE, }; descriptor->SetParameters(params.data()); } @@ -151,7 +215,7 @@ CALL_STUB_INIT_DESCRIPTOR(FindOwnProperty) {} CALL_STUB_INIT_DESCRIPTOR(FindOwnElement) { // 3 : 3 input parameters - static StubDescriptor findOwnElement("FindOwnElement", 0, 3, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor findOwnElement("FindOwnElement", 0, 3, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = findOwnElement; // 3 : 3 input parameters std::array params = { @@ -169,7 +233,7 @@ CALL_STUB_INIT_DESCRIPTOR(FindOwnProperty2) {} CALL_STUB_INIT_DESCRIPTOR(FindOwnElement2) { // 6 : 6 input parameters - static StubDescriptor findOwnElement2("FindOwnElement2", 0, 6, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor findOwnElement2("FindOwnElement2", 0, 6, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = findOwnElement2; // 6 : 6 input parameters std::array params = { @@ -182,7 +246,8 @@ CALL_STUB_INIT_DESCRIPTOR(FindOwnElement2) CALL_STUB_INIT_DESCRIPTOR(GetPropertyByIndex) { // 3 : 3 input parameters - static StubDescriptor getPropertyByIndex("GetPropertyByIndex", 0, 3, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor getPropertyByIndex("GetPropertyByIndex", 0, 3, ArgumentsOrder::DEFAULT_ORDER, + MachineType::UINT64_TYPE); *descriptor = getPropertyByIndex; // 3 : 3 input parameters std::array params = { @@ -196,7 +261,8 @@ CALL_STUB_INIT_DESCRIPTOR(GetPropertyByIndex) CALL_STUB_INIT_DESCRIPTOR(SetPropertyByIndex) { // 4 : 4 input parameters - static StubDescriptor setPropertyByIndex("SetPropertyByIndex", 0, 4, ArgumentsOrder::DEFAULT_ORDER, UINT64_TYPE); + StubDescriptor setPropertyByIndex("SetPropertyByIndex", 0, 4, ArgumentsOrder::DEFAULT_ORDER, + MachineType::UINT64_TYPE); *descriptor = setPropertyByIndex; // 4 : 4 input parameters std::array params = { @@ -208,10 +274,31 @@ CALL_STUB_INIT_DESCRIPTOR(SetPropertyByIndex) descriptor->SetParameters(params.data()); } +CALL_STUB_INIT_DESCRIPTOR(GetPropertyByValue) +{ + // 3 : 3 input parameters + StubDescriptor getPropertyByValue("GetPropertyByValue", 0, 3, + ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = getPropertyByValue; + // 3 : 3 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); +} + +CALL_STUB_INIT_DESCRIPTOR(SetPropertyByValue) +{ +} + + CALL_STUB_INIT_DESCRIPTOR(AddElementInternal) { // 5 : 5 input parameters - static StubDescriptor addElementInternal("AddElementInternal", 0, 5, ArgumentsOrder::DEFAULT_ORDER, BOOL_TYPE); + StubDescriptor addElementInternal("AddElementInternal", 0, 5, ArgumentsOrder::DEFAULT_ORDER, + MachineType::BOOL_TYPE); *descriptor = addElementInternal; // 5 : 5 input parameters std::array params = { @@ -222,10 +309,22 @@ CALL_STUB_INIT_DESCRIPTOR(AddElementInternal) descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); } +CALL_STUB_INIT_DESCRIPTOR(GetTaggedArrayPtrTest) +{ + StubDescriptor getTaggedArrayPtr("GetTaggedArrayPtrTest", 0, 1, ArgumentsOrder::DEFAULT_ORDER, + MachineType::TAGGED_POINTER_TYPE); + *descriptor = getTaggedArrayPtr; + std::array params = { + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); +} + CALL_STUB_INIT_DESCRIPTOR(CallSetter) { // 5 : 5 input parameters - static StubDescriptor callSetter("CallSetter", 0, 5, ArgumentsOrder::DEFAULT_ORDER, NONE_TYPE); + StubDescriptor callSetter("CallSetter", 0, 5, ArgumentsOrder::DEFAULT_ORDER, MachineType::BOOL_TYPE); *descriptor = callSetter; // 5 : 5 input parameters std::array params = { @@ -239,7 +338,7 @@ CALL_STUB_INIT_DESCRIPTOR(CallSetter) CALL_STUB_INIT_DESCRIPTOR(CallGetter) { // 3 : 3 input parameters - static StubDescriptor callGetter("CallGetter", 0, 3, ArgumentsOrder::DEFAULT_ORDER, NONE_TYPE); + StubDescriptor callGetter("CallGetter", 0, 3, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = callGetter; // 3 : 3 input parameters std::array params = { @@ -254,7 +353,7 @@ CALL_STUB_INIT_DESCRIPTOR(CallGetter) CALL_STUB_INIT_DESCRIPTOR(AccessorGetter) { // 3 : 3 input parameters - static StubDescriptor accessorGetter("AccessorGetter", 0, 3, ArgumentsOrder::DEFAULT_ORDER, NONE_TYPE); + StubDescriptor accessorGetter("AccessorGetter", 0, 3, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); *descriptor = accessorGetter; // 3 : 3 input parameters std::array params = { @@ -269,7 +368,7 @@ CALL_STUB_INIT_DESCRIPTOR(AccessorGetter) CALL_STUB_INIT_DESCRIPTOR(ThrowTypeError) { // 2 : 2 input parameters - static StubDescriptor throwTypeError("ThrowTypeError", 0, 2, ArgumentsOrder::DEFAULT_ORDER, NONE_TYPE); + StubDescriptor throwTypeError("ThrowTypeError", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::BOOL_TYPE); *descriptor = throwTypeError; // 2 : 2 input parameters std::array params = { @@ -283,7 +382,8 @@ CALL_STUB_INIT_DESCRIPTOR(ThrowTypeError) CALL_STUB_INIT_DESCRIPTOR(JSProxySetProperty) { // 6 : 6 input parameters - static StubDescriptor jsproxySetproperty("JSProxySetProperty", 0, 6, ArgumentsOrder::DEFAULT_ORDER, BOOL_TYPE); + StubDescriptor jsproxySetproperty("JSProxySetProperty", 0, 6, + ArgumentsOrder::DEFAULT_ORDER, MachineType::BOOL_TYPE); *descriptor = jsproxySetproperty; // 6 : 6 input parameters std::array params = { @@ -297,7 +397,7 @@ CALL_STUB_INIT_DESCRIPTOR(JSProxySetProperty) CALL_STUB_INIT_DESCRIPTOR(GetHash32) { // 2 : 2 input parameters - static StubDescriptor getHash32("GetHash32", 0, 2, ArgumentsOrder::DEFAULT_ORDER, UINT32_TYPE); + StubDescriptor getHash32("GetHash32", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT32_TYPE); *descriptor = getHash32; // 2 : 2 input parameters std::array params = { @@ -311,7 +411,8 @@ CALL_STUB_INIT_DESCRIPTOR(GetHash32) CALL_STUB_INIT_DESCRIPTOR(FindElementWithCache) { // 4 : 4 input parameters - static StubDescriptor findElementWithCache("FindElementWithCache", 0, 4, ArgumentsOrder::DEFAULT_ORDER, INT32_TYPE); + StubDescriptor findElementWithCache("FindElementWithCache", 0, 4, + ArgumentsOrder::DEFAULT_ORDER, MachineType::INT32_TYPE); *descriptor = findElementWithCache; std::array params = { // 4 : 4 input parameters MachineType::UINT64_TYPE, @@ -323,9 +424,43 @@ CALL_STUB_INIT_DESCRIPTOR(FindElementWithCache) descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); } +CALL_STUB_INIT_DESCRIPTOR(Execute) +{ + // 5 : 5 input parameters + StubDescriptor execute("Execute", 0, 5, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = execute; + std::array params = { // 5 : 5 input parameters + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT32_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); +} + +CALL_STUB_INIT_DESCRIPTOR(FunctionCallInternal) +{ + // 5 : 5 input parameters + StubDescriptor functionCallInternal("FunctionCallInternal", 0, 5, + ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = functionCallInternal; + std::array params = { // 5 : 5 input parameters + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT32_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); +} + CALL_STUB_INIT_DESCRIPTOR(StringGetHashCode) { - static StubDescriptor stringGetHashCode("StringGetHashCode", 0, 1, ArgumentsOrder::DEFAULT_ORDER, UINT32_TYPE); + StubDescriptor stringGetHashCode("StringGetHashCode", 0, 1, + ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT32_TYPE); *descriptor = stringGetHashCode; std::array params = { MachineType::UINT64_TYPE, @@ -334,6 +469,84 @@ CALL_STUB_INIT_DESCRIPTOR(StringGetHashCode) descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); } +CALL_STUB_INIT_DESCRIPTOR(SetValueWithBarrier) +{ + // 4 : 4 input parameters + static StubDescriptor SetValueWithBarrier("SetValueWithBarrier", 0, 4, + ArgumentsOrder::DEFAULT_ORDER, MachineType::NONE_TYPE); + *descriptor = SetValueWithBarrier; + // 4 : 4 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); +} + +CALL_STUB_INIT_DESCRIPTOR(NewInternalString) +{ + // 2 : 2 input parameters + StubDescriptor stringGetHashCode("NewInternalString", 0, 2, + ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT64_TYPE); + *descriptor = stringGetHashCode; + // 2 : 2 input parameters + std::array params = { + MachineType::UINT64_TYPE, + MachineType::UINT64_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::RUNTIME_STUB); +} + +CALL_STUB_INIT_DESCRIPTOR(FastLoadElement) +{ + // 2 : 2 input parameters + StubDescriptor fastLoadElement("FastLoadElement", 0, 2, ArgumentsOrder::DEFAULT_ORDER, MachineType::TAGGED_TYPE); + *descriptor = fastLoadElement; + std::array params = { // 2 : 2 input parameters + MachineType::UINT64_TYPE, + MachineType::UINT32_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::TEST_FUNC); +} + +CALL_STUB_INIT_DESCRIPTOR(PhiGateTest) +{ + StubDescriptor phiGateTest("PhiGateTest", 0, 1, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT32_TYPE); + *descriptor = phiGateTest; + std::array params = { + MachineType::UINT32_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::TEST_FUNC); +} + +CALL_STUB_INIT_DESCRIPTOR(LoopTest) +{ + StubDescriptor loopTest("LoopTest", 0, 1, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT32_TYPE); + *descriptor = loopTest; + std::array params = { + MachineType::UINT32_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::TEST_FUNC); +} + +CALL_STUB_INIT_DESCRIPTOR(LoopTest1) +{ + StubDescriptor loopTest1("LoopTest1", 0, 1, ArgumentsOrder::DEFAULT_ORDER, MachineType::UINT32_TYPE); + *descriptor = loopTest1; + std::array params = { + MachineType::UINT32_TYPE, + }; + descriptor->SetParameters(params.data()); + descriptor->SetStubKind(StubDescriptor::CallStubKind::TEST_FUNC); +} + void FastStubDescriptors::InitializeStubDescriptors() { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) diff --git a/ecmascript/compiler/stub_descriptor.h b/ecmascript/compiler/stub_descriptor.h index c921dac73b3498be1f8720454b243d9288f76a4f..57823d82060f379e46b5b257c8f5e2fde31a48c8 100644 --- a/ecmascript/compiler/stub_descriptor.h +++ b/ecmascript/compiler/stub_descriptor.h @@ -33,6 +33,7 @@ public: enum class CallStubKind { CODE_STUB, RUNTIME_STUB, + TEST_FUNC, }; explicit StubDescriptor(std::string name, int flags, int paramCounter, ArgumentsOrder order, MachineType returnType) diff --git a/ecmascript/compiler/tests/BUILD.gn b/ecmascript/compiler/tests/BUILD.gn index 5268dae914decba60e314dc37f00abe35926acc5..2035a339b81ac2c99f64f9306eb86b8d06fa6a40 100644 --- a/ecmascript/compiler/tests/BUILD.gn +++ b/ecmascript/compiler/tests/BUILD.gn @@ -113,7 +113,7 @@ host_unittest_action("StubTest") { deps = [ "$ark_root/libpandabase:libarkbase", - "//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer_test", + "//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer_test(${host_toolchain})", sdk_libc_secshared_dep, ] } diff --git a/ecmascript/compiler/tests/stub_tests.cpp b/ecmascript/compiler/tests/stub_tests.cpp index c684a94da8171bc183ae22d099ac1600159fd5d8..0ad470c698a00c55b81a93399f3ef0986c44f175 100644 --- a/ecmascript/compiler/tests/stub_tests.cpp +++ b/ecmascript/compiler/tests/stub_tests.cpp @@ -17,10 +17,11 @@ #include #include "gtest/gtest.h" +#include "ecmascript/builtins/builtins_promise_handler.h" #include "ecmascript/compiler/fast_stub.h" +#include "ecmascript/compiler/llvm_codegen.h" #include "ecmascript/compiler/llvm_ir_builder.h" -#include "ecmascript/compiler/llvm_mcjit_engine.h" -#include "ecmascript/compiler/llvm_stackmap_parse.h" +#include "ecmascript/compiler/llvm/llvm_stackmap_parser.h" #include "ecmascript/compiler/scheduler.h" #include "ecmascript/compiler/stub_descriptor.h" #include "ecmascript/compiler/verifier.h" @@ -41,6 +42,7 @@ namespace panda::test { using namespace panda::coretypes; using namespace panda::ecmascript; using namespace kungfu; +using BuiltinsPromiseHandler = builtins::BuiltinsPromiseHandler; class StubTest : public testing::Test { public: @@ -55,29 +57,28 @@ public: TestHelper::DestroyEcmaVMWithScope(instance, scope); } - JSTaggedValue FastMul2(JSTaggedValue x, JSTaggedValue y) + void PrintCircuitByBasicBlock(const std::vector> &cfg, const Circuit &netOfGates) { - return FastRuntimeStub::FastMul(x, y); + for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { + std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" + << std::endl; + for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { + netOfGates.Print(cfg[bbIdx][instIdx - 1]); + } + } } PandaVM *instance {nullptr}; EcmaHandleScope *scope {nullptr}; JSThread *thread {nullptr}; - LLVMStubModule stubModule{"fast_stub"}; + LLVMStubModule stubModule {"fast_stub", "x86_64-unknown-linux-gnu"}; }; + HWTEST_F_L0(StubTest, FastLoadElement) { - auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); - LLVMModuleRef module = LLVMModuleCreateWithName("simple_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMPointerType(LLVMInt64Type(), 0), - LLVMInt32Type(), - }; - LLVMValueRef function = - // 2 : parameter number - LLVMAddFunction(module, "FastLoadElement", LLVMFunctionType(LLVMInt64Type(), paramTys, 2, 0)); + auto module = stubModule.GetModule(); + auto function = stubModule.GetTestFunction(FAST_STUB_ID(FastLoadElement)); Circuit netOfGates; FastArrayLoadElementStub optimizer(&netOfGates); optimizer.GenerateCircuit(); @@ -85,35 +86,24 @@ HWTEST_F_L0(StubTest, FastLoadElement) bool result = Verifier::Run(&netOfGates); ASSERT_TRUE(result); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - /* exec function */ - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); - // 5 : 5 means that there are 5 cases in total. - JSHandle values(factory->NewTaggedArray(5)); - // 5 : 5 means that there are 5 cases in total. - for (int i = 0; i < 5; i++) { + // Testcase build and run + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); + auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); + JSHandle values(factory->NewTaggedArray(5)); // 5 : 5 elements in array + for (int i = 0; i < 5; i++) { // 5 : 5 elements in array values->Set(thread, i, JSTaggedValue(i)); } JSHandle array(JSArray::CreateArrayFromList(thread, values)); JSArray *arr = array.GetObject(); auto valValid = fn(arr, 1); EXPECT_EQ(valValid, 0xffff000000000001); - // 6 : size of array - auto valUndefine = fn(arr, 6); + auto valUndefine = fn(arr, 6); // 6 : size of array EXPECT_EQ(valUndefine, 0xa); - std::cerr << "valValid = " << std::hex << valValid << std::endl; - std::cerr << "valUndefine = " << std::hex << valUndefine << std::endl; } class PhiStub : public Stub { @@ -125,18 +115,18 @@ public: void GenerateCircuit() override { auto env = GetEnvironment(); - DEFVARIABLE(z, MachineType::INT32_TYPE, GetInteger32Constant(0)); + DEFVARIABLE(z, MachineType::INT32_TYPE, GetInt32Constant(0)); DEFVARIABLE(x, MachineType::INT32_TYPE, Int32Argument(0)); Label ifTrue(env); Label ifFalse(env); Label next(env); - Branch(Word32Equal(*x, GetInteger32Constant(10)), &ifTrue, &ifFalse); // 10 : size of entry + Branch(Word32Equal(*x, GetInt32Constant(10)), &ifTrue, &ifFalse); // 10 : size of entry Bind(&ifTrue); - z = Int32Add(*x, GetInteger32Constant(10)); // 10 : size of entry + z = Int32Add(*x, GetInt32Constant(10)); // 10 : size of entry Jump(&next); - Bind(&ifFalse); // else - z = Int32Add(*x, GetInteger32Constant(100)); // 100 : size of entry + Bind(&ifFalse); + z = Int32Add(*x, GetInt32Constant(100)); // 100 : size of entry Jump(&next); Bind(&next); Return(*z); @@ -145,64 +135,26 @@ public: HWTEST_F_L0(StubTest, PhiGateTest) { - std::cout << "---------------------PhiGateTest-----------------------------------------------------" << std::endl; - LLVMModuleRef module = LLVMModuleCreateWithName("simple_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMInt32Type(), - }; - LLVMValueRef function = LLVMAddFunction(module, "PhiGateTest", LLVMFunctionType(LLVMInt32Type(), paramTys, 1, 0)); + auto module = stubModule.GetModule(); + auto function = stubModule.GetTestFunction(FAST_STUB_ID(PhiGateTest)); Circuit netOfGates; PhiStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - /* exec function */ - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); - auto val = fn(3); // 3 : size of array - auto val2 = fn(0); - std::cout << "val = " << std::dec << val << std::endl; - std::cout << "val2 = " << std::dec << val2 << std::endl; - std::cout << "+++++++++++++++++++++PhiGateTest+++++++++++++++++++++++++++++++++++++++++++++++++++++" << std::endl; + // Testcase build and run + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); + auto valA = fn(3); // 3 : size of array + auto valB = fn(0); + EXPECT_EQ(valA, 103); // 103 : eXpert res for fn(3) + EXPECT_EQ(valB, 100); // 100 : eXpert res for fn(0) } -class CallPhiStub : public Stub { -public: - explicit CallPhiStub(Circuit *circuit) - : Stub("CallPhi", 1, circuit), - phi_descriptor_("phi", 0, 1, ArgumentsOrder::DEFAULT_ORDER, MachineType::INT32_TYPE) - { - std::array *params = new std::array(); - (*params)[0] = MachineType::INT32_TYPE; - phi_descriptor_.SetParameters(params->data()); - } - ~CallPhiStub() = default; - NO_MOVE_SEMANTIC(CallPhiStub); - NO_COPY_SEMANTIC(CallPhiStub); - void GenerateCircuit() override - { - DEFVARIABLE(x, MachineType::INT32_TYPE, Int32Argument(0)); - x = Int32Add(*x, GetInteger32Constant(1)); - AddrShift callFoo = CallStub(&phi_descriptor_, GetWord64Constant(0), {*x}); - Return(Int32Add(callFoo, GetInteger32Constant(1))); - } - -private: - StubDescriptor phi_descriptor_; -}; - class LoopStub : public Stub { public: explicit LoopStub(Circuit *circuit) : Stub("loop", 1, circuit) {} @@ -212,27 +164,27 @@ public: void GenerateCircuit() override { auto env = GetEnvironment(); - DEFVARIABLE(z, MachineType::INT32_TYPE, GetInteger32Constant(0)); + DEFVARIABLE(z, MachineType::INT32_TYPE, GetInt32Constant(0)); DEFVARIABLE(y, MachineType::INT32_TYPE, Int32Argument(0)); Label loopHead(env); Label loopEnd(env); Label afterLoop(env); - Branch(Int32LessThan(*y, GetInteger32Constant(10)), &loopHead, &afterLoop); // 10 : size of entry + Branch(Int32LessThan(*y, GetInt32Constant(10)), &loopHead, &afterLoop); // 10 : size of entry LoopBegin(&loopHead); Label ifTrue(env); Label ifFalse(env); Label next(env); - Branch(Word32Equal(Int32Argument(0), GetInteger32Constant(9)), &ifTrue, &ifFalse); // 9 : size of entry + Branch(Word32Equal(Int32Argument(0), GetInt32Constant(9)), &ifTrue, &ifFalse); // 9 : size of entry Bind(&ifTrue); - z = Int32Add(*y, GetInteger32Constant(10)); // 10 : size of entry - y = Int32Add(*z, GetInteger32Constant(1)); + z = Int32Add(*y, GetInt32Constant(10)); // 10 : size of entry + y = Int32Add(*z, GetInt32Constant(1)); Jump(&next); Bind(&ifFalse); - z = Int32Add(*y, GetInteger32Constant(100)); // 100 : size of entry + z = Int32Add(*y, GetInt32Constant(100)); // 100 : size of entry Jump(&next); Bind(&next); - y = Int32Add(*y, GetInteger32Constant(1)); - Branch(Int32LessThan(*y, GetInteger32Constant(10)), &loopEnd, &afterLoop); // 10 : size of entry + y = Int32Add(*y, GetInt32Constant(1)); + Branch(Int32LessThan(*y, GetInt32Constant(10)), &loopEnd, &afterLoop); // 10 : size of entry Bind(&loopEnd); LoopEnd(&loopHead); Bind(&afterLoop); @@ -242,38 +194,26 @@ public: HWTEST_F_L0(StubTest, LoopTest) { - LLVMModuleRef module = LLVMModuleCreateWithName("simple_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMInt32Type(), - }; - LLVMValueRef function = LLVMAddFunction(module, "LoopTest", LLVMFunctionType(LLVMInt32Type(), paramTys, 1, 0)); + auto module = stubModule.GetModule(); + auto function = stubModule.GetTestFunction(FAST_STUB_ID(LoopTest)); Circuit netOfGates; LoopStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t inst_idx = cfg[bbIdx].size(); inst_idx > 0; inst_idx--) { - netOfGates.Print(cfg[bbIdx][inst_idx - 1]); - } - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - - /* exec function */ - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); - auto resValid = fn(1); - auto resValid2 = fn(9); // 9 : size of array - auto resInvalid = fn(11); // 11 : size of array - std::cout << "res for loop(1) = " << std::dec << resValid << std::endl; - std::cout << "res for loop(9) = " << std::dec << resValid2 << std::endl; - std::cout << "res for loop(11) = " << std::dec << resInvalid << std::endl; + // Testcase build and run + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); + auto valA = fn(1); + auto valB = fn(9); // 9 : size of array + auto valC = fn(11); // 11 : size of array + EXPECT_EQ(valA, 109); // 109 : eXpert res for fn(1) + EXPECT_EQ(valB, 19); // 10 : eXpert res for fn(9) + EXPECT_EQ(valC, 0); } class LoopStub1 : public Stub { @@ -291,18 +231,18 @@ public: Label loopHead(env); Label loopEnd(env); Label afterLoop(env); - Branch(Int32LessThan(*y, GetInteger32Constant(10)), &loopHead, &afterLoop); // 10 : size of entry + Branch(Int32LessThan(*y, GetInt32Constant(10)), &loopHead, &afterLoop); // 10 : size of entry LoopBegin(&loopHead); - x = Int32Add(*z, GetInteger32Constant(3)); // 3 : size of entry + x = Int32Add(*z, GetInt32Constant(3)); // 3 : size of entry Label ifTrue(env); Label next(env); - Branch(Word32Equal(*x, GetInteger32Constant(9)), &ifTrue, &next); // 9 : size of entry + Branch(Word32Equal(*x, GetInt32Constant(9)), &ifTrue, &next); // 9 : size of entry Bind(&ifTrue); y = Int32Add(*z, *x); Jump(&next); Bind(&next); - y = Int32Add(*y, GetInteger32Constant(1)); - Branch(Int32LessThan(*y, GetInteger32Constant(10)), &loopEnd, &afterLoop); // 10 : size of entry + y = Int32Add(*y, GetInt32Constant(1)); + Branch(Int32LessThan(*y, GetInt32Constant(10)), &loopEnd, &afterLoop); // 10 : size of entry Bind(&loopEnd); LoopEnd(&loopHead); Bind(&afterLoop); @@ -313,8 +253,7 @@ public: HWTEST_F_L0(StubTest, LoopTest1) { - LLVMModuleRef module = LLVMModuleCreateWithName("simple_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); + auto module = stubModule.GetModule(); LLVMTypeRef paramTys[] = { LLVMInt32Type(), }; @@ -324,61 +263,47 @@ HWTEST_F_L0(StubTest, LoopTest1) optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); auto engine = assembler.GetEngine(); - /* exec function */ + // Testcase build and run auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); - auto resValid = fn(1); - auto resValid2 = fn(9); // 9 : size of array - auto resInvalid = fn(11); // 11 : size of array - std::cout << "res for loop1(1) = " << std::dec << resValid << std::endl; - std::cout << "res for loop1(9) = " << std::dec << resValid2 << std::endl; - std::cout << "res for loop1(11) = " << std::dec << resInvalid << std::endl; + auto valA = fn(1); + auto valB = fn(9); // 9 : size of array + auto valC = fn(11); // 11 : size of array + EXPECT_EQ(valA, 10); // 10 : eXpert res for fn(1) + EXPECT_EQ(valB, 10); // 10 : eXpert res for fn(9) + EXPECT_EQ(valC, 11); // 10 : eXpert res for fn(11) } HWTEST_F_L0(StubTest, FastAddTest) { - LLVMModuleRef module = LLVMModuleCreateWithName("fast_add_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMInt64Type(), - LLVMInt64Type(), - }; - LLVMValueRef function = LLVMAddFunction(module, "FastAddTest", LLVMFunctionType(LLVMInt64Type(), paramTys, 2, 0)); + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastAdd)); Circuit netOfGates; FastAddStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - /* exec function */ - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); - auto resValid = fn(JSTaggedValue(1).GetRawData(), JSTaggedValue(1).GetRawData()); - auto resValid2 = fn(JSTaggedValue(2).GetRawData(), JSTaggedValue(2).GetRawData()); // 2 : test case - auto resInvalid = fn(JSTaggedValue(11).GetRawData(), JSTaggedValue(11).GetRawData()); // 11 : test case - std::cout << "res for FastAdd(1, 1) = " << std::dec << resValid.GetNumber() << std::endl; - std::cout << "res for FastAdd(2, 2) = " << std::dec << resValid2.GetNumber() << std::endl; - std::cout << "res for FastAdd(11, 11) = " << std::dec << resInvalid.GetNumber() << std::endl; + // Testcase build and run + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); + auto resA = fn(JSTaggedValue(1).GetRawData(), JSTaggedValue(1).GetRawData()); + auto resB = fn(JSTaggedValue(2).GetRawData(), JSTaggedValue(2).GetRawData()); // 2 : test case + auto resC = fn(JSTaggedValue(11).GetRawData(), JSTaggedValue(11).GetRawData()); // 11 : test case + LOG_ECMA(INFO) << "res for FastAdd(1, 1) = " << resA.GetNumber(); + LOG_ECMA(INFO) << "res for FastAdd(2, 2) = " << resB.GetNumber(); + LOG_ECMA(INFO) << "res for FastAdd(11, 11) = " << resC.GetNumber(); + EXPECT_EQ(resA.GetNumber(), JSTaggedValue(2).GetNumber()); + EXPECT_EQ(resB.GetNumber(), JSTaggedValue(4).GetNumber()); + EXPECT_EQ(resC.GetNumber(), JSTaggedValue(22).GetNumber()); int x1 = 2147483647; int y1 = 15; auto resG = fn(JSTaggedValue(x1).GetRawData(), JSTaggedValue(y1).GetRawData()); @@ -388,75 +313,53 @@ HWTEST_F_L0(StubTest, FastAddTest) HWTEST_F_L0(StubTest, FastSubTest) { - LLVMModuleRef module = LLVMModuleCreateWithName("fast_sub_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMInt64Type(), - LLVMInt64Type(), - }; - LLVMValueRef function = LLVMAddFunction(module, "FastSubTest", LLVMFunctionType(LLVMInt64Type(), paramTys, 2, 0)); + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastSub)); Circuit netOfGates; FastSubStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - /* exec function */ - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); + // Testcase build and run + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); auto resA = fn(JSTaggedValue(2).GetRawData(), JSTaggedValue(1).GetRawData()); // 2 : test case auto resB = fn(JSTaggedValue(7).GetRawData(), JSTaggedValue(2).GetRawData()); // 7, 2 : test cases auto resC = fn(JSTaggedValue(11).GetRawData(), JSTaggedValue(11).GetRawData()); // 11 : test case - std::cout << "res for FastSub(2, 1) = " << std::dec << resA.GetNumber() << std::endl; - std::cout << "res for FastSub(7, 2) = " << std::dec << resB.GetNumber() << std::endl; - std::cout << "res for FastSub(11, 11) = " << std::dec << resC.GetNumber() << std::endl; + LOG_ECMA(INFO) << "res for FastSub(2, 1) = " << resA.GetNumber(); + LOG_ECMA(INFO) << "res for FastSub(7, 2) = " << resB.GetNumber(); + LOG_ECMA(INFO) << "res for FastSub(11, 11) = " << resC.GetNumber(); + EXPECT_EQ(resA, JSTaggedValue(1)); + EXPECT_EQ(resB, JSTaggedValue(5)); + EXPECT_EQ(resC, JSTaggedValue(0)); } HWTEST_F_L0(StubTest, FastMulTest) { - LLVMModuleRef module = LLVMModuleCreateWithName("fast_mul_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMInt64Type(), - LLVMInt64Type(), - }; - LLVMValueRef function = LLVMAddFunction(module, "FastMulTest", LLVMFunctionType(LLVMInt64Type(), paramTys, 2, 0)); + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastMul)); Circuit netOfGates; FastMulStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - - /* exec function */ - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); + // Testcase build and run + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); auto resA = fn(JSTaggedValue(-2).GetRawData(), JSTaggedValue(1).GetRawData()); // -2 : test case auto resB = fn(JSTaggedValue(-7).GetRawData(), JSTaggedValue(-2).GetRawData()); // -7, -2 : test case auto resC = fn(JSTaggedValue(11).GetRawData(), JSTaggedValue(11).GetRawData()); // 11 : test case - std::cout << "res for FastMul(-2, 1) = " << std::dec << resA.GetNumber() << std::endl; - std::cout << "res for FastMul(-7, -2) = " << std::dec << resB.GetNumber() << std::endl; - std::cout << "res for FastMul(11, 11) = " << std::dec << resC.GetNumber() << std::endl; + LOG_ECMA(INFO) << "res for FastMul(-2, 1) = " << std::dec << resA.GetNumber(); + LOG_ECMA(INFO) << "res for FastMul(-7, -2) = " << std::dec << resB.GetNumber(); + LOG_ECMA(INFO) << "res for FastMul(11, 11) = " << std::dec << resC.GetNumber(); int x = 7; double y = 1125899906842624; auto resD = fn(JSTaggedValue(x).GetRawData(), JSTaggedValue(y).GetRawData()); @@ -481,141 +384,182 @@ HWTEST_F_L0(StubTest, FastMulTest) HWTEST_F_L0(StubTest, FastDivTest) { - LLVMModuleRef module = LLVMModuleCreateWithName("fast_div_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMInt64Type(), - LLVMInt64Type(), - }; - LLVMValueRef function = LLVMAddFunction(module, "FastDiv", LLVMFunctionType(LLVMInt64Type(), paramTys, 2, 0)); + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastDiv)); Circuit netOfGates; FastDivStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); - + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); // test normal Division operation uint64_t x1 = JSTaggedValue(50).GetRawData(); uint64_t y1 = JSTaggedValue(25).GetRawData(); - std::cout << "x1 = " << x1 << " y1 = " << y1 << std::endl; + LOG_ECMA(INFO) << "x1 = " << x1 << " y1 = " << y1; auto res1 = fn(x1, y1); - std::cout << "res for FastDiv(50, 25) = " << res1.GetRawData() << std::endl; + LOG_ECMA(INFO) << "res for FastDiv(50, 25) = " << res1.GetRawData(); auto expectedG1 = FastRuntimeStub::FastDiv(JSTaggedValue(x1), JSTaggedValue(y1)); EXPECT_EQ(res1, expectedG1); // test x == 0.0 or std::isnan(x) uint64_t x2 = JSTaggedValue(base::NAN_VALUE).GetRawData(); uint64_t y2 = JSTaggedValue(0).GetRawData(); - std::cout << "x2 = " << x1 << " y2 = " << y2 << std::endl; + LOG_ECMA(INFO) << "x2 = " << x1 << " y2 = " << y2; auto res2 = fn(x2, y2); - std::cout << "res for FastDiv(base::NAN_VALUE, 0) = " << res2.GetRawData() << std::endl; + LOG_ECMA(INFO) << "res for FastDiv(base::NAN_VALUE, 0) = " << res2.GetRawData(); auto expectedG2 = FastRuntimeStub::FastDiv(JSTaggedValue(x2), JSTaggedValue(y2)); EXPECT_EQ(res2, expectedG2); // test other uint64_t x3 = JSTaggedValue(7).GetRawData(); uint64_t y3 = JSTaggedValue(0).GetRawData(); - std::cout << "x2 = " << x3 << " y2 = " << y3 << std::endl; + LOG_ECMA(INFO) << "x2 = " << x3 << " y2 = " << y3; auto res3 = fn(x3, y3); - std::cout << "res for FastDiv(7, 0) = " << res3.GetRawData() << std::endl; + LOG_ECMA(INFO) << "res for FastDiv(7, 0) = " << res3.GetRawData(); auto expectedG3 = FastRuntimeStub::FastDiv(JSTaggedValue(x3), JSTaggedValue(y3)); EXPECT_EQ(res3, expectedG3); } +HWTEST_F_L0(StubTest, FastModTest) +{ + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastMod)); + Circuit netOfGates; + FastModStub optimizer(&netOfGates); + optimizer.GenerateCircuit(); + netOfGates.PrintAllGates(); + auto cfg = Scheduler::Run(&netOfGates); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); + llvmBuilder.Build(); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); + assembler.Run(); + LLVMDumpModule(module); + auto engine = assembler.GetEngine(); + uint64_t stub1Code = LLVMGetFunctionAddress(engine, "FastModStub"); + std::map addr2name = {{stub1Code, "stub1"}}; + assembler.Disassemble(addr2name); + auto fn = reinterpret_cast( + assembler.GetFuncPtrFromCompiledModule(function)); + // test left, right are all integer + int x = 7; + int y = 3; + auto result = fn(thread, JSTaggedValue(x).GetRawData(), JSTaggedValue(y).GetRawData()); + JSTaggedValue expectRes = FastRuntimeStub::FastMod(JSTaggedValue(x), JSTaggedValue(y)); + EXPECT_EQ(result, expectRes); + + // test y == 0.0 || std::isnan(y) || std::isnan(x) || std::isinf(x) return NAN_VALUE + double x2 = 7.3; + int y2 = base::NAN_VALUE; + auto result2 = fn(thread, JSTaggedValue(x2).GetRawData(), JSTaggedValue(y2).GetRawData()); + auto expectRes2 = FastRuntimeStub::FastMod(JSTaggedValue(x2), JSTaggedValue(y2)); + EXPECT_EQ(result2, expectRes2); + LOG_ECMA(INFO) << "result2 for FastMod(7, 'helloworld') = " << result2.GetRawData(); + LOG_ECMA(INFO) << "expectRes2 for FastMod(7, 'helloworld') = " << expectRes2.GetRawData(); + + // // test modular operation under normal conditions + double x3 = 33.0; + double y3 = 44.0; + auto result3 = fn(thread, JSTaggedValue(x3).GetRawData(), JSTaggedValue(y3).GetRawData()); + auto expectRes3 = FastRuntimeStub::FastMod(JSTaggedValue(x3), JSTaggedValue(y3)); + EXPECT_EQ(result3, expectRes3); + + // test x == 0.0 || std::isinf(y) return x + double x4 = base::NAN_VALUE; + int y4 = 7; + auto result4 = fn(thread, JSTaggedValue(x4).GetRawData(), JSTaggedValue(y4).GetRawData()); + auto expectRes4 = FastRuntimeStub::FastMod(JSTaggedValue(x4), JSTaggedValue(y4)); + + LOG_ECMA(INFO) << "result4 for FastMod(base::NAN_VALUE, 7) = " << result4.GetRawData(); + LOG_ECMA(INFO) << "expectRes4 for FastMod(base::NAN_VALUE, 7) = " << expectRes4.GetRawData(); + EXPECT_EQ(result4, expectRes4); + + // test all non-conforming conditions + int x5 = 7; + auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); + auto y5 = factory->NewFromStdString("hello world"); + auto result5 = fn(thread, JSTaggedValue(x5).GetRawData(), y5.GetTaggedValue().GetRawData()); + EXPECT_EQ(result5, JSTaggedValue::Hole()); + auto expectRes5 = FastRuntimeStub::FastMod(JSTaggedValue(x5), y5.GetTaggedValue()); + LOG_ECMA(INFO) << "result1 for FastMod(7, 'helloworld') = " << result5.GetRawData(); + EXPECT_EQ(result5, expectRes5); +} + HWTEST_F_L0(StubTest, FastFindOwnElementStub) { auto module = stubModule.GetModule(); - LLVMValueRef findFunction = LLVMGetNamedFunction(module, "FindOwnElement"); + auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(FindOwnElement)); Circuit netOfGates; - FastFindOwnElementStub optimizer(&netOfGates); + FindOwnElementStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } + PrintCircuitByBasicBlock(cfg, netOfGates); LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); } -HWTEST_F_L0(StubTest, FastGetElementStub) +HWTEST_F_L0(StubTest, FunctionCallInternal) { auto module = stubModule.GetModule(); - LLVMValueRef findFunction = LLVMGetNamedFunction(module, "FindOwnElement"); + auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(FunctionCallInternal)); Circuit netOfGates; - FastFindOwnElementStub findOptimizer(&netOfGates); + FunctionCallInternalStub optimizer(&netOfGates); + optimizer.GenerateCircuit(); + netOfGates.PrintAllGates(); + auto cfg = Scheduler::Run(&netOfGates); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction); + llvmBuilder.Build(); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); + assembler.Run(); +} + +HWTEST_F_L0(StubTest, GetElementStub) +{ + auto module = stubModule.GetModule(); + auto findFunction = stubModule.GetStubFunction(FAST_STUB_ID(FindOwnElement)); + Circuit netOfGates; + FindOwnElementStub findOptimizer(&netOfGates); findOptimizer.GenerateCircuit(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, findFunction); llvmBuilder.Build(); Circuit getNetOfGates; - FastGetElementStub getOptimizer(&getNetOfGates); + GetElementStub getOptimizer(&getNetOfGates); getOptimizer.GenerateCircuit(); getNetOfGates.PrintAllGates(); auto getCfg = Scheduler::Run(&getNetOfGates); - for (size_t bbIdx = 0; bbIdx < getCfg.size(); bbIdx++) { - std::cout << (getNetOfGates.GetOpCode(getCfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = getCfg[bbIdx].size(); instIdx > 0; instIdx--) { - getNetOfGates.Print(getCfg[bbIdx][instIdx - 1]); - } - } + PrintCircuitByBasicBlock(getCfg, getNetOfGates); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); } -HWTEST_F_L0(StubTest, FastFindOwnElement2Stub) +HWTEST_F_L0(StubTest, FindOwnElement2Stub) { - std::cout << " ------------------------FastFindOwnElement2Stub ---------------------" << std::endl; auto module = stubModule.GetModule(); - LLVMValueRef function = LLVMGetNamedFunction(module, "FindOwnElement2"); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FindOwnElement2)); Circuit netOfGates; - FastFindOwnElement2Stub optimizer(&netOfGates); + FindOwnElement2Stub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } + PrintCircuitByBasicBlock(cfg, netOfGates); LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); auto *findOwnElement2Ptr = reinterpret_cast( - reinterpret_cast(LLVMGetPointerToGlobal(engine, function))); + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function))); auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); int x = 213; @@ -631,28 +575,21 @@ HWTEST_F_L0(StubTest, FastFindOwnElement2Stub) EXPECT_EQ(resVal.GetNumber(), x); resVal = findOwnElement2Ptr(thread, elements, 10250, isDict, &attr, &indexOrEntry); EXPECT_EQ(resVal.GetNumber(), y); - std::cout << " ++++++++++++++++++++FastFindOwnElement2Stub ++++++++++++++++++" << std::endl; } HWTEST_F_L0(StubTest, SetElementStub) { auto module = stubModule.GetModule(); - LLVMValueRef function = LLVMGetNamedFunction(module, "SetElement"); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(SetElement)); Circuit netOfGates; - FastSetElementStub optimizer(&netOfGates); + SetElementStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } + PrintCircuitByBasicBlock(cfg, netOfGates); LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); } @@ -720,6 +657,27 @@ int RuntimeFunc2(struct ThreadTy *fpInfo) for (int i = 0; i < 40; i++) { // print 40 ptr value for debug std::cout << std::hex << &(rbp[i]) << " :" << rbp[i] << std::endl; } + /* walk back + stack frame: 0 pre rbp <-- rbp + -8 type + -16 pre frame thread fp + */ + int64_t *frameType = nullptr; + int64_t *gcFp = nullptr; + std::cout << "-----------------walkback----------------" << std::endl; + do { + frameType = rbp - 1; + if (*frameType == 1) { + gcFp = rbp - 2; // 2: 2 stack slot + } else { + gcFp = rbp; + } + rbp = reinterpret_cast(*gcFp); + std::cout << std::hex << "frameType :" << *frameType << " gcFp:" << *gcFp << std::endl; + } while (*gcFp != 0); + std::cout << "+++++++++++++++++walkback++++++++++++++++" << std::endl; + std::cout << "call RuntimeFunc2 func ThreadTy fp: " << fpInfo->fp << " magic:" << fpInfo->magic << std::endl; + std::cout << "RuntimeFunc2 +" << std::endl; return 0; } } @@ -770,7 +728,7 @@ LLVMValueRef LLVMCallingFp(LLVMModuleRef &module, LLVMBuilderRef &builder) return frameAddr; } -#ifdef LLVM_SUPPORT_GC +#ifdef ARK_GC_SUPPORT HWTEST_F_L0(StubTest, JSEntryTest) { std::cout << " ---------- JSEntryTest ------------- " << std::endl; @@ -801,10 +759,7 @@ HWTEST_F_L0(StubTest, JSEntryTest) LLVMBasicBlockRef entryBb = LLVMAppendBasicBlock(stub1, "entry"); LLVMPositionBuilderAtEnd(builder, entryBb); - /* struct ThreadTy fpInfo; - fpInfo.magic = 0x11223344; - fpInfo.fp = calling frame address - */ + LLVMValueRef value = LLVMGetParam(stub1, 0); LLVMValueRef c0 = LLVMConstInt(LLVMInt32Type(), 0, false); LLVMValueRef c1 = LLVMConstInt(LLVMInt32Type(), 1, false); @@ -843,8 +798,8 @@ HWTEST_F_L0(StubTest, JSEntryTest) entryBb = LLVMAppendBasicBlock(stub2, "entry"); LLVMPositionBuilderAtEnd(builder, entryBb); LLVMValueRef value2 = LLVMGetParam(stub2, 0); - /* struct ThreadTy fpInfo; - fpInfo.fp = calling frame address + /* ThreadTy fpInfo struct; + fpInfo.fp assign calling frame address */ gep2 = LLVMBuildGEP2(builder, threadTy, value2, indexes2.data(), indexes2.size(), "fpAddr"); frameAddr = LLVMCallingFp(module, builder); @@ -873,8 +828,8 @@ HWTEST_F_L0(StubTest, JSEntryTest) entryBb = LLVMAppendBasicBlock(stub3, "entry"); LLVMPositionBuilderAtEnd(builder, entryBb); LLVMValueRef value3 = LLVMGetParam(stub3, 0); - /* struct ThreadTy fpInfo; - fpInfo.fp = calling frame address + /* ThreadTy fpInfo + fpInfo.fp set calling frame address */ gep2 = LLVMBuildGEP2(builder, threadTy, value3, indexes2.data(), indexes2.size(), "fpAddr"); /* current frame @@ -891,7 +846,7 @@ HWTEST_F_L0(StubTest, JSEntryTest) char *error = nullptr; LLVMVerifyModule(module, LLVMAbortProcessAction, &error); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); auto engine = assembler.GetEngine(); uint64_t stub1Code = LLVMGetFunctionAddress(engine, "stub1"); @@ -965,7 +920,7 @@ HWTEST_F_L0(StubTest, Prologue) char *error = nullptr; LLVMVerifyModule(module, LLVMAbortProcessAction, &error); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); auto engine = assembler.GetEngine(); uint64_t mainCode = LLVMGetFunctionAddress(engine, "main"); @@ -1002,10 +957,7 @@ HWTEST_F_L0(StubTest, CEntryFp) LLVMAddTargetDependentFunctionAttr(func, "js-stub-call", "1"); LLVMBasicBlockRef entryBb = LLVMAppendBasicBlock(func, "entry"); LLVMPositionBuilderAtEnd(builder, entryBb); - /* struct ThreadTy fpInfo; - fpInfo.magic = 0x11223344; - fpInfo.fp = calling frame address - */ + LLVMValueRef value = LLVMGetParam(func, 0); LLVMValueRef c0 = LLVMConstInt(LLVMInt32Type(), 0, false); @@ -1044,7 +996,7 @@ HWTEST_F_L0(StubTest, CEntryFp) char *error = nullptr; LLVMVerifyModule(module, LLVMAbortProcessAction, &error); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); auto engine = assembler.GetEngine(); uint64_t nativeCode = LLVMGetFunctionAddress(engine, "main"); @@ -1062,7 +1014,7 @@ HWTEST_F_L0(StubTest, LoadGCIRTest) { std::cout << "--------------LoadGCIRTest--------------------" << std::endl; char *path = get_current_dir_name(); - std::string filePath = std::string(path) + "/../../ark/js_runtime/ecmascript/compiler/tests/satepoint_GC_0.ll"; + std::string filePath = std::string(path) + "/ark/js_runtime/ecmascript/compiler/tests/satepoint_GC_0.ll"; char resolvedPath[PATH_MAX]; char *res = realpath(filePath.c_str(), resolvedPath); @@ -1078,10 +1030,11 @@ HWTEST_F_L0(StubTest, LoadGCIRTest) std::unique_ptr rawModule = parseIRFile(inputFilename, err, context); if (!rawModule) { std::cout << "parseIRFile :" << inputFilename.data() << " failed !" << std::endl; + err.print("parseIRFile ", llvm::errs()); return; } LLVMModuleRef module = LLVMCloneModule(wrap(rawModule.get())); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); auto engine = assembler.GetEngine(); LLVMValueRef function = LLVMGetNamedFunction(module, "main"); @@ -1089,8 +1042,8 @@ HWTEST_F_L0(StubTest, LoadGCIRTest) auto *mainPtr = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); uint8_t *ptr = assembler.GetStackMapsSection(); - LLVMStackMapParse::GetInstance().CalculateStackMap(ptr); - LLVMStackMapParse::GetInstance().Print(); + LLVMStackMapParser::GetInstance().CalculateStackMap(ptr); + LLVMStackMapParser::GetInstance().Print(); assembler.Disassemble(); LLVMDumpModule(module); @@ -1108,19 +1061,21 @@ void DoSafepoint() uintptr_t returnAddr = *(rbp + 1); uintptr_t *rsp = rbp + 2; // move 2 steps from rbp to get rsp rbp = reinterpret_cast(*rbp); - DwarfRegAndOffsetType info; - bool found = LLVMStackMapParse::GetInstance().StackMapByAddr(returnAddr, info); + DwarfRegAndOffsetTypeVector infos; + bool found = LLVMStackMapParser::GetInstance().StackMapByAddr(returnAddr, infos); if (found) { - uintptr_t **address = nullptr; - if (info.first == 7) { // 7: x86_64 dwarf register num, representing rsp - address = reinterpret_cast(reinterpret_cast(rsp) + info.second); - // rbp - } else if (info.first == 6) { // 6: x86_64 dwarf register num, representing rbp - address = reinterpret_cast(reinterpret_cast(rbp) + info.second); + for (auto &info : infos) { + uintptr_t **address = nullptr; + if (info.first == SP_DWARF_REG_NUM) { + address = reinterpret_cast(reinterpret_cast(rsp) + info.second); + } else if (info.first == FP_DWARF_REG_NUM) { + address = reinterpret_cast(reinterpret_cast(rbp) + info.second); + } + // print ref and vlue for debug + std::cout << std::hex << "ref addr:" << address; + std::cout << " value:" << *address; + std::cout << " *value :" << **address << std::endl; } - std::cout << std::hex << "ref addr:" << address; - std::cout << " value:" << *address; - std::cout << " *value :" << **address << std::endl; } std::cout << std::endl << std::endl; std::cout << std::hex << "+++++++++++++++++++ returnAddr : 0x" << returnAddr << " rbp:" << rbp @@ -1130,29 +1085,22 @@ void DoSafepoint() } } -HWTEST_F_L0(StubTest, FastGetPropertyByIndexStub) +HWTEST_F_L0(StubTest, GetPropertyByIndexStub) { auto module = stubModule.GetModule(); - LLVMValueRef function = LLVMGetNamedFunction(module, "GetPropertyByIndex"); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByIndex)); Circuit netOfGates; - FastGetPropertyByIndexStub optimizer(&netOfGates); + GetPropertyByIndexStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } + PrintCircuitByBasicBlock(cfg, netOfGates); LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); auto *getpropertyByIndex = reinterpret_cast( - reinterpret_cast(LLVMGetPointerToGlobal(engine, function))); + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function))); auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); int x = 213; @@ -1166,31 +1114,24 @@ HWTEST_F_L0(StubTest, FastGetPropertyByIndexStub) EXPECT_EQ(resVal.GetNumber(), y); } -HWTEST_F_L0(StubTest, FastSetPropertyByIndexStub) +HWTEST_F_L0(StubTest, SetPropertyByIndexStub) { auto module = stubModule.GetModule(); - LLVMValueRef function = LLVMGetNamedFunction(module, "SetPropertyByIndex"); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(SetPropertyByIndex)); Circuit netOfGates; - FastSetPropertyByIndexStub optimizer(&netOfGates); + SetPropertyByIndexStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); bool result = Verifier::Run(&netOfGates); ASSERT_TRUE(result); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } + PrintCircuitByBasicBlock(cfg, netOfGates); LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); auto *setpropertyByIndex = reinterpret_cast( - reinterpret_cast(LLVMGetPointerToGlobal(engine, function))); + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function))); auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); JSHandle array = factory->NewJSArray(); assembler.Disassemble(); @@ -1206,31 +1147,24 @@ HWTEST_F_L0(StubTest, FastSetPropertyByIndexStub) } } -HWTEST_F_L0(StubTest, FastGetPropertyByNameStub) +HWTEST_F_L0(StubTest, GetPropertyByNameStub) { auto module = stubModule.GetModule(); - LLVMValueRef function = LLVMGetNamedFunction(module, "GetPropertyByName"); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByName)); Circuit netOfGates; - FastGetPropertyByNameStub optimizer(&netOfGates); + GetPropertyByNameStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); bool result = Verifier::Run(&netOfGates); ASSERT_TRUE(result); auto cfg = Scheduler::Run(&netOfGates); - for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { - std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" - << std::endl; - for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { - netOfGates.Print(cfg[bbIdx][instIdx - 1]); - } - } + PrintCircuitByBasicBlock(cfg, netOfGates); LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); auto *getPropertyByNamePtr = reinterpret_cast( - reinterpret_cast(LLVMGetPointerToGlobal(engine, function))); + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function))); auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); JSHandle obj = factory->NewEmptyJSObject(); int x = 213; @@ -1247,75 +1181,246 @@ HWTEST_F_L0(StubTest, FastGetPropertyByNameStub) EXPECT_EQ(resVal.GetNumber(), y); } -HWTEST_F_L0(StubTest, FastModTest) +HWTEST_F_L0(StubTest, GetPropertyByValueStub) { - LLVMModuleRef module = LLVMModuleCreateWithName("fast_mod_module"); - LLVMSetTarget(module, "x86_64-unknown-linux-gnu"); - LLVMTypeRef paramTys[] = { - LLVMInt64Type(), - LLVMInt64Type(), - }; - LLVMValueRef function = LLVMAddFunction(module, "FastMod", LLVMFunctionType(LLVMInt64Type(), paramTys, 2, 0)); + auto module = stubModule.GetModule(); + LLVMValueRef getPropertyByIndexfunction = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByIndex)); + Circuit netOfGates2; + GetPropertyByIndexStub getPropertyByIndexStub(&netOfGates2); + getPropertyByIndexStub.GenerateCircuit(); + netOfGates2.PrintAllGates(); + auto cfg2 = Scheduler::Run(&netOfGates2); + LLVMIRBuilder llvmBuilder2(&cfg2, &netOfGates2, &stubModule, getPropertyByIndexfunction); + llvmBuilder2.Build(); + + LLVMValueRef getPropertyByNamefunction = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByName)); + Circuit netOfGates1; + GetPropertyByNameStub getPropertyByNameStub(&netOfGates1); + getPropertyByNameStub.GenerateCircuit(); + bool result = Verifier::Run(&netOfGates1); + ASSERT_TRUE(result); + auto cfg1 = Scheduler::Run(&netOfGates1); + LLVMIRBuilder llvmBuilder1(&cfg1, &netOfGates1, &stubModule, getPropertyByNamefunction); + llvmBuilder1.Build(); + + LLVMValueRef function = stubModule.GetStubFunction(FAST_STUB_ID(GetPropertyByValue)); Circuit netOfGates; - FastModStub optimizer(&netOfGates); + GetPropertyByValueStub optimizer(&netOfGates); optimizer.GenerateCircuit(); netOfGates.PrintAllGates(); + result = Verifier::Run(&netOfGates); + ASSERT_TRUE(result); auto cfg = Scheduler::Run(&netOfGates); for (size_t bbIdx = 0; bbIdx < cfg.size(); bbIdx++) { std::cout << (netOfGates.GetOpCode(cfg[bbIdx].front()).IsCFGMerge() ? "MERGE_" : "BB_") << bbIdx << ":" << std::endl; - for (size_t instIdex = cfg[bbIdx].size(); instIdex < 0; instIdex--) { - netOfGates.Print(cfg[bbIdx][instIdex - 1]); + for (size_t instIdx = cfg[bbIdx].size(); instIdx > 0; instIdx--) { + netOfGates.Print(cfg[bbIdx][instIdx - 1]); } } - LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, module, function); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); llvmBuilder.Build(); - LLVMAssembler assembler(module); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); assembler.Run(); - auto engine = assembler.GetEngine(); - auto fn = reinterpret_cast(LLVMGetPointerToGlobal(engine, function)); + auto *getPropertyByValuePtr = reinterpret_cast( + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function))); + auto *getPropertyByNamePtr = reinterpret_cast( + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(getPropertyByNamefunction))); + auto *getpropertyByIndexPtr = reinterpret_cast( + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(getPropertyByIndexfunction))); - // test left, right are all integer - int x = 7; - int y = 3; - auto result = fn(JSTaggedValue(x).GetRawData(), JSTaggedValue(y).GetRawData()); - JSTaggedValue expectRes = FastRuntimeStub::FastMod(JSTaggedValue(x), JSTaggedValue(y)); - EXPECT_EQ(result, expectRes); + thread->SetFastStubEntry(FAST_STUB_ID(GetPropertyByIndex), reinterpret_cast(getpropertyByIndexPtr)); + thread->SetFastStubEntry(FAST_STUB_ID(GetPropertyByName), reinterpret_cast(getPropertyByNamePtr)); - // test y == 0.0 || std::isnan(y) || std::isnan(x) || std::isinf(x) return NAN_VALUE - double x2 = 7.3; - int y2 = base::NAN_VALUE; - auto result2 = fn(JSTaggedValue(x2).GetRawData(), JSTaggedValue(y2).GetRawData()); - auto expectRes2 = FastRuntimeStub::FastMod(JSTaggedValue(x2), JSTaggedValue(y2)); - EXPECT_EQ(result2, expectRes2); - std::cout << "result2 for FastMod(7, 'helloworld') = " << result2.GetRawData() << std::endl; - std::cout << "expectRes2 for FastMod(7, 'helloworld') = " << expectRes2.GetRawData() << std::endl; + auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); + JSHandle obj = factory->NewEmptyJSObject(); + int x = 213; + int y = 10; - // // test modular operation under normal conditions - double x3 = 33.0; - double y3 = 44.0; - auto result3 = fn(JSTaggedValue(x3).GetRawData(), JSTaggedValue(y3).GetRawData()); - auto expectRes3 = FastRuntimeStub::FastMod(JSTaggedValue(x3), JSTaggedValue(y3)); - EXPECT_EQ(result3, expectRes3); + FastRuntimeStub::SetOwnElement(thread, obj.GetTaggedValue(), 1, JSTaggedValue(x)); + FastRuntimeStub::SetOwnElement(thread, obj.GetTaggedValue(), 10250, JSTaggedValue(y)); - // test x == 0.0 || std::isinf(y) return x - double x4 = base::NAN_VALUE; - int y4 = 7; - auto result4 = fn(JSTaggedValue(x4).GetRawData(), JSTaggedValue(y4).GetRawData()); - auto expectRes4 = FastRuntimeStub::FastMod(JSTaggedValue(x4), JSTaggedValue(y4)); + JSHandle strA(factory->NewFromCanBeCompressString("a")); + JSHandle strBig(factory->NewFromCanBeCompressString("biggest")); + JSHandle strDigit(factory->NewFromCanBeCompressString("10250")); - std::cout << "result4 for FastMod(base::NAN_VALUE, 7) = " << result4.GetRawData() << std::endl; - std::cout << "expectRes4 for FastMod(base::NAN_VALUE, 7) = " << expectRes4.GetRawData() << std::endl; - EXPECT_EQ(result4, expectRes4); + FastRuntimeStub::SetPropertyByName(thread, obj.GetTaggedValue(), strA.GetTaggedValue(), JSTaggedValue(x)); + FastRuntimeStub::SetPropertyByName(thread, obj.GetTaggedValue(), strBig.GetTaggedValue(), JSTaggedValue(y)); + assembler.Disassemble(); - // test all non-conforming conditions - int x5 = 7; + JSTaggedValue resVal1 = getPropertyByNamePtr(thread, obj.GetTaggedValue().GetRawData(), + strA.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal1.GetNumber(), x); + JSTaggedValue resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), + strA.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal.GetNumber(), x); + resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), strBig.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal.GetNumber(), y); + resVal = getpropertyByIndexPtr(thread, obj.GetTaggedValue(), 1); + EXPECT_EQ(resVal.GetNumber(), x); + resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), JSTaggedValue(10250).GetRawData()); + EXPECT_EQ(resVal.GetNumber(), y); + resVal = getPropertyByValuePtr(thread, obj.GetTaggedValue().GetRawData(), strDigit.GetTaggedValue().GetRawData()); + EXPECT_EQ(resVal.GetNumber(), y); + + JSHandle strHello(factory->NewFromCanBeCompressString("hello world")); + double key = 4.29497e+09; + resVal = getPropertyByValuePtr(thread, strHello.GetTaggedValue().GetRawData(), JSTaggedValue(key).GetRawData()); + EXPECT_EQ(resVal.GetRawData(), 0); +} + +HWTEST_F_L0(StubTest, FastTypeOfTest) +{ + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastTypeOf)); + Circuit netOfGates; + FastTypeOfStub optimizer(&netOfGates); + optimizer.GenerateCircuit(); + netOfGates.PrintAllGates(); + bool verRes = Verifier::Run(&netOfGates); + ASSERT_TRUE(verRes); + auto cfg = Scheduler::Run(&netOfGates); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); + llvmBuilder.Build(); + char *error = nullptr; + LLVMVerifyModule(module, LLVMAbortProcessAction, &error); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); + assembler.Run(); + LLVMDumpModule(module); + auto *typeOfPtr = + reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + + // obj is JSTaggedValue::VALUE_TRUE + JSTaggedValue resultVal = typeOfPtr(thread, JSTaggedValue::True().GetRawData()); + JSTaggedValue expectResult = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::True()); + EXPECT_EQ(resultVal, globalConst->GetBooleanString()); + EXPECT_EQ(resultVal, expectResult); + + // obj is JSTaggedValue::VALUE_FALSE + JSTaggedValue resultVal2 = typeOfPtr(thread, JSTaggedValue::False().GetRawData()); + JSTaggedValue expectResult2 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::False()); + EXPECT_EQ(resultVal2, globalConst->GetBooleanString()); + EXPECT_EQ(resultVal2, expectResult2); + + // obj is JSTaggedValue::VALUE_NULL + JSTaggedValue resultVal3 = typeOfPtr(thread, JSTaggedValue::Null().GetRawData()); + JSTaggedValue expectResult3 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::Null()); + EXPECT_EQ(resultVal3, globalConst->GetObjectString()); + EXPECT_EQ(resultVal3, expectResult3); + + // obj is JSTaggedValue::VALUE_UNDEFINED + JSTaggedValue resultVal4 = typeOfPtr(thread, JSTaggedValue::Undefined().GetRawData()); + JSTaggedValue expectResult4 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue::Undefined()); + EXPECT_EQ(resultVal4, globalConst->GetUndefinedString()); + EXPECT_EQ(resultVal4, expectResult4); + + // obj is IsNumber + JSTaggedValue resultVal5 = typeOfPtr(thread, JSTaggedValue(5).GetRawData()); + JSTaggedValue expectResult5 = FastRuntimeStub::FastTypeOf(thread, JSTaggedValue(5)); + EXPECT_EQ(resultVal5, globalConst->GetNumberString()); + EXPECT_EQ(resultVal5, expectResult5); + + // obj is String auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); - auto y5 = factory->NewFromStdString("hello world"); - auto result5 = fn(JSTaggedValue(x5).GetRawData(), y5.GetTaggedValue().GetRawData()); - EXPECT_EQ(result5, JSTaggedValue::Hole()); - auto expectRes5 = FastRuntimeStub::FastMod(JSTaggedValue(x5), y5.GetTaggedValue()); - std::cout << "result1 for FastMod(7, 'helloworld') = " << result5.GetRawData() << std::endl; - EXPECT_EQ(result5, expectRes5); + JSHandle str1 = factory->NewFromStdString("a"); + JSHandle str2 = factory->NewFromStdString("a"); + JSTaggedValue expectResult6 = FastRuntimeStub::FastTypeOf(thread, str1.GetTaggedValue()); + JSTaggedValue resultVal6 = typeOfPtr(thread, str2.GetTaggedValue().GetRawData()); + EXPECT_EQ(resultVal6, globalConst->GetStringString()); + EXPECT_EQ(resultVal6, expectResult6); + + // obj is Symbol + JSHandle globalEnv = JSThread::Cast(thread)->GetEcmaVM()->GetGlobalEnv(); + JSTaggedValue symbol = globalEnv->GetIteratorSymbol().GetTaggedValue(); + JSTaggedValue expectResult7= FastRuntimeStub::FastTypeOf(thread, symbol); + JSTaggedValue resultVal7 = typeOfPtr(thread, symbol.GetRawData()); + EXPECT_EQ(resultVal7, globalConst->GetSymbolString()); + EXPECT_EQ(resultVal7, expectResult7); + + // obj is callable + JSHandle resolveCallable = + factory->CreateJSPromiseReactionsFunction(reinterpret_cast(BuiltinsPromiseHandler::Resolve)); + JSTaggedValue expectResult8= FastRuntimeStub::FastTypeOf(thread, resolveCallable.GetTaggedValue()); + JSTaggedValue resultVal8 = typeOfPtr(thread, resolveCallable.GetTaggedValue().GetRawData()); + EXPECT_EQ(resultVal8, globalConst->GetFunctionString()); + EXPECT_EQ(resultVal8, expectResult8); + + // obj is heapObject + JSHandle object = factory->NewEmptyJSObject(); + JSTaggedValue expectResult9= FastRuntimeStub::FastTypeOf(thread, object.GetTaggedValue()); + JSTaggedValue resultVal9 = typeOfPtr(thread, object.GetTaggedValue().GetRawData()); + EXPECT_EQ(resultVal9, globalConst->GetObjectString()); + EXPECT_EQ(resultVal9, expectResult9); +} + +HWTEST_F_L0(StubTest, FastEqualTest) +{ + auto module = stubModule.GetModule(); + auto function = stubModule.GetStubFunction(FAST_STUB_ID(FastEqual)); + Circuit netOfGates; + FastEqualStub optimizer(&netOfGates); + optimizer.GenerateCircuit(); + netOfGates.PrintAllGates(); + auto cfg = Scheduler::Run(&netOfGates); + PrintCircuitByBasicBlock(cfg, netOfGates); + LLVMIRBuilder llvmBuilder(&cfg, &netOfGates, &stubModule, function); + llvmBuilder.Build(); + LLVMAssembler assembler(module, "x86_64-unknown-linux-gnu"); + assembler.Run(); + LLVMDumpModule(module); + auto fn = reinterpret_cast(assembler.GetFuncPtrFromCompiledModule(function)); + // test for 1 == 1 + auto resA = fn(JSTaggedValue(1).GetRawData(), JSTaggedValue(1).GetRawData()); + auto expectA = FastRuntimeStub::FastEqual(JSTaggedValue(1), JSTaggedValue(1)); + EXPECT_EQ(resA, expectA); + + // test for nan == nan + double nan = std::numeric_limits::quiet_NaN(); + auto resB = fn(JSTaggedValue(nan).GetRawData(), JSTaggedValue(nan).GetRawData()); + auto expectB = FastRuntimeStub::FastEqual(JSTaggedValue(nan), JSTaggedValue(nan)); + EXPECT_EQ(resB, expectB); + + // test for undefined == null + auto resC = fn(JSTaggedValue::Undefined().GetRawData(), JSTaggedValue::Null().GetRawData()); + auto expectC = FastRuntimeStub::FastEqual(JSTaggedValue::Undefined(), JSTaggedValue::Null()); + EXPECT_EQ(resC, expectC); + + // test for "hello world" == undefined + auto *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); + auto str = factory->NewFromStdString("hello world"); + auto resD = fn(str.GetTaggedValue().GetRawData(), JSTaggedValue::Undefined().GetRawData()); + auto expectD = FastRuntimeStub::FastEqual(str.GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(resD, expectD); + + // test for true == hole + auto resE = fn(JSTaggedValue::True().GetRawData(), JSTaggedValue::Hole().GetRawData()); + auto expectE = FastRuntimeStub::FastEqual(JSTaggedValue::True(), JSTaggedValue::Hole()); + EXPECT_EQ(resE, expectE); + + // test for "hello world" == "hello world" + auto resF = fn(str.GetTaggedValue().GetRawData(), str.GetTaggedValue().GetRawData()); + auto expectF = FastRuntimeStub::FastEqual(str.GetTaggedValue(), str.GetTaggedValue()); + EXPECT_EQ(resF, expectF); + + // test for 5.2 == 5.2 + auto resG = fn(JSTaggedValue(5.2).GetRawData(), JSTaggedValue(5.2).GetRawData()); + auto expectG = FastRuntimeStub::FastEqual(JSTaggedValue(5.2), JSTaggedValue(5.2)); + EXPECT_EQ(resG, expectG); + + // test for false == false + auto resH = fn(JSTaggedValue::False().GetRawData(), JSTaggedValue::False().GetRawData()); + auto expectH = FastRuntimeStub::FastEqual(JSTaggedValue::False(), JSTaggedValue::False()); + EXPECT_EQ(resH, expectH); + + // test for obj == obj + JSHandle obj1 = factory->NewEmptyJSObject(); + JSHandle obj2 = factory->NewEmptyJSObject(); + FastRuntimeStub::SetOwnElement(thread, obj1.GetTaggedValue(), 1, JSTaggedValue(1)); + FastRuntimeStub::SetOwnElement(thread, obj2.GetTaggedValue(), 1, JSTaggedValue(1)); + auto resI = fn(obj1.GetTaggedValue().GetRawData(), obj2.GetTaggedValue().GetRawData()); + auto expectI = FastRuntimeStub::FastEqual(obj1.GetTaggedValue(), obj2.GetTaggedValue()); + EXPECT_EQ(resI, expectI); } } // namespace panda::test diff --git a/ecmascript/compiler/type.h b/ecmascript/compiler/type.h index 399d6cfa755bd939c2ab48b6d786997cbcf5449a..3525788d6e5231d566552d4598271785f4d16979 100644 --- a/ecmascript/compiler/type.h +++ b/ecmascript/compiler/type.h @@ -20,8 +20,8 @@ namespace kungfu { using GateType = uint8_t; -enum TypeCode : GateType { - // for HIR +enum class TypeCode : GateType { + // for AOT NOTYPE, JS_ANY, JS_NULL, @@ -42,9 +42,9 @@ enum TypeCode : GateType { JS_UINT32ARRAY, JS_FLOAT32ARRAY, JS_FLOAT64ARRAY, - // for MIR - IS_REFERENCE, - NOT_REFERENCE, + // for Stub + POINTER_TYPE, + TAGGED_POINTER_TYPE, }; class Type { diff --git a/ecmascript/dump.cpp b/ecmascript/dump.cpp index 30bacd0593a194b25b69e177ac2316725470b55a..74988092e158b078194cf694c50fe0cb80fa8d0d 100644 --- a/ecmascript/dump.cpp +++ b/ecmascript/dump.cpp @@ -20,27 +20,45 @@ #include "ecmascript/accessor_data.h" #include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" #include "ecmascript/global_dictionary-inl.h" #include "ecmascript/global_env.h" +#include "ecmascript/ic/ic_handler.h" +#include "ecmascript/ic/proto_change_details.h" +#include "ecmascript/ic/property_box.h" +#include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/jobs/pending_job.h" #include "ecmascript/js_array.h" #include "ecmascript/js_array_iterator.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_async_function.h" +#include "ecmascript/js_collator.h" #include "ecmascript/js_dataview.h" #include "ecmascript/js_date.h" +#include "ecmascript/js_date_time_format.h" +#include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_function.h" +#include "ecmascript/js_function_extra_info.h" +#include "ecmascript/js_generator_object.h" +#include "ecmascript/js_global_object.h" #include "ecmascript/js_handle.h" +#include "ecmascript/js_intl.h" +#include "ecmascript/js_locale.h" #include "ecmascript/js_map.h" #include "ecmascript/js_map_iterator.h" +#include "ecmascript/js_number_format.h" #include "ecmascript/js_object-inl.h" +#include "ecmascript/js_plural_rules.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_promise.h" +#include "ecmascript/js_realm.h" #include "ecmascript/js_regexp.h" +#include "ecmascript/js_relative_time_format.h" #include "ecmascript/js_set.h" #include "ecmascript/js_set_iterator.h" +#include "ecmascript/js_string_iterator.h" #include "ecmascript/js_tagged_number.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" @@ -51,8 +69,10 @@ #include "ecmascript/linked_hash_table-inl.h" #include "ecmascript/mem/assert_scope-inl.h" #include "ecmascript/mem/c_containers.h" +#include "ecmascript/mem/machine_code.h" #include "ecmascript/tagged_array.h" #include "ecmascript/tagged_dictionary.h" +#include "ecmascript/template_map.h" #include "ecmascript/transitions_dictionary.h" namespace panda::ecmascript { @@ -73,6 +93,8 @@ CString JSHClass::DumpJSType(JSType type) return "TaggedDictionary"; case JSType::STRING: return "BaseString"; + case JSType::JS_NATIVE_POINTER: + return "NativePointer"; case JSType::JS_OBJECT: return "Object"; case JSType::JS_FUNCTION_BASE: @@ -193,6 +215,42 @@ CString JSHClass::DumpJSType(JSType type) return "AsyncAwaitStatusFunction"; case JSType::JS_ASYNC_FUNC_OBJECT: return "AsyncFunctionObject"; + case JSType::JS_REALM: + return "Realm"; + case JSType::JS_GLOBAL_OBJECT: + return "GlobalObject"; + case JSType::JS_INTL: + return "JSIntl"; + case JSType::JS_LOCALE: + return "JSLocale"; + case JSType::JS_DATE_TIME_FORMAT: + return "JSDateTimeFormat"; + case JSType::JS_RELATIVE_TIME_FORMAT: + return "JSRelativeTimeFormat"; + case JSType::JS_NUMBER_FORMAT: + return "JSNumberFormat"; + case JSType::JS_COLLATOR: + return "JSCollator"; + case JSType::JS_PLURAL_RULES: + return "JSPluralRules"; + case JSType::JS_GENERATOR_OBJECT: + return "JSGeneratorObject"; + case JSType::JS_GENERATOR_CONTEXT: + return "JSGeneratorContext"; + case JSType::PROTO_CHANGE_MARKER: + return "ProtoChangeMarker"; + case JSType::PROTOTYPE_INFO: + return "PrototypeInfo"; + case JSType::PROGRAM: + return "program"; + case JSType::LEXICAL_FUNCTION: + return "LexicalFunction"; + case JSType::FUNCTION_EXTRA_INFO: + return "FunctionExtraInfo"; + case JSType::MACHINE_CODE_OBJECT: + return "MachineCode"; + case JSType::ECMA_MODULE: + return "EcmaModule"; default: { CString ret = "unknown type "; return ret + static_cast(type); @@ -321,12 +379,15 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os) return DumpDynClass(thread, obj, os); case JSType::TAGGED_ARRAY: case JSType::TAGGED_DICTIONARY: + case JSType::TEMPLATE_MAP: DumpArrayClass(thread, TaggedArray::Cast(obj), os); break; case JSType::STRING: DumpStringClass(EcmaString::Cast(obj), os); os << "\n"; break; + case JSType::JS_NATIVE_POINTER: + break; case JSType::JS_OBJECT: case JSType::JS_GLOBAL_OBJECT: case JSType::JS_ERROR: @@ -447,13 +508,88 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::ostream &os) case JSType::JS_GENERATOR_FUNCTION: JSGeneratorFunction::Cast(obj)->Dump(thread, os); break; + case JSType::JS_INTL_BOUND_FUNCTION: + JSIntlBoundFunction::Cast(obj)->Dump(thread, os); + break; case JSType::JS_ITERATOR: + break; case JSType::JS_FORIN_ITERATOR: + JSForInIterator::Cast(obj)->Dump(thread, os); + break; case JSType::JS_MAP_ITERATOR: + JSMapIterator::Cast(obj)->Dump(thread, os); + break; case JSType::JS_SET_ITERATOR: + JSSetIterator::Cast(obj)->Dump(thread, os); + break; case JSType::JS_ARRAY_ITERATOR: + JSArrayIterator::Cast(obj)->Dump(thread, os); + break; case JSType::JS_STRING_ITERATOR: + JSStringIterator::Cast(obj)->Dump(thread, os); + break; + case JSType::PROTOTYPE_HANDLER: + PrototypeHandler::Cast(obj)->Dump(thread, os); + break; + case JSType::TRANSITION_HANDLER: + TransitionHandler::Cast(obj)->Dump(thread, os); + break; case JSType::PROPERTY_BOX: + PropertyBox::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_REALM: + JSRealm::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_INTL: + JSIntl::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_LOCALE: + JSLocale::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_DATE_TIME_FORMAT: + JSDateTimeFormat::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_RELATIVE_TIME_FORMAT: + JSRelativeTimeFormat::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_NUMBER_FORMAT: + JSNumberFormat::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_COLLATOR: + JSCollator::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_PLURAL_RULES: + JSPluralRules::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_GENERATOR_OBJECT: + JSGeneratorObject::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_ASYNC_FUNC_OBJECT: + JSAsyncFuncObject::Cast(obj)->Dump(thread, os); + break; + case JSType::JS_GENERATOR_CONTEXT: + GeneratorContext::Cast(obj)->Dump(thread, os); + break; + case JSType::PROTOTYPE_INFO: + ProtoChangeDetails::Cast(obj)->Dump(thread, os); + break; + case JSType::PROTO_CHANGE_MARKER: + ProtoChangeMarker::Cast(obj)->Dump(thread, os); + break; + case JSType::PROGRAM: + Program::Cast(obj)->Dump(thread, os); + break; + case JSType::LEXICAL_FUNCTION: + LexicalFunction::Cast(obj)->Dump(thread, os); + break; + case JSType::FUNCTION_EXTRA_INFO: + JSFunctionExtraInfo::Cast(obj)->Dump(thread, os); + break; + case JSType::MACHINE_CODE_OBJECT: + MachineCode::Cast(obj)->Dump(thread, os); + break; + case JSType::ECMA_MODULE: + EcmaModule::Cast(obj)->Dump(thread, os); break; default: UNREACHABLE(); @@ -552,7 +688,7 @@ void JSTaggedValue::DumpVal(JSThread *thread, JSTaggedType val) void JSThread::DumpStack() { - EcmaFrameHandler handler(this); + InterpretedFrameHandler handler(this); handler.DumpStack(std::cout); } @@ -762,16 +898,16 @@ void AccessorData::Dump(JSThread *thread, std::ostream &os) const void Program::Dump(JSThread *thread, std::ostream &os) const { os << " - Location: "; - GetLocation().DumpTaggedValue(thread, os); + GetLocation().Dump(thread); os << "\n"; os << " - ConstantPool: "; - TaggedArray *arr = TaggedArray::Cast(GetConstantPool().GetTaggedObject()); - DumpArrayClass(thread, arr, os); + GetConstantPool().Dump(thread); os << "\n"; - os << " - MainFunction: "; - GetMainFunction().DumpTaggedValue(thread, os); + GetMainFunction().Dump(thread); os << "\n"; + os << " - MethodsData: " << GetMethodsData() << "\n"; + os << " - NumberMethods: " << GetNumberMethods() << "\n"; } void ConstantPool::Dump(JSThread *thread, std::ostream &os) const @@ -781,6 +917,27 @@ void ConstantPool::Dump(JSThread *thread, std::ostream &os) const void JSFunction::Dump(JSThread *thread, std::ostream &os) const { + os << " - ProtoOrDynClass: "; + GetProtoOrDynClass().Dump(thread); + os << "\n"; + os << " - LexicalEnv: "; + GetLexicalEnv().Dump(thread); + os << "\n"; + os << " - HomeObject: "; + GetHomeObject().Dump(thread); + os << "\n"; + os << " - FunctionInfoFlag: "; + GetFunctionInfoFlag().Dump(thread); + os << "\n"; + os << " - FunctionExtraInfo: "; + GetFunctionExtraInfo().Dump(thread); + os << "\n"; + os << " - ConstantPool: "; + GetConstantPool().Dump(thread); + os << "\n"; + os << " - ProfileTypeInfo: "; + GetProfileTypeInfo().Dump(thread); + os << "\n"; JSObject::Dump(thread, os); } @@ -833,6 +990,23 @@ void JSMap::Dump(JSThread *thread, std::ostream &os) const map->Dump(thread, os); } +void JSForInIterator::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Object : "; + GetObject().DumpTaggedValue(thread, os); + os << "\n"; + os << " - WasVisited : "; + GetWasVisited().DumpTaggedValue(thread, os); + os << "\n"; + os << " - VisitedKeys : "; + GetVisitedKeys().DumpTaggedValue(thread, os); + os << "\n"; + os << " - RemainingKeys : "; + GetRemainingKeys().DumpTaggedValue(thread, os); + os << "\n"; + JSObject::Dump(thread, os); +} + void JSMapIterator::Dump(JSThread *thread, std::ostream &os) const { LinkedHashMap *map = LinkedHashMap::Cast(GetIteratedMap().GetTaggedObject()); @@ -914,6 +1088,13 @@ void JSArrayIterator::Dump(JSThread *thread, std::ostream &os) const JSObject::Dump(thread, os); } +void JSStringIterator::Dump(JSThread *thread, std::ostream &os) const +{ + EcmaString *str = EcmaString::Cast(GetIteratedString().GetTaggedObject()); + os << " - IteratedString: " << str->GetCString().get() << "\n"; + os << " - StringIteratorNextIndex: " << std::dec << GetStringIteratorNextIndex().GetInt() << "\n"; + JSObject::Dump(thread, os); +} void JSTypedArray::Dump(JSThread *thread, std::ostream &os) const { os << " - viewed-array-buffer: "; @@ -931,11 +1112,20 @@ void JSTypedArray::Dump(JSThread *thread, std::ostream &os) const void JSRegExp::Dump(JSThread *thread, std::ostream &os) const { - os << " - source: "; - DumpStringClass(EcmaString::Cast(GetOriginalSource().GetTaggedObject()), os); + os << " - LastIndex: "; + GetLastIndex().Dump(thread); os << "\n"; - os << " - flags: "; - os << GetOriginalFlags().GetInt(); + os << " - ByteCodeBuffer: "; + GetByteCodeBuffer().Dump(thread); + os << "\n"; + os << " - OriginalSource: "; + GetOriginalSource().Dump(thread); + os << "\n"; + os << " - OriginalFlags: "; + GetOriginalFlags().Dump(thread); + os << "\n"; + os << " - Length: "; + GetLength().Dump(thread); os << "\n"; JSObject::Dump(thread, os); } @@ -1197,6 +1387,8 @@ void JSArrayBuffer::Dump(JSThread *thread, std::ostream &os) const GetArrayBufferByteLength().Dump(thread); os << " - buffer-data: "; GetArrayBufferData().Dump(thread); + os << " - Shared: "; + GetShared().Dump(thread); } void PromiseReaction::Dump(JSThread *thread, std::ostream &os) const @@ -1315,7 +1507,7 @@ void JSProxyRevocFunction::Dump(JSThread *thread, std::ostream &os) const { os << " - RevocableProxy: "; os << "\n"; - JSObject::Cast(GetRevocableProxy().GetTaggedObject())->Dump(thread, os); + GetRevocableProxy().Dump(thread); os << "\n"; } @@ -1328,7 +1520,7 @@ void JSAsyncAwaitStatusFunction::Dump(JSThread *thread, std::ostream &os) const { os << " - AsyncContext: "; os << "\n"; - JSObject::Cast(GetAsyncContext().GetTaggedObject())->Dump(thread, os); + GetAsyncContext().Dump(thread); os << "\n"; } @@ -1337,6 +1529,364 @@ void JSGeneratorFunction::Dump(JSThread *thread, std::ostream &os) const JSFunction::Dump(thread, os); } +void JSIntlBoundFunction::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - NumberFormat: "; + GetNumberFormat().Dump(thread); + os << "\n"; + os << " - DateTimeFormat: "; + GetDateTimeFormat().Dump(thread); + os << "\n"; + os << " - Collator: "; + GetCollator().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void PropertyBox::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Value: "; + GetValue().Dump(thread); + os << "\n"; +} + +void PrototypeHandler::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - HandlerInfo: "; + GetHandlerInfo().Dump(thread); + os << "\n"; + os << " - ProtoCell: "; + GetHandlerInfo().Dump(thread); + os << "\n"; + os << " - Holder: "; + GetHandlerInfo().Dump(thread); + os << "\n"; +} + +void TransitionHandler::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - HandlerInfo: "; + GetHandlerInfo().Dump(thread); + os << "\n"; + os << " - TransitionHClass: "; + GetTransitionHClass().Dump(thread); + os << "\n"; +} + +void JSRealm::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Value: "; + GetValue().Dump(thread); + os << "\n"; + os << " - GlobalEnv: "; + GetGlobalEnv().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSIntl::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - FallbackSymbol: "; + GetFallbackSymbol().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSLocale::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - IcuField: "; + GetIcuField().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSDateTimeFormat::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Locale: "; + GetLocale().Dump(thread); + os << "\n"; + os << " - Calendar: "; + GetCalendar().Dump(thread); + os << "\n"; + os << " - NumberingSystem: "; + GetNumberingSystem().Dump(thread); + os << "\n"; + os << " - TimeZone: "; + GetTimeZone().Dump(thread); + os << "\n"; + os << " - HourCycle: "; + GetHourCycle().Dump(thread); + os << "\n"; + os << " - LocaleIcu: "; + GetLocaleIcu().Dump(thread); + os << "\n"; + os << " - SimpleDateTimeFormatIcu: "; + GetSimpleDateTimeFormatIcu().Dump(thread); + os << "\n"; + os << " - Iso8601: "; + GetIso8601().Dump(thread); + os << "\n"; + os << " - DateStyle: "; + GetDateStyle().Dump(thread); + os << "\n"; + os << " - TimeStyle: "; + GetTimeStyle().Dump(thread); + os << "\n"; + os << " - BoundFormat: "; + GetBoundFormat().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSRelativeTimeFormat::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Locale: "; + GetLocale().Dump(thread); + os << "\n"; + os << " - InitializedRelativeTimeFormat: "; + GetInitializedRelativeTimeFormat().Dump(thread); + os << "\n"; + os << " - NumberingSystem: "; + GetNumberingSystem().Dump(thread); + os << "\n"; + os << " - Style: "; + GetStyle().Dump(thread); + os << "\n"; + os << " - Numeric: "; + GetNumeric().Dump(thread); + os << "\n"; + os << " - AvailableLocales: "; + GetAvailableLocales().Dump(thread); + os << "\n"; + os << " - IcuField: "; + GetIcuField().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSNumberFormat::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Locale: "; + GetLocale().Dump(thread); + os << "\n" << " - NumberingSystem: "; + GetNumberingSystem().Dump(thread); + os << "\n" << " - Style: "; + GetStyle().Dump(thread); + os << "\n" << " - Currency: "; + GetCurrency().Dump(thread); + os << "\n" << " - CurrencyDisplay: "; + GetCurrencyDisplay().Dump(thread); + os << "\n" << " - CurrencySign: "; + GetCurrencySign().Dump(thread); + os << "\n" << " - Unit: "; + GetUnit().Dump(thread); + os << "\n" << " - UnitDisplay: "; + GetUnitDisplay().Dump(thread); + os << "\n" << " - MinimumIntegerDigits: "; + GetMinimumIntegerDigits().Dump(thread); + os << "\n" << " - MinimumFractionDigits: "; + GetMinimumFractionDigits().Dump(thread); + os << "\n" << " - MaximumFractionDigits: "; + GetMaximumFractionDigits().Dump(thread); + os << "\n" << " - MinimumSignificantDigits: "; + GetMinimumSignificantDigits().Dump(thread); + os << "\n" << " - MaximumSignificantDigits: "; + GetMaximumSignificantDigits().Dump(thread); + os << "\n" << " - UseGrouping: "; + GetUseGrouping().Dump(thread); + os << "\n" << " - RoundingType: "; + GetUseGrouping().Dump(thread); + os << "\n" << " - Notation: "; + GetMinimumIntegerDigits().Dump(thread); + os << "\n" << " - CompactDisplay: "; + GetMaximumSignificantDigits().Dump(thread); + os << "\n" << " - SignDisplay: "; + GetMinimumFractionDigits().Dump(thread); + os << "\n" << " - BoundFormat: "; + GetMaximumFractionDigits().Dump(thread); + os << "\n" << " - IcuField: "; + GetMinimumSignificantDigits().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSCollator::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - IcuField: "; + GetIcuField().Dump(thread); + os << "\n"; + os << " - Locale: "; + GetLocale().Dump(thread); + os << "\n"; + os << " - Usage: "; + GetUsage().Dump(thread); + os << "\n"; + os << " - Sensitivity: "; + GetSensitivity().Dump(thread); + os << "\n"; + os << " - IgnorePunctuation: "; + GetIgnorePunctuation().Dump(thread); + os << "\n"; + os << " - Collation: "; + GetCollation().Dump(thread); + os << "\n"; + os << " - Numeric: "; + GetNumeric().Dump(thread); + os << "\n"; + os << " - CaseFirst: "; + GetCaseFirst().Dump(thread); + os << "\n"; + os << " - BoundCompare: "; + GetBoundCompare().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSPluralRules::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Locale: "; + GetLocale().Dump(thread); + os << "\n"; + os << " - InitializedPluralRules: "; + GetInitializedPluralRules().Dump(thread); + os << "\n"; + os << " - Type: "; + GetType().Dump(thread); + os << "\n"; + os << " - MinimumIntegerDigits: "; + GetMinimumIntegerDigits().Dump(thread); + os << "\n"; + os << " - MinimumFractionDigits: "; + GetMinimumFractionDigits().Dump(thread); + os << "\n"; + os << " - MaximumFractionDigits: "; + GetMaximumFractionDigits().Dump(thread); + os << "\n"; + os << " - MinimumSignificantDigits: "; + GetMinimumSignificantDigits().Dump(thread); + os << "\n"; + os << " - MaximumSignificantDigits: "; + GetMaximumSignificantDigits().Dump(thread); + os << "\n"; + os << " - RoundingType: "; + GetRoundingType().Dump(thread); + os << "\n"; + os << " - IcuPR: "; + GetIcuPR().Dump(thread); + os << "\n"; + os << " - IcuNF: "; + GetIcuNF().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSGeneratorObject::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - GeneratorState: "; + GetGeneratorState().Dump(thread); + os << "\n"; + os << " - GeneratorContext: "; + GetGeneratorContext().Dump(thread); + os << "\n"; + os << " - ResumeResult: "; + GetResumeResult().Dump(thread); + os << "\n"; + os << " - ResumeMode: "; + GetResumeMode().Dump(thread); + os << "\n"; + JSObject::Dump(thread, os); +} + +void JSAsyncFuncObject::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Promise: "; + GetPromise().Dump(thread); + os << "\n"; +} + +void GeneratorContext::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - RegsArray: "; + GetRegsArray().Dump(thread); + os << "\n"; + os << " - Method: "; + GetMethod().Dump(thread); + os << "\n"; + os << " - Acc: "; + GetAcc().Dump(thread); + os << "\n"; + os << " - NRegs: "; + GetNRegs().Dump(thread); + os << "\n"; + os << " - BCOffset: "; + GetBCOffset().Dump(thread); + os << "\n"; + os << " - GeneratorObject: "; + GetGeneratorObject().Dump(thread); + os << "\n"; + os << " - LexicalEnv: "; + GetLexicalEnv().Dump(thread); + os << "\n"; +} + +void ProtoChangeMarker::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - HasChanged: " << GetHasChanged() << "\n"; +} + +void ProtoChangeDetails::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - ChangeListener: "; + GetChangeListener().Dump(thread); + os << "\n"; + os << " - RegisterIndex: "; + GetRegisterIndex().Dump(thread); + os << "\n"; +} + +void LexicalFunction::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Name: "; + GetName().Dump(thread); + os << "\n"; + os << " - NumberVRegs: "; + GetNumberVRegs().Dump(thread); + os << "\n"; + os << " - NumberICSlots: "; + GetNumberICSlots().Dump(thread); + os << "\n"; + os << " - Bytecode: "; + GetBytecode().Dump(thread); + os << "\n"; + os << " - Program: "; + GetProgram().Dump(thread); + os << "\n"; +} + +void JSFunctionExtraInfo::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - Callback: "; + GetCallback().Dump(thread); + os << "\n"; + os << " - Data: "; + GetData().Dump(thread); + os << "\n"; +} + +void MachineCode::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - InstructionSizeInBytes: "; + GetInstructionSizeInBytes().Dump(thread); + os << "\n"; +} + +void EcmaModule::Dump(JSThread *thread, std::ostream &os) const +{ + os << " - NameDictionary: "; + GetNameDictionary().Dump(thread); + os << "\n"; +} + // ######################################################################################## // Dump for Snapshot // ######################################################################################## @@ -1352,6 +1902,12 @@ static void DumpArrayClass([[maybe_unused]] JSThread *thread, const TaggedArray } } +static void DumpStringClass([[maybe_unused]] JSThread *thread, const EcmaString *str, + std::vector> &vec) +{ + vec.push_back(std::make_pair("string", JSTaggedValue(str))); +} + static void DumpDynClass([[maybe_unused]] JSThread *thread, TaggedObject *obj, std::vector> &vec) { @@ -1359,7 +1915,8 @@ static void DumpDynClass([[maybe_unused]] JSThread *thread, TaggedObject *obj, vec.push_back(std::make_pair("__proto__", jshclass->GetPrototype())); } -static void DumpObject(JSThread *thread, TaggedObject *obj, std::vector> &vec) +static void DumpObject(JSThread *thread, TaggedObject *obj, + std::vector> &vec, bool isVmMode) { DISALLOW_GARBAGE_COLLECTION; auto jsHclass = obj->GetClass(); @@ -1368,14 +1925,16 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::vectorDumpForSnapshot(thread, vec); - break; + return; case JSType::JS_FUNCTION_BASE: case JSType::JS_FUNCTION: JSFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_BOUND_FUNCTION: JSBoundFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_SET: JSSet::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_MAP: JSMap::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_WEAK_SET: JSWeakSet::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_WEAK_MAP: JSWeakMap::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_REG_EXP: JSRegExp::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_DATE: JSDate::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_ARRAY: JSArray::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_TYPED_ARRAY: case JSType::JS_INT8_ARRAY: case JSType::JS_UINT8_ARRAY: @@ -1426,62 +1986,59 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::vectorDumpForSnapshot(thread, vec); - break; + return; case JSType::JS_PROXY: JSProxy::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_PRIMITIVE_REF: JSPrimitiveRef::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::SYMBOL: JSSymbol::Cast(obj)->DumpForSnapshot(thread, vec); - break; - case JSType::GLOBAL_ENV: - GlobalEnv::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::ACCESSOR_DATA: case JSType::INTERNAL_ACCESSOR: AccessorData::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_DATA_VIEW: JSDataView::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::PROMISE_REACTIONS: PromiseReaction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::PROMISE_CAPABILITY: PromiseCapability::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::PROMISE_ITERATOR_RECORD: PromiseIteratorRecord::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::PROMISE_RECORD: PromiseRecord::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::RESOLVING_FUNCTIONS_RECORD: ResolvingFunctionsRecord::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_PROMISE: JSPromise::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_PROMISE_REACTIONS_FUNCTION: JSPromiseReactionsFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_PROMISE_EXECUTOR_FUNCTION: JSPromiseExecutorFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION: JSPromiseAllResolveElementFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::MICRO_JOB_QUEUE: MicroJobQueue::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::PENDING_JOB: PendingJob::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::COMPLETION_RECORD: CompletionRecord::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_ITERATOR: case JSType::JS_FORIN_ITERATOR: case JSType::JS_MAP_ITERATOR: @@ -1490,26 +2047,101 @@ static void DumpObject(JSThread *thread, TaggedObject *obj, std::vectorDumpForSnapshot(thread, vec); - break; + return; case JSType::JS_PROXY_REVOC_FUNCTION: JSProxyRevocFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_ASYNC_FUNCTION: JSAsyncFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION: JSAsyncAwaitStatusFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; + return; case JSType::JS_GENERATOR_FUNCTION: JSGeneratorFunction::Cast(obj)->DumpForSnapshot(thread, vec); - break; - case JSType::TRANSITION_HANDLER: - case JSType::PROTOTYPE_HANDLER: - case JSType::PROPERTY_BOX: - break; + return; + case JSType::JS_INTL_BOUND_FUNCTION: + JSIntlBoundFunction::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_REALM: + JSRealm::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_INTL: + JSIntl::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_LOCALE: + JSLocale::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_DATE_TIME_FORMAT: + JSDateTimeFormat::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_RELATIVE_TIME_FORMAT: + JSRelativeTimeFormat::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_NUMBER_FORMAT: + JSNumberFormat::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_COLLATOR: + JSCollator::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_PLURAL_RULES: + JSPluralRules::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_GENERATOR_OBJECT: + JSGeneratorObject::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_ASYNC_FUNC_OBJECT: + JSAsyncFuncObject::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::JS_GENERATOR_CONTEXT: + GeneratorContext::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::FUNCTION_EXTRA_INFO: + JSFunctionExtraInfo::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::ECMA_MODULE: + EcmaModule::Cast(obj)->DumpForSnapshot(thread, vec); + return; default: break; } + if (isVmMode) { + switch (type) { + case JSType::PROPERTY_BOX: + PropertyBox::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::TEMPLATE_MAP: + DumpArrayClass(thread, TaggedArray::Cast(obj), vec); + return; + case JSType::LEXICAL_FUNCTION: + LexicalFunction::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::GLOBAL_ENV: + GlobalEnv::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::PROTO_CHANGE_MARKER: + ProtoChangeMarker::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::PROTOTYPE_INFO: + ProtoChangeDetails::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::PROGRAM: + Program::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::MACHINE_CODE_OBJECT: + MachineCode::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::TRANSITION_HANDLER: + TransitionHandler::Cast(obj)->DumpForSnapshot(thread, vec); + return; + case JSType::PROTOTYPE_HANDLER: + PrototypeHandler::Cast(obj)->DumpForSnapshot(thread, vec); + return; + default: + UNREACHABLE(); + break; + } + } } static inline void EcmaStringToStd(CString &res, EcmaString *str) @@ -1544,10 +2176,11 @@ static void KeyToStd(CString &res, JSTaggedValue key) } } -void JSTaggedValue::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +void JSTaggedValue::DumpForSnapshot(JSThread *thread, + std::vector> &vec, bool isVmMode) const { if (IsHeapObject()) { - return DumpObject(thread, GetTaggedObject(), vec); + return DumpObject(thread, GetTaggedObject(), vec, isVmMode); } UNREACHABLE(); @@ -1634,7 +2267,6 @@ void LinkedHashMap::DumpForSnapshot([[maybe_unused]] JSThread *thread, void JSObject::DumpForSnapshot(JSThread *thread, std::vector> &vec) const { DISALLOW_GARBAGE_COLLECTION; - JSHClass *jshclass = GetJSHClass(); vec.push_back(std::make_pair("__proto__", jshclass->GetPrototype())); @@ -1691,6 +2323,13 @@ void JSHClass::DumpForSnapshot([[maybe_unused]] JSThread *thread, void JSFunction::DumpForSnapshot([[maybe_unused]] JSThread *thread, std::vector> &vec) const { + vec.push_back(std::make_pair(CString("ProtoOrDynClass"), GetProtoOrDynClass())); + vec.push_back(std::make_pair(CString("LexicalEnv"), GetLexicalEnv())); + vec.push_back(std::make_pair(CString("HomeObject"), GetHomeObject())); + vec.push_back(std::make_pair(CString("FunctionInfoFlag"), GetFunctionInfoFlag())); + vec.push_back(std::make_pair(CString("FunctionExtraInfo"), GetFunctionExtraInfo())); + vec.push_back(std::make_pair(CString("ConstantPool"), GetConstantPool())); + vec.push_back(std::make_pair(CString("ProfileTypeInfo"), GetProfileTypeInfo())); JSObject::DumpForSnapshot(thread, vec); } @@ -1700,6 +2339,8 @@ void Program::DumpForSnapshot([[maybe_unused]] JSThread *thread, vec.push_back(std::make_pair(CString("Location"), GetLocation())); vec.push_back(std::make_pair(CString("ConstantPool"), GetConstantPool())); vec.push_back(std::make_pair(CString("MainFunction"), GetMainFunction())); + // MethodsData is another native field, and we don't dump it for JS heap. + vec.push_back(std::make_pair(CString("NumberMethods"), JSTaggedValue(GetNumberMethods()))); } void ConstantPool::DumpForSnapshot([[maybe_unused]] JSThread *thread, @@ -1743,6 +2384,16 @@ void JSMap::DumpForSnapshot([[maybe_unused]] JSThread *thread, JSObject::DumpForSnapshot(thread, vec); } +void JSForInIterator::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Object"), GetObject())); + vec.push_back(std::make_pair(CString("WasVisited"), GetWasVisited())); + vec.push_back(std::make_pair(CString("VisitedKeys"), GetVisitedKeys())); + vec.push_back(std::make_pair(CString("RemainingKeys"), GetRemainingKeys())); + JSObject::DumpForSnapshot(thread, vec); +} + void JSMapIterator::DumpForSnapshot([[maybe_unused]] JSThread *thread, std::vector> &vec) const { @@ -1805,6 +2456,14 @@ void JSArrayIterator::DumpForSnapshot([[maybe_unused]] JSThread *thread, JSObject::DumpForSnapshot(thread, vec); } +void JSStringIterator::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("IteratedString"), GetIteratedString())); + vec.push_back(std::make_pair(CString("StringIteratorNextIndex"), GetStringIteratorNextIndex())); + JSObject::DumpForSnapshot(thread, vec); +} + void JSTypedArray::DumpForSnapshot([[maybe_unused]] JSThread *thread, std::vector> &vec) const { @@ -1982,6 +2641,7 @@ void JSArrayBuffer::DumpForSnapshot([[maybe_unused]] JSThread *thread, { vec.push_back(std::make_pair(CString("byte-length"), GetArrayBufferByteLength())); vec.push_back(std::make_pair(CString("buffer-data"), GetArrayBufferData())); + vec.push_back(std::make_pair(CString("shared"), GetShared())); } void PromiseReaction::DumpForSnapshot([[maybe_unused]] JSThread *thread, @@ -2101,4 +2761,198 @@ void JSGeneratorFunction::DumpForSnapshot([[maybe_unused]] JSThread *thread, { JSFunction::DumpForSnapshot(thread, vec); } + +void JSIntlBoundFunction::DumpForSnapshot(JSThread *thread, + std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("NumberFormat"), GetNumberFormat())); + vec.push_back(std::make_pair(CString("DateTimeFormat"), GetDateTimeFormat())); + vec.push_back(std::make_pair(CString("Collator"), GetCollator())); + JSObject::DumpForSnapshot(thread, vec); +} + +void PropertyBox::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Value"), GetValue())); +} + +void PrototypeHandler::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("HandlerInfo"), GetHandlerInfo())); + vec.push_back(std::make_pair(CString("ProtoCell"), GetProtoCell())); + vec.push_back(std::make_pair(CString("Holder"), GetHolder())); +} + +void TransitionHandler::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("HandlerInfo"), GetHandlerInfo())); + vec.push_back(std::make_pair(CString("TransitionHClass"), GetTransitionHClass())); +} + +void JSRealm::DumpForSnapshot([[maybe_unused]] JSThread *thread, + std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Value"), GetValue())); + vec.push_back(std::make_pair(CString("GLobalEnv"), GetGlobalEnv())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSIntl::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("FallbackSymbol"), GetFallbackSymbol())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSLocale::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("IcuField"), GetIcuField())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSDateTimeFormat::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Locale"), GetLocale())); + vec.push_back(std::make_pair(CString("Calendar"), GetCalendar())); + vec.push_back(std::make_pair(CString("NumberingSystem"), GetNumberingSystem())); + vec.push_back(std::make_pair(CString("TimeZone"), GetTimeZone())); + vec.push_back(std::make_pair(CString("HourCycle"), GetHourCycle())); + vec.push_back(std::make_pair(CString("LocaleIcu"), GetLocaleIcu())); + vec.push_back(std::make_pair(CString("SimpleDateTimeFormatIcu"), GetSimpleDateTimeFormatIcu())); + vec.push_back(std::make_pair(CString("Iso8601"), GetIso8601())); + vec.push_back(std::make_pair(CString("DateStyle"), GetDateStyle())); + vec.push_back(std::make_pair(CString("TimeStyle"), GetTimeStyle())); + vec.push_back(std::make_pair(CString("BoundFormat"), GetBoundFormat())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSRelativeTimeFormat::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Locale"), GetLocale())); + vec.push_back(std::make_pair(CString("InitializedRelativeTimeFormat"), GetInitializedRelativeTimeFormat())); + vec.push_back(std::make_pair(CString("NumberingSystem"), GetNumberingSystem())); + vec.push_back(std::make_pair(CString("Style"), GetStyle())); + vec.push_back(std::make_pair(CString("Numeric"), GetNumeric())); + vec.push_back(std::make_pair(CString("AvailableLocales"), GetAvailableLocales())); + vec.push_back(std::make_pair(CString("IcuField"), GetIcuField())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSNumberFormat::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Locale"), GetLocale())); + vec.push_back(std::make_pair(CString("NumberingSystem"), GetNumberingSystem())); + vec.push_back(std::make_pair(CString("Style"), GetStyle())); + vec.push_back(std::make_pair(CString("Currency"), GetCurrency())); + vec.push_back(std::make_pair(CString("CurrencyDisplay"), GetCurrencyDisplay())); + vec.push_back(std::make_pair(CString("CurrencySign"), GetCurrencySign())); + vec.push_back(std::make_pair(CString("Unit"), GetUnit())); + vec.push_back(std::make_pair(CString("UnitDisplay"), GetUnitDisplay())); + vec.push_back(std::make_pair(CString("MinimumIntegerDigits"), GetMinimumIntegerDigits())); + vec.push_back(std::make_pair(CString("MinimumFractionDigits"), GetMinimumFractionDigits())); + vec.push_back(std::make_pair(CString("MaximumFractionDigits"), GetMaximumFractionDigits())); + vec.push_back(std::make_pair(CString("MinimumSignificantDigits"), GetMinimumSignificantDigits())); + vec.push_back(std::make_pair(CString("MaximumSignificantDigits"), GetMaximumSignificantDigits())); + vec.push_back(std::make_pair(CString("UseGrouping"), GetUseGrouping())); + vec.push_back(std::make_pair(CString("RoundingType"), GetRoundingType())); + vec.push_back(std::make_pair(CString("Notation"), GetNotation())); + vec.push_back(std::make_pair(CString("CompactDisplay"), GetCompactDisplay())); + vec.push_back(std::make_pair(CString("SignDisplay"), GetSignDisplay())); + vec.push_back(std::make_pair(CString("BoundFormat"), GetBoundFormat())); + vec.push_back(std::make_pair(CString("IcuField"), GetIcuField())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSCollator::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("IcuField"), GetIcuField())); + vec.push_back(std::make_pair(CString("Locale"), GetLocale())); + vec.push_back(std::make_pair(CString("Usage"), GetUsage())); + vec.push_back(std::make_pair(CString("Sensitivity"), GetSensitivity())); + vec.push_back(std::make_pair(CString("IgnorePunctuation"), GetIgnorePunctuation())); + vec.push_back(std::make_pair(CString("Collation"), GetCollation())); + vec.push_back(std::make_pair(CString("Numeric"), GetNumeric())); + vec.push_back(std::make_pair(CString("CaseFirst"), GetCaseFirst())); + vec.push_back(std::make_pair(CString("BoundCompare"), GetBoundCompare())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSPluralRules::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Locale"), GetLocale())); + vec.push_back(std::make_pair(CString("InitializedPluralRules"), GetInitializedPluralRules())); + vec.push_back(std::make_pair(CString("Type"), GetType())); + vec.push_back(std::make_pair(CString("MinimumIntegerDigits"), GetMinimumIntegerDigits())); + vec.push_back(std::make_pair(CString("MinimumFractionDigits"), GetMinimumFractionDigits())); + vec.push_back(std::make_pair(CString("MaximumFractionDigits"), GetMaximumFractionDigits())); + vec.push_back(std::make_pair(CString("MinimumSignificantDigits"), GetMinimumSignificantDigits())); + vec.push_back(std::make_pair(CString("MaximumSignificantDigits"), GetMaximumSignificantDigits())); + vec.push_back(std::make_pair(CString("RoundingType"), GetRoundingType())); + vec.push_back(std::make_pair(CString("IcuPR"), GetIcuPR())); + vec.push_back(std::make_pair(CString("IcuNF"), GetIcuNF())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSGeneratorObject::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("GeneratorState"), GetGeneratorState())); + vec.push_back(std::make_pair(CString("GeneratorContext"), GetGeneratorContext())); + vec.push_back(std::make_pair(CString("ResumeResult"), GetResumeResult())); + vec.push_back(std::make_pair(CString("ResumeMode"), GetResumeMode())); + JSObject::DumpForSnapshot(thread, vec); +} + +void JSAsyncFuncObject::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Promise"), GetPromise())); +} + +void GeneratorContext::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("RegsArray"), GetRegsArray())); + vec.push_back(std::make_pair(CString("Method"), GetMethod())); + vec.push_back(std::make_pair(CString("Acc"), GetAcc())); + vec.push_back(std::make_pair(CString("NRegs"), GetNRegs())); + vec.push_back(std::make_pair(CString("BCOffset"), GetBCOffset())); + vec.push_back(std::make_pair(CString("GeneratorObject"), GetGeneratorObject())); + vec.push_back(std::make_pair(CString("LexicalEnv"), GetLexicalEnv())); +} + +void ProtoChangeMarker::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Promise"), JSTaggedValue(GetHasChanged()))); +} + +void ProtoChangeDetails::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("ChangeListener"), GetChangeListener())); + vec.push_back(std::make_pair(CString("RegisterIndex"), GetRegisterIndex())); +} + +void LexicalFunction::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Name"), GetName())); + vec.push_back(std::make_pair(CString("NumberVRegs"), GetNumberVRegs())); + vec.push_back(std::make_pair(CString("NumberICSlots"), GetNumberICSlots())); + vec.push_back(std::make_pair(CString("Bytecode"), GetBytecode())); + vec.push_back(std::make_pair(CString("Program"), GetProgram())); +} + +void JSFunctionExtraInfo::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("Callback"), GetCallback())); + vec.push_back(std::make_pair(CString("Data"), GetData())); +} + +void MachineCode::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("InstructionSizeInBytes"), GetInstructionSizeInBytes())); +} + +void EcmaModule::DumpForSnapshot(JSThread *thread, std::vector> &vec) const +{ + vec.push_back(std::make_pair(CString("NameDictionary"), GetNameDictionary())); +} } // namespace panda::ecmascript diff --git a/ecmascript/ecma_language_context.cpp b/ecmascript/ecma_language_context.cpp index 5bd15494b5a4de8b879e02a0ecf31549b892661f..df8d3678a60065e7d9abe9c884c6a3f912f6dab2 100644 --- a/ecmascript/ecma_language_context.cpp +++ b/ecmascript/ecma_language_context.cpp @@ -17,6 +17,7 @@ #include "ecmascript/ecma_class_linker_extension.h" #include "ecmascript/ecma_exceptions.h" +#include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/js_method.h" #include "ecmascript/js_object.h" #include "ecmascript/js_tagged_value.h" @@ -25,7 +26,8 @@ #include "include/tooling/pt_lang_extension.h" namespace panda { -using ecmascript::EcmaFrameHandler; +using ecmascript::JSTaggedType; +using ecmascript::InterpretedFrameHandler; using ecmascript::EcmaVM; using ecmascript::JSThread; @@ -34,8 +36,8 @@ std::pair EcmaLanguageContext::GetCatchMethodAndOffset(Metho Method *catchMethod = method; uint32_t catchOffset = 0; auto jsThread = static_cast(thread); - EcmaFrameHandler frameHandler(jsThread); - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + InterpretedFrameHandler frameHandler(jsThread); + for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { if (frameHandler.IsBreakFrame()) { continue; } diff --git a/ecmascript/ecma_macros.h b/ecmascript/ecma_macros.h index b13285f0a5336d52b3b38fea8a94a2285664b763..b0c11b6aa96f6db4685111adb418719b7b7e2832 100644 --- a/ecmascript/ecma_macros.h +++ b/ecmascript/ecma_macros.h @@ -371,14 +371,14 @@ // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECL_VISIT_OBJECT(BEGIN_OFFSET, SIZE) \ - void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ + void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ { \ visitor(this, ObjectSlot(ToUintPtr(this) + BEGIN_OFFSET), ObjectSlot(ToUintPtr(this) + SIZE)); \ } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define DECL_VISIT_OBJECT_FOR_JS_OBJECT(PARENTCLASS, BEGIN_OFFSET, SIZE) \ - void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ + void VisitRangeSlot(const EcmaObjectRangeVisitor &visitor) \ { \ VisitObjects(visitor); \ /* visit in object fields */ \ @@ -396,4 +396,9 @@ visitor(this, ObjectSlot(ToUintPtr(this) + BEGIN_OFFSET), ObjectSlot(ToUintPtr(this) + SIZE)); \ } +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHECK_DUMP_FILEDS(begin, end, num) \ + LOG_IF(num != (end - begin) / JSTaggedValue::TaggedTypeSize(), FATAL, RUNTIME) \ + << "Fileds in obj are not in dump list. "; + #endif // ECMASCRIPT_ECMA_MACROS_H diff --git a/ecmascript/ecma_module.cpp b/ecmascript/ecma_module.cpp index 3dc94b52efb8cf765f30a6fdb35c131ee00c212b..edeaadc50eead693d4f0fc7e83ddc4f94bbbcb2d 100644 --- a/ecmascript/ecma_module.cpp +++ b/ecmascript/ecma_module.cpp @@ -36,30 +36,38 @@ JSHandle EcmaModule::GetItem(const JSThread *thread, JSHandle(thread, JSTaggedValue::Undefined()); } -void EcmaModule::AddItem(const JSThread *thread, JSHandle itemName, JSHandle itemValue) +void EcmaModule::AddItem(const JSThread *thread, JSHandle module, JSHandle itemName, + JSHandle itemValue) { - JSHandle data(thread, GetNameDictionary()); + JSHandle data(thread, module->GetNameDictionary()); if (data->IsUndefined()) { JSHandle dict(thread, NameDictionary::Create(thread, DICTIONART_CAP)); - auto result = dict->Put(thread, dict, itemName, itemValue, PropertyAttributes::Default()); - SetNameDictionary(thread, JSTaggedValue(result)); + NameDictionary *newDict = NameDictionary::Put(thread, dict, itemName, itemValue, PropertyAttributes::Default()); + module->SetNameDictionary(thread, JSTaggedValue(newDict)); } else { JSHandle dataDict = JSHandle::Cast(data); - auto result = dataDict->Put(thread, dataDict, itemName, itemValue, PropertyAttributes::Default()); - SetNameDictionary(thread, JSTaggedValue(result)); + NameDictionary *newDict = + NameDictionary::Put(thread, dataDict, itemName, itemValue, PropertyAttributes::Default()); + module->SetNameDictionary(thread, JSTaggedValue(newDict)); } } -void EcmaModule::RemoveItem(const JSThread *thread, JSHandle itemName) +void EcmaModule::RemoveItem(const JSThread *thread, JSHandle module, JSHandle itemName) { - JSHandle moduleItems(thread, NameDictionary::Cast(GetNameDictionary().GetTaggedObject())); + JSHandle data(thread, module->GetNameDictionary()); + if (data->IsUndefined()) { + return; + } + JSHandle moduleItems(data); int entry = moduleItems->FindEntry(itemName.GetTaggedValue()); if (entry != -1) { - NameDictionary::Remove(thread, moduleItems, entry); // discard return + NameDictionary *newDict = NameDictionary::Remove(thread, moduleItems, entry); + module->SetNameDictionary(thread, JSTaggedValue(newDict)); } } -void EcmaModule::CopyModuleInternal(const JSThread *thread, JSHandle srcModule) +void EcmaModule::CopyModuleInternal(const JSThread *thread, JSHandle dstModule, + JSHandle srcModule) { JSHandle moduleItems(thread, NameDictionary::Cast(srcModule->GetNameDictionary().GetTaggedObject())); @@ -76,7 +84,7 @@ void EcmaModule::CopyModuleInternal(const JSThread *thread, JSHandle if (entry != -1) { itemName.Update(allKeys->Get(i)); itemValue.Update(moduleItems->GetValue(entry)); - AddItem(thread, itemName, itemValue); + EcmaModule::AddItem(thread, dstModule, itemName, itemValue); } } } @@ -110,20 +118,21 @@ ModuleManager::ModuleManager(EcmaVM *vm) : vm_(vm) // class ModuleManager void ModuleManager::AddModule(JSHandle moduleName, JSHandle module) { - [[maybe_unused]] EcmaHandleScope scope(vm_->GetJSThread()); - JSHandle dict(vm_->GetJSThread(), ecmaModules_); + JSThread *thread = vm_->GetJSThread(); + [[maybe_unused]] EcmaHandleScope scope(thread); + JSHandle dict(thread, ecmaModules_); ecmaModules_ = - JSTaggedValue(dict->Put(vm_->GetJSThread(), dict, moduleName, module, PropertyAttributes::Default())); + JSTaggedValue(NameDictionary::Put(thread, dict, moduleName, module, PropertyAttributes::Default())); } void ModuleManager::RemoveModule(JSHandle moduleName) { - [[maybe_unused]] EcmaHandleScope scope(vm_->GetJSThread()); JSThread *thread = vm_->GetJSThread(); + [[maybe_unused]] EcmaHandleScope scope(thread); JSHandle moduleItems(thread, ecmaModules_); int entry = moduleItems->FindEntry(moduleName.GetTaggedValue()); if (entry != -1) { - NameDictionary::Remove(vm_->GetJSThread(), moduleItems, entry); // discard return + ecmaModules_ = JSTaggedValue(NameDictionary::Remove(thread, moduleItems, entry)); } } @@ -137,6 +146,29 @@ JSHandle ModuleManager::GetModule(const JSThread *thread, return thread->GlobalConstants()->GetHandledUndefined(); } +CString ModuleManager::GenerateModuleFullPath(const std::string ¤tPathFile, const CString &relativeFile) +{ + if (relativeFile.find("./") != 0 && relativeFile.find("../") != 0) { // not start with "./" or "../" + return relativeFile; // not relative + } + + auto slashPos = currentPathFile.find_last_of('/'); + if (slashPos == std::string::npos) { + return relativeFile; // no need to process + } + + auto dotPos = relativeFile.find_last_of("."); + if (dotPos == std::string::npos) { + dotPos = 0; + } + + CString fullPath; + fullPath.append(currentPathFile.substr(0, slashPos + 1)); // 1: with "/" + fullPath.append(relativeFile.substr(0, dotPos)); + fullPath.append(".abc"); // ".js" -> ".abc" + return fullPath; +} + const CString &ModuleManager::GetCurrentExportModuleName() { return moduleStack_.GetTop(); @@ -168,11 +200,11 @@ void ModuleManager::AddModuleItem(const JSThread *thread, JSHandle module = GetModule(thread, JSHandle::Cast(moduleName)); if (module->IsUndefined()) { JSHandle emptyModule = factory->NewEmptyEcmaModule(); - emptyModule->AddItem(thread, itemName, value); + EcmaModule::AddItem(thread, emptyModule, itemName, value); AddModule(JSHandle::Cast(moduleName), JSHandle::Cast(emptyModule)); } else { - EcmaModule::Cast(module->GetTaggedObject())->AddItem(thread, itemName, value); + EcmaModule::AddItem(thread, JSHandle(module), itemName, value); } } @@ -195,11 +227,11 @@ void ModuleManager::CopyModule(const JSThread *thread, JSHandle s if (dstModule->IsUndefined()) { JSHandle emptyModule = factory->NewEmptyEcmaModule(); - emptyModule->CopyModuleInternal(thread, srcModule); + EcmaModule::CopyModuleInternal(thread, emptyModule, srcModule); AddModule(JSHandle::Cast(moduleName), JSHandle::Cast(emptyModule)); } else { - JSHandle::Cast(dstModule)->CopyModuleInternal(thread, srcModule); + EcmaModule::CopyModuleInternal(thread, JSHandle(dstModule), srcModule); } } diff --git a/ecmascript/ecma_module.h b/ecmascript/ecma_module.h index 707724d782f69a70a61e4c9b24ee026ad3e66bd0..9d6652e466639839e41fd6c9bb90b130da75af52 100644 --- a/ecmascript/ecma_module.h +++ b/ecmascript/ecma_module.h @@ -33,9 +33,10 @@ public: JSHandle GetItem(const JSThread *thread, JSHandle itemName); - void AddItem(const JSThread *thread, JSHandle itemName, JSHandle itemValue); + static void AddItem(const JSThread *thread, JSHandle module, JSHandle itemName, + JSHandle itemValue); - void RemoveItem(const JSThread *thread, JSHandle itemName); + static void RemoveItem(const JSThread *thread, JSHandle module, JSHandle itemName); void DebugPrint(const JSThread *thread, const CString &caller); @@ -43,9 +44,11 @@ public: ACCESSORS(NameDictionary, NAME_DICTIONARY_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(ECMAObject, NAME_DICTIONARY_OFFSET, SIZE) + DECL_DUMP() protected: - void CopyModuleInternal(const JSThread *thread, JSHandle srcModule); + static void CopyModuleInternal(const JSThread *thread, JSHandle dstModule, + JSHandle srcModule); friend class ModuleManager; }; @@ -79,6 +82,8 @@ public: JSHandle GetModule(const JSThread *thread, JSHandle moduleName); + CString GenerateModuleFullPath(const std::string ¤tPathFile, const CString &relativeFile); + const CString &GetCurrentExportModuleName(); const CString &GetPrevExportModuleName(); diff --git a/ecmascript/ecma_string.cpp b/ecmascript/ecma_string.cpp index 51e300d39fb69724db2b3b805fc4a873eb1984b3..797848f2a24da75b6439241a60c6a7ff96239fbc 100644 --- a/ecmascript/ecma_string.cpp +++ b/ecmascript/ecma_string.cpp @@ -415,7 +415,7 @@ uint32_t EcmaString::ComputeHashcode() const hash = ComputeHashForData(GetDataUtf16(), GetLength()); } } else { - ASSERT(static_cast(GetLength()) > (std::numeric_limits::max() >> 1U)); + ASSERT(static_cast(GetLength()) < (std::numeric_limits::max() >> 1U)); hash = ComputeHashForData(GetDataUtf16(), GetLength()); } return hash; diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index 499295787b1dc9e21cf603ddf98a1ca1da7f96d4..453b2d12506ca847e00362f9a3d15826078887d4 100644 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -45,6 +45,13 @@ public: static EcmaString *FastSubString(const JSHandle &src, uint32_t start, uint32_t utf16Len, const EcmaVM *vm); + static constexpr uint32_t STRING_COMPRESSED_BIT = 0x1; + static constexpr uint32_t STRING_INTERN_BIT = 0x2; + enum CompressedStatus { + STRING_COMPRESSED, + STRING_UNCOMPRESSED, + }; + template uint16_t At(int32_t index) const; @@ -138,7 +145,7 @@ public: } return length; } - return base::utf_helper::ConvertRegionUtf16ToUtf8(GetDataUtf16(), buf, length, maxLength - 1, start) - 1; + return base::utf_helper::ConvertRegionUtf16ToUtf8(GetDataUtf16(), buf, length, maxLength - 1, start); } inline uint32_t CopyDataUtf16(uint16_t *buf, uint32_t maxLength) const @@ -285,12 +292,6 @@ private: static void CopyUtf16AsUtf8(const uint16_t *utf16From, uint8_t *utf8To, uint32_t utf16Len); static bool compressedStringsEnabled; - static constexpr uint32_t STRING_COMPRESSED_BIT = 0x1; - static constexpr uint32_t STRING_INTERN_BIT = 0x2; - enum CompressedStatus { - STRING_COMPRESSED, - STRING_UNCOMPRESSED, - }; static bool IsASCIICharacter(uint16_t data) { diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index fd4b50b2c722b23b3b1d57640e208a8aebd1a2c8..761862a89255f6dec75db936724a13fb310e0b59 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -22,6 +22,7 @@ #include "ecmascript/class_linker/program_object-inl.h" #include "ecmascript/ecma_module.h" #include "ecmascript/ecma_string_table.h" +#include "ecmascript/global_dictionary.h" #include "ecmascript/global_env.h" #include "ecmascript/global_env_constants-inl.h" #include "ecmascript/global_env_constants.h" @@ -35,6 +36,7 @@ #include "ecmascript/mem/heap.h" #include "ecmascript/tagged_dictionary.h" #include "ecmascript/object_factory.h" +#include "ecmascript/platform/platform.h" #include "ecmascript/regexp/regexp_parser_cache.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/runtime_trampolines.h" @@ -54,9 +56,10 @@ namespace panda::ecmascript { // NOLINTNEXTLINE(fuchsia-statically-constructed-objects) static const std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; +JSRuntimeOptions EcmaVM::options_; // NOLINT(fuchsia-statically-constructed-objects) /* static */ -EcmaVM *EcmaVM::Create(const RuntimeOptions &options) +EcmaVM *EcmaVM::Create(const JSRuntimeOptions &options) { auto runtime = Runtime::GetCurrent(); auto vm = runtime->GetInternalAllocator()->New(options); @@ -91,18 +94,18 @@ Expected EcmaVM::Create(Runtime *runtime) } // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) -EcmaVM::EcmaVM() : EcmaVM(Runtime::GetOptions()) +EcmaVM::EcmaVM() : EcmaVM(EcmaVM::GetJSOptions()) { isTestMode_ = true; } -EcmaVM::EcmaVM(RuntimeOptions options) - : options_(std::move(options)), - stringTable_(new EcmaStringTable(this)), +EcmaVM::EcmaVM(JSRuntimeOptions options) + : stringTable_(new EcmaStringTable(this)), regionFactory_(std::make_unique()), chunk_(regionFactory_.get()), nativeMethods_(&chunk_) { + options_ = std::move(options); icEnable_ = options_.IsIcEnable(); rendezvous_ = chunk_.New(); snapshotSerializeEnable_ = options_.IsSnapshotSerializeEnabled(); @@ -111,12 +114,16 @@ EcmaVM::EcmaVM(RuntimeOptions options) } fileName_ = options_.GetSnapshotFile(); frameworkAbcFileName_ = options_.GetFrameworkAbcFile(); + + auto runtime = Runtime::GetCurrent(); + notificationManager_ = chunk_.New(runtime->GetInternalAllocator()); + notificationManager_->SetRendezvous(rendezvous_); } bool EcmaVM::Initialize() { trace::ScopedTrace scoped_trace("EcmaVM::Initialize"); - + Platform::GetCurrentPlatform()->Initialize(); RuntimeTrampolines::InitializeRuntimeTrampolines(thread_); auto globalConst = const_cast(thread_->GlobalConstants()); @@ -153,13 +160,16 @@ bool EcmaVM::Initialize() globalEnv->SetEmptyArray(thread_, factory_->NewEmptyArray()); globalEnv->SetEmptyLayoutInfo(thread_, factory_->CreateLayoutInfo(0)); globalEnv->SetRegisterSymbols(thread_, JSTaggedValue(SymbolTable::Create(thread_))); - globalEnv->SetGlobalRecord(thread_, JSTaggedValue(NameDictionary::Create(thread_))); + globalEnv->SetGlobalRecord(thread_, JSTaggedValue(GlobalDictionary::Create(thread_))); JSTaggedValue emptyStr = thread_->GlobalConstants()->GetEmptyString(); stringTable_->InternEmptyString(EcmaString::Cast(emptyStr.GetTaggedObject())); globalEnv->SetEmptyTaggedQueue(thread_, factory_->NewTaggedQueue(0)); globalEnv->SetTemplateMap(thread_, JSTaggedValue(TemplateMap::Create(thread_))); globalEnv->SetRegisterSymbols(GetJSThread(), JSTaggedValue(SymbolTable::Create(GetJSThread()))); - +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + std::string moduleFile = options_.GetStubModuleFile(); + thread_->LoadFastStubModule(moduleFile.c_str()); +#endif SetupRegExpResultCache(); microJobQueue_ = factory_->NewMicroJobQueue().GetTaggedValue(); @@ -181,8 +191,8 @@ bool EcmaVM::Initialize() moduleManager_ = new ModuleManager(this); InitializeFinish(); - Runtime::GetCurrent()->GetNotificationManager()->VmStartEvent(); - Runtime::GetCurrent()->GetNotificationManager()->VmInitializationEvent(0); + notificationManager_->VmStartEvent(); + notificationManager_->VmInitializationEvent(0); return true; } @@ -231,6 +241,7 @@ bool EcmaVM::InitializeFinish() } EcmaVM::~EcmaVM() { + Platform::GetCurrentPlatform()->Destory(); vmInitialized_ = false; ClearNativeMethodsData(); @@ -259,6 +270,11 @@ EcmaVM::~EcmaVM() delete regExpParserCache_; regExpParserCache_ = nullptr; + if (notificationManager_ != nullptr) { + chunk_.Delete(notificationManager_); + notificationManager_ = nullptr; + } + if (factory_ != nullptr) { chunk_.Delete(factory_); factory_ = nullptr; @@ -435,7 +451,7 @@ Expected EcmaVM::InvokeEcmaEntrypoint(const panda_file::Fil params->MakeArgList(*jsargs); panda::ecmascript::InvokeJsFunction(thread_, func, global, newTarget, params); if (!thread_->HasPendingException()) { - job::MicroJobQueue::Cast(microJobQueue_.GetTaggedObject())->ExecutePendingJob(thread_); + job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); } // print exception information @@ -452,7 +468,7 @@ void EcmaVM::AddPandaFile(const panda_file::File *pf, bool isModule) pandaFileWithProgram_.push_back(std::make_tuple(nullptr, pf, isModule)); // for debugger - Runtime::GetCurrent()->GetNotificationManager()->LoadModuleEvent(pf->GetFilename()); + notificationManager_->LoadModuleEvent(pf->GetFilename()); } void EcmaVM::SetProgram(Program *program, const panda_file::File *pf) @@ -636,7 +652,7 @@ void EcmaVM::ClearBufferData() bool EcmaVM::ExecutePromisePendingJob() const { if (!thread_->HasPendingException()) { - job::MicroJobQueue::Cast(microJobQueue_.GetTaggedObject())->ExecutePendingJob(thread_); + job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); return true; } return false; @@ -679,12 +695,13 @@ void EcmaVM::SetMicroJobQueue(job::MicroJobQueue *queue) JSHandle EcmaVM::GetModuleByName(JSHandle moduleName) { - CString dirPath; - CString scriptName = ConvertToString(EcmaString::Cast(moduleName->GetTaggedObject())); + auto currentFileTuple = pandaFileWithProgram_.back(); + auto currentFileInfo = std::get<1>(currentFileTuple); + std::string currentPathFile = currentFileInfo->GetFilename(); + CString relativeFile = ConvertToString(EcmaString::Cast(moduleName->GetTaggedObject())); - // need to check abc file - auto pos = scriptName.find_last_of('.'); - CString abcPath = dirPath.append(scriptName.substr(0, pos == std::string::npos ? 0 : pos)).append(".abc"); + // generate full path + CString abcPath = moduleManager_->GenerateModuleFullPath(currentPathFile, relativeFile); // Uniform module name JSHandle abcModuleName = factory_->NewFromString(abcPath); diff --git a/ecmascript/ecma_vm.h b/ecmascript/ecma_vm.h index 94c5079c8586313a860ddc126f212a018091898a..d100ccfdba553bf475578772a48223397147111b 100644 --- a/ecmascript/ecma_vm.h +++ b/ecmascript/ecma_vm.h @@ -24,6 +24,7 @@ #include "ecmascript/js_handle.h" #include "ecmascript/js_method.h" #include "ecmascript/js_native_pointer.h" +#include "ecmascript/js_runtime_options.h" #include "ecmascript/mem/c_containers.h" #include "ecmascript/mem/c_string.h" #include "ecmascript/mem/chunk_containers.h" @@ -38,6 +39,7 @@ #include "libpandabase/os/library_loader.h" namespace panda { +class RuntimeNotificationManager; namespace panda_file { class File; } // namespace panda_file @@ -74,11 +76,11 @@ public: return reinterpret_cast(object); } - static EcmaVM *Create(const RuntimeOptions &options); + static EcmaVM *Create(const JSRuntimeOptions &options); static bool Destroy(PandaVM *vm); - explicit EcmaVM(RuntimeOptions options); + explicit EcmaVM(JSRuntimeOptions options); static Expected Create([[maybe_unused]] Runtime *runtime); @@ -210,6 +212,11 @@ public: } const RuntimeOptions &GetOptions() const override + { + return Runtime::GetOptions(); + } + + static const JSRuntimeOptions &GetJSOptions() { return options_; } @@ -330,23 +337,16 @@ public: return moduleManager_; } - static constexpr uint32_t GetGlobalEnvOffset() - { - return MEMBER_OFFSET(EcmaVM, globalEnv_); - } - - static constexpr uint32_t GetMicroJobQueueOffset() - { - return MEMBER_OFFSET(EcmaVM, microJobQueue_); - } - void SetupRegExpResultCache(); JSHandle GetRegExpCache() { return JSHandle(reinterpret_cast(®expCache_)); } - friend class ValueSerializer; + RuntimeNotificationManager *GetNotificationManager() const + { + return notificationManager_; + } protected: bool CheckEntrypointSignature([[maybe_unused]] Method *entrypoint) override @@ -389,7 +389,7 @@ private: NO_COPY_SEMANTIC(EcmaVM); // init EcmaVM construct - RuntimeOptions options_; + static JSRuntimeOptions options_; EcmaStringTable *stringTable_; std::unique_ptr regionFactory_; Chunk chunk_; @@ -403,6 +403,7 @@ private: CString frameworkAbcFileName_; bool isTestMode_{false}; + RuntimeNotificationManager *notificationManager_ {nullptr}; // init EcmaVM Create JSThread *thread_{nullptr}; @@ -433,6 +434,8 @@ private: friend class SnapShotSerialize; friend class ObjectFactory; + friend class ValueSerializer; + friend class panda::JSNApi; }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/frames.h b/ecmascript/frames.h index dc5c0022865afcd0c0ac708b802e7959a959027a..6b292763c50b5f8b2cbf57141bccf0363c4ba80e 100644 --- a/ecmascript/frames.h +++ b/ecmascript/frames.h @@ -13,42 +13,257 @@ * limitations under the License. */ +// in aot project, three Frame: Interpreter Frame、Runtime Frame、Optimized Frame. Optimized Frame split +// Optimized Entry Frame(interpreter call stub) and Optimized Frame(stub call stub) by call scenario. +// ​we gc trigger, we skip Runtime Frame, thus define OPTIMIZED_FRAME、OPTIMIZED_ENTRY_FRAME、 +// INTERPRETER_FRAME respectively +// represent optimized frame、optimized entry frame、interpreter frame. + +// Frame Layout +// Interpreter Frame(alias **iframe** ) Layout as follow: +// ``` +// +---------------------------------+--------------------+ +// | argv[n-1] | ^ +// |----------------------------------| | +// | ........ | | +// | argv[0] | | +// |----------------------------------| | +// | thisArg | | +// |----------------------------------| | +// | newTarget | | +// |----------------------------------| | +// | callTarget | | +// +----------------------------------+--------+ | +// | FrameType | ^ interpreter frame +// |----------------------------------| | | +// | pre(pre stack pointer) | | | +// |----------------------------------| | | +// | numActualArgs | | | +// |----------------------------------| | | +// | env | | | +// |----------------------------------| | | +// | acc | FrameState | +// |----------------------------------| | | +// | constantpool | | | +// |----------------------------------| | | +// | method | | | +// |----------------------------------| | | +// | sp(current stack point) | | | +// |----------------------------------| | | +// | pc(bytecode addr) | v v +// +----------------------------------+--------+----------+ +// ``` +// address space grow from high address to low address.we add new field **FrameType** , +// the field's value is INTERPRETER_FRAME(represent interpreter frame). +// **currentsp** is pointer to callTarget field address, sp field 's value is **currentsp** , +// pre field pointer pre stack frame point. fill JSthread's sp field with iframe sp field +// by calling JSThread->SetCurrentSPFrame and save pre Frame address to iframe pre field. + +// Runtime Frame: comply with C-ABI without custom modify, function generat frame. +// ​ +// Optimized Frame and Optimized Entry Frame, we also comply with C-ABI, +// the difference from Runtime Frame is that prologue and epilogue is customed. + +// Optimized Entry Frame layout as follow, we reserve two stack slot for saving eparately new field **FrameType** +// which's value is OPTIMIZED_ENTRY_FRAME and +// new field pre that's value is iframe.sp by calling JSThread->GetCurrentSPFrame. +// fp field point to pre frame, **currentfp** is pointer to fp field address. +// save JSthread's sp to pre field and fill JSthread's sp field with **currentfp** . + + +// ``` +// +---------------------------------------------------+ +// | parameter i | ^ +// |- - - - - - - - - -- | | +// | parameter n-2 | Caller frame +// | ... | comply c-abi +// | parameter n-1 | paramters push to stack from left to right +// |- - - - - - - - - | i-n th prameter spill to slot +// | parameter n | v +// +--------------------------+------------------------+ +// | return addr | ^ ^ +// |- - - - - - - - - | | | +// | fp | Fixed | +// |- - - - - - - - - | Header <-- frame ptr | +// | FrameType | | callee frame Header +// |- - - - - - - - - | | | +// | pre | v | +// +--------------------------+------------------------+ +// ``` + +// ​ Optimized Frame layout as follow, we reserve one stack slot for saving FrameType field, +// which's value is OPTIMIZED_FRAME. + +// ``` +// +---------------------------------------------------+ +// | parameter n | ^ +// |- - - - - - - - - -- | | +// | parameter n-1 | Caller frame +// | ... | comply c-abi +// | parameter n-2 | paramters push to stack from left to right +// |- - - - - - - - - | i-n th prameter spill to slot +// | parameter i | v +// +--------------------------+------------------------+ +// | return addr | ^ ^ +// |- - - - - - - - - | | | +// | fp | Fixed | +// |- - - - - - - - - | Header <-- frame ptr callee frame Header +// | FrameType | V | +// +--------------------------+------------------------+ +// ``` + +// ​ JSthread's sp will be updated dynamic, the scenarios is as follows by different Frames: +// **SAVE** is to save JSthread's sp to current Frame pre field, +// **UPDATE** is to fill JSthread's sp with currentsp or currentfp when current frame is iframe +// or Optimized EntryFrame/Optimized Frame. +// **nop** represent don't call SAVE or UPDATE, **illegal** represent this secnarios don't existed. + +// +----------------------------------------------------------------------+ +// | | iframe | OptimizedEntry | Optimized | RunTime | +// |----------------------------------------------------------------------- +// |iframe | SAVE/UPATE | SAVE | illegal | SAVE/UPATE | +// |----------------------------------------------------------------------- +// |OptimizedEntry | UPATE | illegal | nop | UPATE | +// |----------------------------------------------------------------------- +// |Optimized | UPATE | illegal | nop | UPATE | +// |----------------------------------------------------------------------- +// |RunTime | nop | illegal | illegal | nop | +// +----------------------------------------------------------------------+ +// ``` + +// ​ Iterator Frame from Runtime Frame, the process is as flollows: + +// 1 calling JSThread->GetCurrentSPFrame get Current Frame, then get FrameType field + +// 2 Iterator previous Frame: + +// ​ accessing fp field when the current frame is Optimized Frame; + +// ​ accessing pre field when the current frame is Optimized Entry Frame or Interpreter Frame + +// 3 repeat process 2 until Current Frame is nullptr + +// For Example: +// ``` +// call call call +// foo -----------------> bar --------------->baz---------------------> rtfunc +// (interpret frame) (Optimized Entry Frame) (Optimized Frame) (Runtime Frame) +// ``` + +// Frame Layout as follow: +// ``` +// +---------------------------------+--------------------+ +// | argv[n-1] | ^ +// |----------------------------------| | +// | ........ | | +// | argv[0] | | +// |----------------------------------| | +// | thisArg | | +// |----------------------------------| | +// | newTarget | | +// |----------------------------------| | +// | callTarget | | +// +----------------------------------+--------+ | +// | FrameType | ^ foo's frame +// |----------------------------------| | | +// | pre(pre stack pointer) | | | +// |----------------------------------| | | +// | numActualArgs | | | +// |----------------------------------| | | +// | env | | | +// |----------------------------------| | | +// | acc | FrameState | +// |----------------------------------| | | +// | constantpool | | | +// |----------------------------------| | | +// | method | | | +// |----------------------------------| | | +// | sp(current stack point) | | | +// |----------------------------------| | | +// | pc(bytecode addr) | v v +// +----------------------------------+--------+----------+ +// | ............. | +// +--------------------------+---------------------------+ +// | return addr | ^ ^ +// |- - - - - - - - - | | | +// | fp | Fixed | +// |- - - - - - - - - | Header <-- frame ptr | +// | FrameType | | bar's frame Header +// |- - - - - - - - - | | | +// | pre | v | +// +--------------------------+---------------------------+ +// | ............. | +// +--------------------------+---------------------------+ +// | return addr | ^ ^ +// |- - - - - - - - - | | | +// | fp | Fixed | +// |- - - - - - - - - | Header <-- frame ptr | +// | FrameType | v baz's frame Header +// | ............. | +// +--------------------------+---------------------------+ +// | | +// | rtfunc's Frame | +// | | +// +------------------------------------------------------+ +// ``` +// Iterator: +// rtfunc get baz's Frame **currentfp** by calling GetCurrentSPFrame. +// baz'Frame fp field point to bar's Frame **currentfp**, then get bar's Frame pre field. +// bar's Frame pre field point to foo's Frame **currentsp**. +// finally we can iterator foo's Frame. + #ifndef ECMASCRIPT_FRAMES_H #define ECMASCRIPT_FRAMES_H +#include "ecmascript/js_tagged_value.h" + +#ifdef PANDA_TARGET_AMD64 +#define GET_CURRETN_FP(fp) asm("mov %%rbp, %0" : "=rm" (fp)) +#define POINTER_CAST(fp, type) static_cast(static_cast(fp) +#define GET_PREV_FP(fp) reinterpret_cast(*(fp)) +#else +#define GET_CURRETN_FP(fp) +#define POINTER_CAST(fp, type) static_cast(static_cast(fp)) +#define GET_PREV_FP(fp) reinterpret_cast(*(POINTER_CAST(fp, uintptr_t *))) +#endif + namespace panda::ecmascript { -enum class FrameType: unsigned int { +class JSThread; +enum class FrameType: uintptr_t { OPTIMIZED_FRAME = 0, OPTIMIZED_ENTRY_FRAME = 1, INTERPRETER_FRAME = 2, }; -template -auto as_integer(Enumeration const value) --> typename std::underlying_type::type -{ - return static_cast::type>(value); -} +class OptimizedFrameStateBase { +public: + uintptr_t frameType; + JSTaggedType *prev; // for llvm :c-fp ; for interrupt: thread-fp for gc + static size_t GetFrameStateOffsetFromSp() + { + return MEMBER_OFFSET(OptimizedFrameStateBase, prev); + } +}; -class FrameStateBase { +class InterpretedFrameStateBase { public: - FrameType frameType; - uint64_t *prev; // for llvm :c-fp ; for interrupt: thread-fp for gc + JSTaggedType *prev; // for llvm :c-fp ; for interrupt: thread-fp for gc + uintptr_t frameType; }; -class LLVMBoundaryFrameState { +class OptimizedEntryFrameState { public: - uint64_t *threadFp; // for gc - FrameStateBase base; + JSTaggedType *threadFp; // for gc + OptimizedFrameStateBase base; + static size_t GetFrameStateOffsetFromSp() + { + return MEMBER_OFFSET(OptimizedEntryFrameState, base.prev); + } }; -constexpr int kSystemPointerSize = sizeof(void*); class FrameConst { public: - uint64_t *prev; - FrameType frameType; - static constexpr int kPreOffset = -kSystemPointerSize; - static constexpr int kFrameType = -2 * kSystemPointerSize; + static constexpr size_t FRAME_TYPE_OFFSET = -sizeof(uintptr_t); }; } // namespace panda::ecmascript -#endif // ECMASCRIPT_FRAMES_H \ No newline at end of file +#endif // ECMASCRIPT_FRAMES_H diff --git a/ecmascript/global_env.h b/ecmascript/global_env.h index 6a9eff025f7caa0f9e8d2c21820f3f5d6270618a..2181d1fdfcf1ad15fa324218e5e95f9831979555 100644 --- a/ecmascript/global_env.h +++ b/ecmascript/global_env.h @@ -137,7 +137,6 @@ class JSThread; V(JSTaggedValue, JSIntlBoundFunctionClass, JS_INTL_BOUND_FUNCTION_CLASS) \ V(JSTaggedValue, NumberFormatLocales, NUMBER_FORMAT_LOCALES_INDEX) \ V(JSTaggedValue, DateTimeFormatLocales, DATE_TIMEFORMAT_LOCALES_INDEX) \ - V(JSTaggedValue, JSNativeObjectClass, JS_NATIVE_OBJECT_CLASS) \ V(JSTaggedValue, GlobalRecord, GLOBAL_RECORD) class GlobalEnv : public TaggedObject { diff --git a/ecmascript/hprof/heap_profiler.cpp b/ecmascript/hprof/heap_profiler.cpp index 42a38012445c67c29ee2e0992bae98375ab68f65..016eed3907ff852cf28b45b70004541e6a4fd033 100644 --- a/ecmascript/hprof/heap_profiler.cpp +++ b/ecmascript/hprof/heap_profiler.cpp @@ -23,6 +23,7 @@ #include "ecmascript/hprof/heap_snapshot.h" #include "ecmascript/js_thread.h" #include "ecmascript/mem/assert_scope-inl.h" +#include "ecmascript/mem/concurrent_sweeper.h" #include "ecmascript/mem/heap.h" namespace panda::ecmascript { @@ -33,7 +34,7 @@ HeapProfiler::~HeapProfiler() jsonSerializer_ = nullptr; } -bool HeapProfiler::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath) +bool HeapProfiler::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath, bool isVmMode) { [[maybe_unused]] bool heapClean = ForceFullGC(thread); ASSERT(heapClean); @@ -41,7 +42,7 @@ bool HeapProfiler::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, con size_t heapSize = heap->GetNewSpace()->GetHeapObjectSize() + heap->GetOldSpace()->GetHeapObjectSize() + heap->GetNonMovableSpace()->GetHeapObjectSize(); LOG(ERROR, RUNTIME) << "HeapProfiler DumpSnapshot heap size " << heapSize; - HeapSnapShot *snapShot = MakeHeapSnapShot(thread, SampleType::ONE_SHOT); + HeapSnapShot *snapShot = MakeHeapSnapShot(thread, SampleType::ONE_SHOT, isVmMode); ASSERT(snapShot != nullptr); std::pair realPath = FilePathValid(filePath); if (realPath.first) { @@ -55,9 +56,9 @@ bool HeapProfiler::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, con UNREACHABLE(); } -bool HeapProfiler::StartHeapTracking(JSThread *thread, double timeInterval) +bool HeapProfiler::StartHeapTracking(JSThread *thread, double timeInterval, bool isVmMode) { - HeapSnapShot *snapShot = MakeHeapSnapShot(thread, SampleType::REAL_TIME); + HeapSnapShot *snapShot = MakeHeapSnapShot(thread, SampleType::REAL_TIME, isVmMode); if (snapShot == nullptr) { return false; } @@ -157,13 +158,15 @@ bool HeapProfiler::ForceFullGC(JSThread *thread) return false; } -HeapSnapShot *HeapProfiler::MakeHeapSnapShot(JSThread *thread, SampleType sampleType) +HeapSnapShot *HeapProfiler::MakeHeapSnapShot(JSThread *thread, SampleType sampleType, bool isVmMode) { LOG(ERROR, RUNTIME) << "HeapProfiler::MakeHeapSnapShot"; DISALLOW_GARBAGE_COLLECTION; + heap_->GetSweeper()->EnsureAllTaskFinish(); switch (sampleType) { case SampleType::ONE_SHOT: { - auto *snapShot = const_cast(heap_->GetRegionFactory())->New(thread, heap_); + auto *snapShot = + const_cast(heap_->GetRegionFactory())->New(thread, heap_, isVmMode); if (snapShot == nullptr) { LOG_ECMA(FATAL) << "alloc snapshot failed"; UNREACHABLE(); @@ -173,7 +176,8 @@ HeapSnapShot *HeapProfiler::MakeHeapSnapShot(JSThread *thread, SampleType sample return snapShot; } case SampleType::REAL_TIME: { - auto *snapShot = const_cast(heap_->GetRegionFactory())->New(thread, heap_); + auto *snapShot = + const_cast(heap_->GetRegionFactory())->New(thread, heap_, isVmMode); if (snapShot == nullptr) { LOG_ECMA(FATAL) << "alloc snapshot failed"; UNREACHABLE(); diff --git a/ecmascript/hprof/heap_profiler.h b/ecmascript/hprof/heap_profiler.h index a516645df78e51fd5ad0247c38c5b7914091fa3c..2510247298c07c01b5109cc0f3bf15db42e3a606 100644 --- a/ecmascript/hprof/heap_profiler.h +++ b/ecmascript/hprof/heap_profiler.h @@ -44,10 +44,10 @@ public: /** * dump the specific snapshot in target format */ - bool DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &path); + bool DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &path, bool isVmMode = true); void AddSnapShot(HeapSnapShot *snapshot); - bool StartHeapTracking(JSThread *thread, double timeInterval) override; + bool StartHeapTracking(JSThread *thread, double timeInterval, bool isVmMode = true) override; bool StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const CString &filePath) override; private: @@ -59,7 +59,7 @@ private: /** * make a new heap snapshot and put it into a container eg, vector */ - HeapSnapShot *MakeHeapSnapShot(JSThread *thread, SampleType sampleType); + HeapSnapShot *MakeHeapSnapShot(JSThread *thread, SampleType sampleType, bool isVmMode = true); std::pair FilePathValid(const CString &filePath); CString GenDumpFileName(DumpFormat dumpFormat); CString GetTimeStamp(); diff --git a/ecmascript/hprof/heap_profiler_interface.cpp b/ecmascript/hprof/heap_profiler_interface.cpp index 0292c07942560ee71e3e6cf3a98e7f4f27a8add4..715ff9838b78855859f6cb5b0eec0ce0c99bdba5 100644 --- a/ecmascript/hprof/heap_profiler_interface.cpp +++ b/ecmascript/hprof/heap_profiler_interface.cpp @@ -18,7 +18,7 @@ #include "ecmascript/mem/heap.h" namespace panda::ecmascript { -void HeapProfilerInterface::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath) +void HeapProfilerInterface::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath, bool isVmMode) { LOG(ERROR, RUNTIME) << "HeapProfilerInterface::DumpHeapSnapshot"; const Heap *heap = thread->GetEcmaVM()->GetHeap(); @@ -27,7 +27,7 @@ void HeapProfilerInterface::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFo LOG_ECMA(FATAL) << "alloc hprof failed"; UNREACHABLE(); } - hprof->DumpHeapSnapShot(thread, dumpFormat, filePath); + hprof->DumpHeapSnapShot(thread, dumpFormat, filePath, isVmMode); const_cast(heap->GetRegionFactory())->Delete(hprof); } diff --git a/ecmascript/hprof/heap_profiler_interface.h b/ecmascript/hprof/heap_profiler_interface.h index 736f8167479484e0a28dbfb5185e1cd26edb67a3..e7a864100dc6e1206b5b090fa737abd86bdf5545 100644 --- a/ecmascript/hprof/heap_profiler_interface.h +++ b/ecmascript/hprof/heap_profiler_interface.h @@ -24,7 +24,8 @@ enum class DumpFormat { JSON, BINARY, OTHER }; class HeapProfilerInterface { public: - static void DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath); + static void DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, + const CString &filePath, bool isVmMode = true); static HeapProfilerInterface *CreateHeapProfiler(JSThread *thread); static void Destory(JSThread *thread, HeapProfilerInterface *heapProfiler); @@ -32,7 +33,7 @@ public: HeapProfilerInterface() = default; virtual ~HeapProfilerInterface() = default; - virtual bool StartHeapTracking(JSThread *thread, double timeInterval) = 0; + virtual bool StartHeapTracking(JSThread *thread, double timeInterval, bool isVmMode = true) = 0; virtual bool StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const CString &filePath) = 0; NO_MOVE_SEMANTIC(HeapProfilerInterface); diff --git a/ecmascript/hprof/heap_snapshot.cpp b/ecmascript/hprof/heap_snapshot.cpp index 5145640c4b74730afe0d012e006c4ffadfe0c787..1523cd4f9d5388318db9352acdcf8ff6ccb09f86 100644 --- a/ecmascript/hprof/heap_snapshot.cpp +++ b/ecmascript/hprof/heap_snapshot.cpp @@ -142,204 +142,36 @@ void HeapSnapShot::MoveNode(uintptr_t address, uintptr_t forward_address) // NOLINTNEXTLINE(readability-function-size) CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) { - CString *name = GetString("UnKnownType"); auto *hCls = entry->GetClass(); - if (hCls->IsTaggedArray()) { - CString arrayName; - TaggedArray *array = TaggedArray::Cast(entry); - if (hCls->IsDictionary()) { - arrayName = "TaggedDict["; - arrayName.append(ToCString(array->GetLength())); - arrayName.append("]"); - } else { + JSType type = hCls->GetObjectType(); + switch (type) { + case JSType::TAGGED_ARRAY: { + CString arrayName; + TaggedArray *array = TaggedArray::Cast(entry); arrayName = "TaggedArray["; arrayName.append(ToCString(array->GetLength())); arrayName.append("]"); + return GetString(arrayName); // String type was handled singly, see#GenerateStringNode } - name = GetString(arrayName); // String type was handled singly, see#GenerateStringNode - } else if (hCls->IsHClass()) { - name = GetString("HiddenClass"); - } else if (hCls->IsJSNativePointer()) { - name = GetString("JSNativePointer"); - } else { - if (hCls->IsRealm()) { - name = GetString("JSRealm"); - } else if (hCls->IsString()) { - name = GetString("JsString"); - } else if (hCls->IsJSSymbol()) { - name = GetString("JSSymbol"); - } else if (hCls->IsJSArray()) { - JSArray *jsArray = JSArray::Cast(entry); - CString arrayName("JSArray["); - arrayName.append(ToCString(jsArray->GetLength().GetInt())); - arrayName.append("]"); - name = GetString(arrayName); - } else if (hCls->IsTypedArray()) { - name = GetString("TypedArray"); - } else if (hCls->IsJSTypedArray()) { - name = GetString("JSTypedArray"); - } else if (hCls->IsJSInt8Array()) { - name = GetString("JSInt8Array"); - } else if (hCls->IsJSUint8Array()) { - name = GetString("JSUint8Array"); - } else if (hCls->IsJSUint8ClampedArray()) { - name = GetString("JSUint8ClampedArray"); - } else if (hCls->IsJSInt16Array()) { - name = GetString("JSInt16Array"); - } else if (hCls->IsJSUint16Array()) { - name = GetString("JSUint16Array"); - } else if (hCls->IsJSInt32Array()) { - name = GetString("JSInt32Array"); - } else if (hCls->IsJSUint32Array()) { - name = GetString("JSUint32Array"); - } else if (hCls->IsJSFloat32Array()) { - name = GetString("JSFloat32Array"); - } else if (hCls->IsJSFloat64Array()) { - name = GetString("JSFloat64Array"); - } else if (hCls->IsJsGlobalEnv()) { - name = GetString("JSGlobalEnv"); - } else if (hCls->IsJSFunctionBase()) { - name = GetString("JSFunctionBase"); - } else if (hCls->IsJsBoundFunction()) { - name = GetString("JsBoundFunction"); - } else if (hCls->IsJSIntlBoundFunction()) { - name = GetString("JSIntlBoundFunction"); - } else if (hCls->IsJSProxyRevocFunction()) { - name = GetString("JSProxyRevocFunction"); - } else if (hCls->IsJSAsyncFunction()) { - name = GetString("JSAsyncFunction"); - } else if (hCls->IsJSAsyncAwaitStatusFunction()) { - name = GetString("JSAsyncAwaitStatusFunction"); - } else if (hCls->IsJSPromiseReactionFunction()) { - name = GetString("JSPromiseReactionFunction"); - } else if (hCls->IsJSPromiseExecutorFunction()) { - name = GetString("JSPromiseExecutorFuncton"); - } else if (hCls->IsJSPromiseAllResolveElementFunction()) { - name = GetString("JSPromiseAllResolveElementFunction"); - } else if (hCls->IsJSFunctionExtraInfo()) { - name = GetString("JSFunctionExtraInfo"); - } else if (hCls->IsMicroJobQueue()) { - name = GetString("MicroJobQueue"); - } else if (hCls->IsPendingJob()) { - name = GetString("PendingJob"); - } else if (hCls->IsJsPrimitiveRef()) { - name = GetString("JsPrimitiveRef"); - } else if (hCls->IsJSSet()) { - name = GetString("JSSet"); - } else if (hCls->IsJSMap()) { - name = GetString("JSMap"); - } else if (hCls->IsJSWeakMap()) { - name = GetString("JSWeakMap"); - } else if (hCls->IsJSWeakSet()) { - name = GetString("JSWeakSet"); - } else if (hCls->IsJSFunction()) { - name = GetString("JSFunction"); - } else if (hCls->IsJSError()) { - name = GetString("JSError"); - } else if (hCls->IsArguments()) { - name = GetString("Arguments"); - } else if (hCls->IsDate()) { - name = GetString("Date"); - } else if (hCls->IsJSRegExp()) { - name = GetString("JSRegExp"); - } else if (hCls->IsJSProxy()) { - name = GetString("JSProxy"); - } else if (hCls->IsJSLocale()) { - name = GetString("JSLocale"); - } else if (hCls->IsJSIntl()) { - name = GetString("JSIntl"); - } else if (hCls->IsJSDateTimeFormat()) { - name = GetString("JSDateTimeFormat"); - } else if (hCls->IsJSRelativeTimeFormat()) { - name = GetString("JSRelativeTimeFormat"); - } else if (hCls->IsJSNumberFormat()) { - name = GetString("JSNumberFormat"); - } else if (hCls->IsAccessorData()) { - name = GetString("AccessorData"); - } else if (hCls->IsInternalAccessor()) { - name = GetString("InternalAccessor"); - } else if (hCls->IsIterator()) { - name = GetString("Iterator"); - } else if (hCls->IsForinIterator()) { - name = GetString("ForinIterator"); - } else if (hCls->IsStringIterator()) { - name = GetString("StringIterator"); - } else if (hCls->IsArrayBuffer()) { - name = GetString("ArrayBuffer"); - } else if (hCls->IsDataView()) { - name = GetString("DataView"); - } else if (hCls->IsJSSetIterator()) { - name = GetString("JSSetIterator"); - } else if (hCls->IsJSMapIterator()) { - name = GetString("JSMapIterator"); - } else if (hCls->IsJSArrayIterator()) { - name = GetString("JSArrayIterator"); - } else if (hCls->IsPrototypeHandler()) { - name = GetString("PrototypeHandler"); - } else if (hCls->IsTransitionHandler()) { - name = GetString("TransitionHandler"); - } else if (hCls->IsPropertyBox()) { - name = GetString("PropertyBox"); - } else if (hCls->IsProtoChangeMarker()) { - name = GetString("ProtoChangeMarker"); - } else if (hCls->IsProtoChangeDetails()) { - name = GetString("ProtoChangeDetails"); - } else if (hCls->IsProgram()) { - name = GetString("Program"); - } else if (hCls->IsEcmaModule()) { - name = GetString("EcmaModule"); - } else if (hCls->IsLexicalFunction()) { - name = GetString("LexicalFunction"); - } else if (hCls->IsConstructor()) { - name = GetString("Constructor"); - } else if (hCls->IsExtensible()) { - name = GetString("Extensible"); - } else if (hCls->IsPrototype()) { - name = GetString("Prototype"); - } else if (hCls->IsLiteral()) { - name = GetString("Literal"); - } else if (hCls->IsClassConstructor()) { - name = GetString("ClassConstructor"); - } else if (hCls->IsJSGlobalObject()) { - name = GetString("JSGlobalObject"); - } else if (hCls->IsClassPrototype()) { - name = GetString("ClassPrototype"); - } else if (hCls->IsGeneratorFunction()) { - name = GetString("GeneratorFunction"); - } else if (hCls->IsGeneratorObject()) { - name = GetString("GeneratorObject"); - } else if (hCls->IsAsyncFuncObject()) { - name = GetString("AsyncFunction"); - } else if (hCls->IsJSPromise()) { - name = GetString("JSPromise"); - } else if (hCls->IsResolvingFunctionsRecord()) { - name = GetString("ResolvingFunctionsRecord"); - } else if (hCls->IsPromiseRecord()) { - name = GetString("PromiseRecord"); - } else if (hCls->IsPromiseIteratorRecord()) { - name = GetString("JSPromiseIteratorRecord"); - } else if (hCls->IsPromiseCapability()) { - name = GetString("PromiseCapability"); - } else if (hCls->IsPromiseReaction()) { - name = GetString("JSPromiseReaction"); - } else if (hCls->IsCompletionRecord()) { - name = GetString("CompletionRecord"); - } else if (hCls->IsRecord()) { - name = GetString("Record"); - } else if (hCls->IsTemplateMap()) { - name = GetString("TemplateMap"); - } else if (hCls->IsFreeObjectWithOneField()) { - name = GetString("FreeObjectWithOneField"); - } else if (hCls->IsFreeObjectWithTwoField()) { - name = GetString("FreeObjectWithTwoField"); - } else if (hCls->IsJSObject()) { + case JSType::HCLASS: + return GetString("HiddenClass"); + case JSType::TAGGED_DICTIONARY: { + CString dictName; + TaggedArray *dict = TaggedArray::Cast(entry); + dictName = "TaggedDict["; + dictName.append(ToCString(dict->GetLength())); + dictName.append("]"); + return GetString(dictName); + } + case JSType::STRING: + return GetString("BaseString"); + case JSType::JS_OBJECT: { const GlobalEnvConstants *globalConst = thread->GlobalConstants(); CString objName = CString("JSOBJECT(Ctor="); // Ctor-name JSTaggedValue proto = JSObject::Cast(entry)->GetPrototype(thread); JSHandle protoHandle(thread, proto); if (protoHandle->IsNull() || protoHandle->IsUndefined()) { - name = GetString("JSObject(Ctor=UnKnown)"); - return name; + return GetString("JSObject(Ctor=UnKnown)"); } JSHandle ctor = JSObject::GetProperty(thread, protoHandle, globalConst->GetHandledConstructorString()).GetValue(); @@ -348,16 +180,197 @@ CString *HeapSnapShot::GenerateNodeName(JSThread *thread, TaggedObject *entry) JSHandle value = JSObject::GetProperty(thread, ctor, nameKey).GetValue(); CString ctorName = EntryVisitor::ConvertKey(value.GetTaggedValue()); objName.append(ctorName).append(")"); - name = GetString(objName); } - } else if (hCls->IsECMAObject()) { - name = GetString("ECMAObject"); - } else { - name = GetString("UnEmuratedJSType"); + return GetString(objName); + } + case JSType::FREE_OBJECT_WITH_ONE_FIELD: + case JSType::FREE_OBJECT_WITH_NONE_FIELD: + case JSType::FREE_OBJECT_WITH_TWO_FIELD: + case JSType::JS_NATIVE_POINTER: + { + break; + } + case JSType::JS_FUNCTION_BASE: + return GetString("JSFunctionBase"); + case JSType::JS_FUNCTION: + return GetString("JSFunction"); + case JSType::JS_ERROR: + return GetString("Error"); + case JSType::JS_EVAL_ERROR: + return GetString("Eval Error"); + case JSType::JS_RANGE_ERROR: + return GetString("Range Error"); + case JSType::JS_TYPE_ERROR: + return GetString("Type Error"); + case JSType::JS_REFERENCE_ERROR: + return GetString("Reference Error"); + case JSType::JS_URI_ERROR: + return GetString("Uri Error"); + case JSType::JS_SYNTAX_ERROR: + return GetString("Syntax Error"); + case JSType::JS_REG_EXP: + return GetString("Regexp"); + case JSType::JS_SET: + return GetString("Set"); + case JSType::JS_MAP: + return GetString("Map"); + case JSType::JS_WEAK_SET: + return GetString("WeakSet"); + case JSType::JS_WEAK_MAP: + return GetString("WeakMap"); + case JSType::JS_DATE: + return GetString("Date"); + case JSType::JS_BOUND_FUNCTION: + return GetString("Bound Function"); + case JSType::JS_ARRAY: { + JSArray *jsArray = JSArray::Cast(entry); + CString jsArrayName("JSArray["); + jsArrayName.append(ToCString(jsArray->GetLength().GetInt())); + jsArrayName.append("]"); + return GetString(jsArrayName); + } + case JSType::JS_TYPED_ARRAY: + return GetString("Typed Array"); + case JSType::JS_INT8_ARRAY: + return GetString("Int8 Array"); + case JSType::JS_UINT8_ARRAY: + return GetString("Uint8 Array"); + case JSType::JS_UINT8_CLAMPED_ARRAY: + return GetString("Uint8 Clamped Array"); + case JSType::JS_INT16_ARRAY: + return GetString("Int16 Array"); + case JSType::JS_UINT16_ARRAY: + return GetString("Uint16 Array"); + case JSType::JS_INT32_ARRAY: + return GetString("Int32 Array"); + case JSType::JS_UINT32_ARRAY: + return GetString("Uint32 Array"); + case JSType::JS_FLOAT32_ARRAY: + return GetString("Float32 Array"); + case JSType::JS_FLOAT64_ARRAY: + return GetString("Float64 Array"); + case JSType::JS_ARGUMENTS: + return GetString("Arguments"); + case JSType::JS_PROXY: + return GetString("Proxy"); + case JSType::JS_PRIMITIVE_REF: + return GetString("Primitive"); + case JSType::JS_DATA_VIEW: + return GetString("DataView"); + case JSType::JS_ITERATOR: + return GetString("Iterator"); + case JSType::JS_FORIN_ITERATOR: + return GetString("ForinInterator"); + case JSType::JS_MAP_ITERATOR: + return GetString("MapIterator"); + case JSType::JS_SET_ITERATOR: + return GetString("SetIterator"); + case JSType::JS_ARRAY_ITERATOR: + return GetString("ArrayIterator"); + case JSType::JS_STRING_ITERATOR: + return GetString("StringIterator"); + case JSType::JS_ARRAY_BUFFER: + return GetString("ArrayBuffer"); + case JSType::JS_PROXY_REVOC_FUNCTION: + return GetString("ProxyRevocFunction"); + case JSType::PROMISE_REACTIONS: + return GetString("PromiseReaction"); + case JSType::PROMISE_CAPABILITY: + return GetString("PromiseCapability"); + case JSType::PROMISE_ITERATOR_RECORD: + return GetString("PromiseIteratorRecord"); + case JSType::PROMISE_RECORD: + return GetString("PromiseRecord"); + case JSType::RESOLVING_FUNCTIONS_RECORD: + return GetString("ResolvingFunctionsRecord"); + case JSType::JS_PROMISE: + return GetString("Promise"); + case JSType::JS_PROMISE_REACTIONS_FUNCTION: + return GetString("PromiseReactionsFunction"); + case JSType::JS_PROMISE_EXECUTOR_FUNCTION: + return GetString("PromiseExecutorFunction"); + case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION: + return GetString("PromiseAllResolveElementFunction"); + case JSType::JS_GENERATOR_FUNCTION: + return GetString("JSGeneratorFunction"); + case JSType::SYMBOL: + return GetString("Symbol"); + case JSType::JS_ASYNC_FUNCTION: + return GetString("AsyncFunction"); + case JSType::JS_INTL_BOUND_FUNCTION: + return GetString("JSIntlBoundFunction"); + case JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION: + return GetString("AsyncAwaitStatusFunction"); + case JSType::JS_ASYNC_FUNC_OBJECT: + return GetString("AsyncFunctionObject"); + case JSType::JS_REALM: + return GetString("Realm"); + case JSType::JS_GLOBAL_OBJECT: + return GetString("GlobalObject"); + case JSType::JS_INTL: + return GetString("JSIntl"); + case JSType::JS_LOCALE: + return GetString("JSLocale"); + case JSType::JS_DATE_TIME_FORMAT: + return GetString("JSDateTimeFormat"); + case JSType::JS_RELATIVE_TIME_FORMAT: + return GetString("JSRelativeTimeFormat"); + case JSType::JS_NUMBER_FORMAT: + return GetString("JSNumberFormat"); + case JSType::JS_COLLATOR: + return GetString("JSCollator"); + case JSType::JS_PLURAL_RULES: + return GetString("JSPluralRules"); + case JSType::JS_GENERATOR_OBJECT: + return GetString("JSGeneratorObject"); + case JSType::JS_GENERATOR_CONTEXT: + return GetString("JSGeneratorContext"); + case JSType::ACCESSOR_DATA: + return GetString("AccessorData"); + case JSType::INTERNAL_ACCESSOR: + return GetString("InternalAccessor"); + case JSType::FUNCTION_EXTRA_INFO: + return GetString("FunctionExtraInfo"); + case JSType::MICRO_JOB_QUEUE: + return GetString("MicroJobQueue"); + case JSType::PENDING_JOB: + return GetString("PendingJob"); + case JSType::COMPLETION_RECORD: + return GetString("CompletionRecord"); + case JSType::ECMA_MODULE: + return GetString("EcmaModule"); + default: + break; + } + if (IsInVmMode()) { + switch (type) { + case JSType::PROPERTY_BOX: + return GetString("PropertyBox"); + case JSType::GLOBAL_ENV: + return GetString("GlobalEnv"); + case JSType::PROTOTYPE_HANDLER: + return GetString("ProtoTypeHandler"); + case JSType::TRANSITION_HANDLER: + return GetString("TransitionHandler"); + case JSType::PROTO_CHANGE_MARKER: + return GetString("ProtoChangeMarker"); + case JSType::PROTOTYPE_INFO: + return GetString("ProtoChangeDetails"); + case JSType::TEMPLATE_MAP: + return GetString("TemplateMap"); + case JSType::PROGRAM: + return GetString("Program"); + case JSType::LEXICAL_FUNCTION: + return GetString("LexicalFunction"); + case JSType::MACHINE_CODE_OBJECT: + return GetString("MachineCode"); + default: + break; } - return name; // Cached in String-Table + } else { + return GetString("Hidden Object"); } - return name; + return GetString("UnKnownType"); } NodeType HeapSnapShot::GenerateNodeType(TaggedObject *entry) @@ -367,7 +380,7 @@ NodeType HeapSnapShot::GenerateNodeType(TaggedObject *entry) if (hCls->IsTaggedArray()) { nodeType = NodeType::JS_ARRAY; } else if (hCls->IsHClass()) { - nodeType = NodeType::PROPERTY_BOX; + nodeType = NodeType::HCLASS; } else { nodeType = NodeType(hCls->GetObjectType()); } @@ -489,7 +502,7 @@ void HeapSnapShot::FillEdges(JSThread *thread) ASSERT(*iter != nullptr); auto *objFrom = reinterpret_cast((*iter)->GetAddress()); std::vector> nameResources; - JSTaggedValue(objFrom).DumpForSnapshot(thread, nameResources); + JSTaggedValue(objFrom).DumpForSnapshot(thread, nameResources, isVmMode_); JSTaggedValue objValue(objFrom); for (auto const &it : nameResources) { JSTaggedValue toValue = it.second; diff --git a/ecmascript/hprof/heap_snapshot.h b/ecmascript/hprof/heap_snapshot.h index f2ad5fb7d12a33f1d9c760815a88f24de9131645..43afb09673d18c573bda64544db1382ea09caa35 100644 --- a/ecmascript/hprof/heap_snapshot.h +++ b/ecmascript/hprof/heap_snapshot.h @@ -236,8 +236,8 @@ public: static constexpr int SEQ_STEP = 2; NO_MOVE_SEMANTIC(HeapSnapShot); NO_COPY_SEMANTIC(HeapSnapShot); - explicit HeapSnapShot(JSThread *thread, const Heap *heap) - : stringTable_(heap), thread_(thread), heap_(heap) + explicit HeapSnapShot(JSThread *thread, const Heap *heap, const bool isVmMode) + : stringTable_(heap), thread_(thread), heap_(heap), isVmMode_(isVmMode) { } ~HeapSnapShot(); @@ -293,6 +293,11 @@ public: CString *GetString(const CString &as); + bool IsInVmMode() const + { + return isVmMode_; + } + private: void FillNodes(JSThread *thread); Node *GenerateNode(JSThread *thread, JSTaggedValue entry, int sequenceId = -1); @@ -320,6 +325,7 @@ private: panda::ecmascript::HeapRootVisitor rootVisitor_; JSThread *thread_; const Heap *heap_; + bool isVmMode_{true}; }; class EntryVisitor { diff --git a/ecmascript/hprof/tests/BUILD.gn b/ecmascript/hprof/tests/BUILD.gn index 04ca90811bf465a53ed67c1c46b8d49b3658653b..269c55107c1cd830a0873530dfaa52e8a94d84ae 100644 --- a/ecmascript/hprof/tests/BUILD.gn +++ b/ecmascript/hprof/tests/BUILD.gn @@ -73,16 +73,10 @@ host_unittest_action("HprofTest") { group("unittest") { testonly = true - deps = [ - ":HeapTrackerTest", - ":HprofTest", - ] + deps = [ ":HeapTrackerTest" ] } group("host_unittest") { testonly = true - deps = [ - ":HeapTrackerTestAction", - ":HprofTestAction", - ] + deps = [ ":HeapTrackerTestAction" ] } diff --git a/ecmascript/hprof/tests/hprof_test.cpp b/ecmascript/hprof/tests/hprof_test.cpp index a8edc9b592ddda2de6e6be447a6fa1df68f5a051..97ef0d87387d83f23aa70f7470f43c0ad0345e8d 100644 --- a/ecmascript/hprof/tests/hprof_test.cpp +++ b/ecmascript/hprof/tests/hprof_test.cpp @@ -16,20 +16,76 @@ #include #include +#include "ecmascript/accessor_data.h" +#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" +#include "ecmascript/global_dictionary-inl.h" #include "ecmascript/global_env.h" #include "ecmascript/hprof/heap_profiler.h" #include "ecmascript/hprof/heap_profiler_interface.h" #include "ecmascript/hprof/heap_snapshot.h" #include "ecmascript/hprof/heap_snapshot_json_serializer.h" #include "ecmascript/hprof/string_hashmap.h" +#include "ecmascript/ic/ic_handler.h" +#include "ecmascript/ic/proto_change_details.h" +#include "ecmascript/ic/property_box.h" +#include "ecmascript/jobs/micro_job_queue.h" +#include "ecmascript/jobs/pending_job.h" +#include "ecmascript/js_arguments.h" +#include "ecmascript/js_array.h" +#include "ecmascript/js_array_iterator.h" +#include "ecmascript/js_arraybuffer.h" +#include "ecmascript/js_async_function.h" +#include "ecmascript/js_collator.h" +#include "ecmascript/js_dataview.h" +#include "ecmascript/js_date.h" +#include "ecmascript/js_date_time_format.h" +#include "ecmascript/js_for_in_iterator.h" +#include "ecmascript/js_function.h" +#include "ecmascript/js_function_extra_info.h" +#include "ecmascript/js_generator_object.h" +#include "ecmascript/js_global_object.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_intl.h" +#include "ecmascript/js_locale.h" +#include "ecmascript/js_map.h" +#include "ecmascript/js_map_iterator.h" +#include "ecmascript/js_number_format.h" +#include "ecmascript/js_object-inl.h" +#include "ecmascript/js_plural_rules.h" +#include "ecmascript/js_primitive_ref.h" +#include "ecmascript/js_promise.h" +#include "ecmascript/js_realm.h" +#include "ecmascript/js_regexp.h" +#include "ecmascript/js_relative_time_format.h" +#include "ecmascript/js_set.h" +#include "ecmascript/js_set_iterator.h" +#include "ecmascript/js_string_iterator.h" +#include "ecmascript/js_tagged_number.h" +#include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" +#include "ecmascript/js_typed_array.h" +#include "ecmascript/js_weak_container.h" +#include "ecmascript/layout_info-inl.h" +#include "ecmascript/lexical_env.h" +#include "ecmascript/linked_hash_table-inl.h" +#include "ecmascript/mem/assert_scope-inl.h" +#include "ecmascript/mem/c_containers.h" +#include "ecmascript/mem/machine_code.h" #include "ecmascript/object_factory.h" +#include "ecmascript/tagged_array.h" +#include "ecmascript/tagged_dictionary.h" +#include "ecmascript/template_map.h" #include "ecmascript/tests/test_helper.h" +#include "ecmascript/transitions_dictionary.h" using namespace panda::ecmascript; +using namespace panda::ecmascript::base; namespace panda::test { +using MicroJobQueue = panda::ecmascript::job::MicroJobQueue; +using PendingJob = panda::ecmascript::job::PendingJob; class HProfTest : public testing::Test { public: static void SetUpTestCase() diff --git a/ecmascript/ic/function_cache.h b/ecmascript/ic/function_cache.h index edf42f06f5390e2410cc2fc8127ca53a0949d3dd..b2ddcd5c75d70ffd36486aa8ea2ca6f76ef52738 100644 --- a/ecmascript/ic/function_cache.h +++ b/ecmascript/ic/function_cache.h @@ -36,7 +36,7 @@ public: static inline FunctionCache *GetCurrent(JSThread *thread) { - JSTaggedValue funcValue = EcmaFrameHandler(thread).GetFunction(); + JSTaggedValue funcValue = InterpretedFrameHandler(thread).GetFunction(); JSFunction *func = JSFunction::Cast(funcValue.GetTaggedObject()); return FunctionCache::Cast(func->GetFunctionCache().GetTaggedObject()); } diff --git a/ecmascript/ic/ic_handler.h b/ecmascript/ic/ic_handler.h index e87af94ab09b8e3c26293a790222d270e38b6dcc..51b6c6f7e2ad3b5339234539c64b5fd83b371aef 100644 --- a/ecmascript/ic/ic_handler.h +++ b/ecmascript/ic/ic_handler.h @@ -122,6 +122,7 @@ public: ACCESSORS(TransitionHClass, TRANSITION_HCLASS_OFFSET, SIZE) DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) + DECL_DUMP() }; class PrototypeHandler : public TaggedObject { @@ -146,6 +147,7 @@ public: ACCESSORS(Holder, HOLDER_OFFSET, SIZE) DECL_VISIT_OBJECT(HANDLER_INFO_OFFSET, SIZE) + DECL_DUMP() }; } // namespace panda::ecmascript #endif // ECMASCRIPT_IC_IC_HANDLER_H diff --git a/ecmascript/ic/ic_runtime.cpp b/ecmascript/ic/ic_runtime.cpp index 33b3161800a065239ebc5a93cf6be88b0e95eadd..bac8baee384fb3861e48835081045e8fc125c1b4 100644 --- a/ecmascript/ic/ic_runtime.cpp +++ b/ecmascript/ic/ic_runtime.cpp @@ -136,15 +136,18 @@ JSTaggedValue LoadICRuntime::LoadMiss(JSHandle receiver, JSHandle if (receiver->IsTypedArray() || !receiver->IsJSObject()) { return JSTaggedValue::GetProperty(thread_, receiver, key).GetValue().GetTaggedValue(); } - // 1. find from global record + + // global variable find from global record firstly if (GetICKind() == ICKind::NamedGlobalLoadIC) { bool found = false; - JSTaggedValue res = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue(), &found); + JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue(), &found); if (found) { - return res; + ASSERT(box.IsPropertyBox()); + icAccessor_.AddGlobalRecordHandler(JSHandle(thread_, box)); + return PropertyBox::Cast(box.GetTaggedObject())->GetValue(); } } - // 2. find from global object + ObjectOperator op(GetThread(), receiver, key); auto result = JSHandle(thread_, JSObject::GetProperty(GetThread(), &op)); if (!op.IsFound() && GetICKind() == ICKind::NamedGlobalLoadIC) { @@ -176,18 +179,21 @@ JSTaggedValue StoreICRuntime::StoreMiss(JSHandle receiver, JSHand bool success = JSTaggedValue::SetProperty(GetThread(), receiver, key, value, true); return success ? JSTaggedValue::Undefined() : JSTaggedValue::Exception(); } - // 1. find from global record + + // global variable find from global record firstly if (GetICKind() == ICKind::NamedGlobalStoreIC) { bool found = false; - SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue(), &found); + JSTaggedValue box = SlowRuntimeStub::LdGlobalRecord(thread_, key.GetTaggedValue(), &found); if (found) { + ASSERT(box.IsPropertyBox()); SlowRuntimeStub::TryUpdateGlobalRecord(thread_, key.GetTaggedValue(), value.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); + icAccessor_.AddGlobalRecordHandler(JSHandle(thread_, box)); return JSTaggedValue::Undefined(); } } UpdateReceiverHClass(JSHandle(GetThread(), JSHandle::Cast(receiver)->GetClass())); - // 2. find from global object + ObjectOperator op(GetThread(), receiver, key); bool success = JSObject::SetProperty(&op, value, true); if (!success && GetICKind() == ICKind::NamedGlobalStoreIC) { diff --git a/ecmascript/ic/profile_type_info.cpp b/ecmascript/ic/profile_type_info.cpp index 9091b8970006055eba9d2cdd802a1f195b951006..6725d364e8cb114a0a936f45e062eae762f6ba3d 100644 --- a/ecmascript/ic/profile_type_info.cpp +++ b/ecmascript/ic/profile_type_info.cpp @@ -181,6 +181,12 @@ void ProfileTypeAccessor::AddGlobalHandlerKey(JSHandle key, JSHan profileTypeInfo_->Set(thread_, index, newArr.GetTaggedValue()); } +void ProfileTypeAccessor::AddGlobalRecordHandler(JSHandle handler) const +{ + uint32_t index = slotId_; + profileTypeInfo_->Set(thread_, index, handler.GetTaggedValue()); +} + void ProfileTypeAccessor::SetAsMega() const { profileTypeInfo_->Set(thread_, slotId_, JSTaggedValue::Hole()); diff --git a/ecmascript/ic/profile_type_info.h b/ecmascript/ic/profile_type_info.h index 3546a856b9ae971f8d7cbcc328c9535b0d3c6333..f7fecfef553c2c7a753878b108528ee9f686be62 100644 --- a/ecmascript/ic/profile_type_info.h +++ b/ecmascript/ic/profile_type_info.h @@ -116,6 +116,7 @@ public: void AddHandlerWithKey(JSHandle key, JSHandle dynclass, JSHandle handler) const; void AddGlobalHandlerKey(JSHandle key, JSHandle handler) const; + void AddGlobalRecordHandler(JSHandle handler) const; JSTaggedValue GetWeakRef(JSTaggedValue value) const { diff --git a/ecmascript/ic/property_box.h b/ecmascript/ic/property_box.h index 180834c1d8466a636eed5136f3555558bcdb44f7..23d45211156f3a2625ac3a4cdff645b2fb44cc86 100644 --- a/ecmascript/ic/property_box.h +++ b/ecmascript/ic/property_box.h @@ -42,6 +42,7 @@ public: ACCESSORS(Value, VALUE_OFFSET, SIZE); DECL_VISIT_OBJECT(VALUE_OFFSET, SIZE) + DECL_DUMP() }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/ic/proto_change_details.h b/ecmascript/ic/proto_change_details.h index c212fd2ad530810ca4a8a0638e516c2afe2a08aa..8ddeb5fc36a97de02ff2cfce527ccb43c2c15b5b 100644 --- a/ecmascript/ic/proto_change_details.h +++ b/ecmascript/ic/proto_change_details.h @@ -35,6 +35,7 @@ public: static constexpr size_t HAS_CHANGED_OFFSET = TaggedObjectSize(); SET_GET_PRIMITIVE_FIELD(HasChanged, bool, HAS_CHANGED_OFFSET, SIZE); + DECL_DUMP() }; class ProtoChangeDetails : public TaggedObject { @@ -51,6 +52,7 @@ public: ACCESSORS(RegisterIndex, REGISTER_INDEX_OFFSET, SIZE); DECL_VISIT_OBJECT(CHANGE_LISTENER_OFFSET, SIZE) + DECL_DUMP() }; class ChangeListener : public WeakVector { diff --git a/ecmascript/interpreter/fast_runtime_stub-inl.h b/ecmascript/interpreter/fast_runtime_stub-inl.h index f5ec11414d2ce4cdb8eae9570a076457ca17930c..239d2f703e398901418b36ae4ba91c3cce2aa6f6 100644 --- a/ecmascript/interpreter/fast_runtime_stub-inl.h +++ b/ecmascript/interpreter/fast_runtime_stub-inl.h @@ -269,8 +269,8 @@ JSTaggedValue FastRuntimeStub::AddPropertyByName(JSThread *thread, JSTaggedValue // change to dictionary and add one. JSHandle dict(JSObject::TransitionToDictionary(thread, objHandle)); attr.SetDictionaryOrder(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES); - auto result = JSTaggedValue(NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr)); - objHandle->SetProperties(thread, result); + NameDictionary *newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr); + objHandle->SetProperties(thread, JSTaggedValue(newDict)); // index is not essential when fastMode is false; return JSTaggedValue::Undefined(); } @@ -286,8 +286,8 @@ JSTaggedValue FastRuntimeStub::AddPropertyByName(JSThread *thread, JSTaggedValue array->Set(thread, outProps, valueHandle.GetTaggedValue()); } else { JSHandle dictHandle(array); - auto result = JSTaggedValue(NameDictionary::PutIfAbsent(thread, dictHandle, keyHandle, valueHandle, attr)); - objHandle->SetProperties(thread, result); + NameDictionary *newDict = NameDictionary::PutIfAbsent(thread, dictHandle, keyHandle, valueHandle, attr); + objHandle->SetProperties(thread, JSTaggedValue(newDict)); } return JSTaggedValue::Undefined(); } @@ -622,7 +622,14 @@ bool FastRuntimeStub::FastSetPropertyByIndex(JSThread *thread, JSTaggedValue rec JSTaggedValue value) { INTERPRETER_TRACE(thread, FastSetPropertyByIndex); +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(SetPropertyByIndex)); + typedef JSTaggedValue (*PFSetPropertyByIndex)(JSThread *, JSTaggedValue, uint32_t, JSTaggedValue); + auto setPropertyByIndex = reinterpret_cast(stubAddr); + JSTaggedValue result = setPropertyByIndex(thread, receiver, index, value); +#else JSTaggedValue result = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value); +#endif if (!result.IsHole()) { return result != JSTaggedValue::Exception(); } @@ -654,7 +661,14 @@ JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedV // Maybe moved by GC receiver = receiverHandler.GetTaggedValue(); } +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByName)); + typedef JSTaggedValue (*PFGetPropertyByName)(JSThread *, JSTaggedValue, JSTaggedValue); + auto getPropertyByNamePtr = reinterpret_cast(stubAddr); + JSTaggedValue result = getPropertyByNamePtr(thread, receiver, key); +#else JSTaggedValue result = FastRuntimeStub::GetPropertyByName(thread, receiver, key); +#endif if (result.IsHole()) { return JSTaggedValue::GetProperty(thread, JSHandle(thread, receiver), JSHandle(thread, key)) @@ -667,7 +681,14 @@ JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedV JSTaggedValue FastRuntimeStub::FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key) { INTERPRETER_TRACE(thread, FastGetPropertyByValue); +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByValue)); + typedef JSTaggedValue (*PFGetPropertyByValue)(JSThread *, JSTaggedValue, JSTaggedValue); + auto getPropertyByValuePtr = reinterpret_cast(stubAddr); + JSTaggedValue result = getPropertyByValuePtr(thread, receiver, key); +#else JSTaggedValue result = FastRuntimeStub::GetPropertyByValue(thread, receiver, key); +#endif if (result.IsHole()) { return JSTaggedValue::GetProperty(thread, JSHandle(thread, receiver), JSHandle(thread, key)) @@ -681,7 +702,14 @@ template // UseHole is only for Array::Sort() which requires Hole JSTaggedValue FastRuntimeStub::FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index) { INTERPRETER_TRACE(thread, FastGetPropertyByIndex); - JSTaggedValue result = GetPropertyByIndex(thread, receiver, index); +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByIndex)); + typedef JSTaggedValue (*PFGetPropertyByIndex)(JSThread *, JSTaggedValue, uint32_t); + auto getPropertyByIndex = reinterpret_cast(stubAddr); + JSTaggedValue result = getPropertyByIndex(thread, receiver, index); +#else + JSTaggedValue result = FastRuntimeStub::GetPropertyByIndex(thread, receiver, index); +#endif if (result.IsHole() && !UseHole) { return JSTaggedValue::GetProperty(thread, JSHandle(thread, receiver), index) .GetValue() @@ -880,9 +908,9 @@ bool FastRuntimeStub::SetPropertyByName(JSThread *thread, JSTaggedValue receiver if (receiver.IsJSGlobalObject()) { [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle dict_handle(thread, properties); + JSHandle dictHandle(thread, properties); // globalobj have no internal accessor - GlobalDictionary::InvalidatePropertyBox(thread, dict_handle, indexOrEntry, attr); + GlobalDictionary::InvalidatePropertyBox(thread, dictHandle, indexOrEntry, attr); return true; } @@ -961,7 +989,7 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei JSHandle keyHandle(thread, key); JSHandle valHandle(thread, value); JSHandle objHandle(thread, obj); - JSHandle dict_handle(thread, GlobalDictionary::Create(thread)); + JSHandle dictHandle(thread, GlobalDictionary::Create(thread)); // Add PropertyBox to global dictionary ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); @@ -970,9 +998,9 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei PropertyBoxType boxType = valHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT; attr.SetBoxType(boxType); - objHandle->SetProperties( - thread, JSTaggedValue(GlobalDictionary::PutIfAbsent(thread, dict_handle, keyHandle, - JSHandle(boxHandle), attr))); + GlobalDictionary *properties = + GlobalDictionary::PutIfAbsent(thread, dictHandle, keyHandle, JSHandle(boxHandle), attr); + objHandle->SetProperties(thread, JSTaggedValue(properties)); return true; } @@ -983,8 +1011,8 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei if (!attr.IsAccessor()) { if (attr.IsWritable()) { // globalobj have no internal accessor - JSHandle dict_handle(thread, dict); - GlobalDictionary::InvalidatePropertyBox(thread, dict_handle, entry, attr); + JSHandle dictHandle(thread, dict); + GlobalDictionary::InvalidatePropertyBox(thread, dictHandle, entry, attr); return true; } } @@ -1011,7 +1039,7 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei JSHandle keyHandle(thread, key); JSHandle valHandle(thread, value); JSHandle objHandle(thread, obj); - JSHandle dict_handle(thread, dict); + JSHandle dictHandle(thread, dict); // Add PropertyBox to global dictionary ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); @@ -1020,9 +1048,9 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei PropertyBoxType boxType = valHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT; attr.SetBoxType(boxType); - objHandle->SetProperties(thread, JSTaggedValue(GlobalDictionary::PutIfAbsent( - thread, dict_handle, keyHandle, - JSHandle(boxHandle), attr))); + GlobalDictionary *properties = + GlobalDictionary::PutIfAbsent(thread, dictHandle, keyHandle, JSHandle(boxHandle), attr); + objHandle->SetProperties(thread, JSTaggedValue(properties)); return true; } diff --git a/ecmascript/interpreter/fast_runtime_stub.h b/ecmascript/interpreter/fast_runtime_stub.h index 271ac0f0f9faeee58ad752d7f5c8bc7ce8feabfd..2437bae80d55ab53d3a7365ecbb47b1a04f71c6f 100644 --- a/ecmascript/interpreter/fast_runtime_stub.h +++ b/ecmascript/interpreter/fast_runtime_stub.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_H #define ECMASCRIPT_INTERPRETER_FAST_RUNTIME_STUB_H +#include #include "ecmascript/js_tagged_value.h" namespace panda::ecmascript { diff --git a/ecmascript/interpreter/frame_handler.cpp b/ecmascript/interpreter/frame_handler.cpp index c0ac197d1e29e574d78674ed48419f282cce8fc5..d276f130f016d001cfb2d0541233d425218ed33c 100644 --- a/ecmascript/interpreter/frame_handler.cpp +++ b/ecmascript/interpreter/frame_handler.cpp @@ -14,62 +14,81 @@ */ #include "ecmascript/interpreter/frame_handler.h" - -#include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_thread.h" #include "libpandafile/bytecode_instruction-inl.h" +#include "ecmascript/compiler/llvm/llvm_stackmap_parser.h" namespace panda::ecmascript { -EcmaFrameHandler::EcmaFrameHandler(const JSThread *thread) +void FrameHandler::PrevFrame() { - sp_ = const_cast(thread->GetCurrentSPFrame()); + ASSERT(HasFrame()); + auto type = GetFrameType(); + switch (type) { + case FrameType::OPTIMIZED_FRAME: { + auto framehandle = + reinterpret_cast(this); + framehandle->PrevFrame(); + break; + } + case FrameType::OPTIMIZED_ENTRY_FRAME: { + auto framehandle = + reinterpret_cast(this); + framehandle->PrevFrame(); + break; + } + case FrameType::INTERPRETER_FRAME: { + auto framehandle = + reinterpret_cast(this); + framehandle->PrevFrame(); + break; + } + default: + UNREACHABLE(); + } } -bool EcmaFrameHandler::HasFrame() const +InterpretedFrameHandler::InterpretedFrameHandler(JSThread *thread) + : FrameHandler(const_cast(thread->GetCurrentSPFrame())) { - // Breakframe also is a frame - return sp_ != nullptr; } -bool EcmaFrameHandler::IsBreakFrame() const +void InterpretedFrameHandler::PrevFrame() { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; - return state->sp == nullptr; + sp_ = state->base.prev; } -void EcmaFrameHandler::PrevFrame() +void InterpretedFrameHandler::PrevInterpretedFrame() { - ASSERT(HasFrame()); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - FrameState *state = reinterpret_cast(sp_) - 1; - sp_ = state->prev; + FrameHandler::PrevFrame(); + for (;HasFrame() && GetFrameType() != FrameType::INTERPRETER_FRAME; FrameHandler::PrevFrame()); } -EcmaFrameHandler EcmaFrameHandler::GetPrevFrame() const +InterpretedFrameHandler InterpretedFrameHandler::GetPrevFrame() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; - return EcmaFrameHandler(state->prev); + return InterpretedFrameHandler(state->base.prev); } -JSTaggedValue EcmaFrameHandler::GetVRegValue(size_t index) const +JSTaggedValue InterpretedFrameHandler::GetVRegValue(size_t index) const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) return JSTaggedValue(sp_[index]); } -void EcmaFrameHandler::SetVRegValue(size_t index, JSTaggedValue value) +void InterpretedFrameHandler::SetVRegValue(size_t index, JSTaggedValue value) { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) sp_[index] = value.GetRawData(); } -JSTaggedValue EcmaFrameHandler::GetAcc() const +JSTaggedValue InterpretedFrameHandler::GetAcc() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -77,18 +96,18 @@ JSTaggedValue EcmaFrameHandler::GetAcc() const return state->acc; } -uint32_t EcmaFrameHandler::GetSize() const +uint32_t InterpretedFrameHandler::GetSize() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(sp_) - 1; - JSTaggedType *prevSp = state->prev; + JSTaggedType *prevSp = state->base.prev; ASSERT(prevSp != nullptr); auto size = (prevSp - sp_) - FRAME_STATE_SIZE; return static_cast(size); } -uint32_t EcmaFrameHandler::GetBytecodeOffset() const +uint32_t InterpretedFrameHandler::GetBytecodeOffset() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -98,7 +117,7 @@ uint32_t EcmaFrameHandler::GetBytecodeOffset() const return static_cast(offset); } -JSMethod *EcmaFrameHandler::GetMethod() const +JSMethod *InterpretedFrameHandler::GetMethod() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -106,7 +125,7 @@ JSMethod *EcmaFrameHandler::GetMethod() const return state->method; } -JSTaggedValue EcmaFrameHandler::GetFunction() const +JSTaggedValue InterpretedFrameHandler::GetFunction() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -117,7 +136,7 @@ JSTaggedValue EcmaFrameHandler::GetFunction() const return func; } -const uint8_t *EcmaFrameHandler::GetPc() const +const uint8_t *InterpretedFrameHandler::GetPc() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -125,7 +144,7 @@ const uint8_t *EcmaFrameHandler::GetPc() const return state->pc; } -JSTaggedType *EcmaFrameHandler::GetSp() const +JSTaggedType *InterpretedFrameHandler::GetSp() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -133,7 +152,7 @@ JSTaggedType *EcmaFrameHandler::GetSp() const return state->sp; } -ConstantPool *EcmaFrameHandler::GetConstpool() const +ConstantPool *InterpretedFrameHandler::GetConstpool() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -141,7 +160,7 @@ ConstantPool *EcmaFrameHandler::GetConstpool() const return state->constpool; } -JSTaggedValue EcmaFrameHandler::GetEnv() const +JSTaggedValue InterpretedFrameHandler::GetEnv() const { ASSERT(HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) @@ -149,17 +168,17 @@ JSTaggedValue EcmaFrameHandler::GetEnv() const return state->env; } -void EcmaFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) +void InterpretedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) { JSTaggedType *current = sp_; - while (current != nullptr) { + if (current != nullptr) { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(current) - 1; if (state->sp != nullptr) { uintptr_t start = ToUintPtr(current); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - FrameState *prev_state = reinterpret_cast(state->prev) - 1; + FrameState *prev_state = reinterpret_cast(state->base.prev) - 1; uintptr_t end = ToUintPtr(prev_state); v1(Root::ROOT_FRAME, ObjectSlot(start), ObjectSlot(end)); if (state->pc != nullptr) { @@ -170,14 +189,13 @@ void EcmaFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1 v0(Root::ROOT_FRAME, ObjectSlot(ToUintPtr(&state->profileTypeInfo))); } } - current = state->prev; } } -void EcmaFrameHandler::DumpStack(std::ostream &os) const +void InterpretedFrameHandler::DumpStack(std::ostream &os) const { size_t i = 0; - EcmaFrameHandler frameHandler(sp_); + InterpretedFrameHandler frameHandler(sp_); for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { os << "[" << i++ << "]:" << frameHandler.GetMethod()->ParseFunctionName() @@ -185,13 +203,109 @@ void EcmaFrameHandler::DumpStack(std::ostream &os) const } } -void EcmaFrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const +void InterpretedFrameHandler::DumpPC(std::ostream &os, const uint8_t *pc) const { - EcmaFrameHandler frameHandler(sp_); + InterpretedFrameHandler frameHandler(sp_); ASSERT(frameHandler.HasFrame()); // NOLINTNEXTLINE(cppcoreguidelines-narrowing-conversions, bugprone-narrowing-conversions) int offset = pc - JSMethod::Cast(frameHandler.GetMethod())->GetBytecodeArray(); os << "offset: " << offset << "\n"; } + +void OptimizedFrameHandler::PrevFrame() +{ + OptimizedFrameStateBase *state = reinterpret_cast( + reinterpret_cast(sp_) - OptimizedFrameStateBase::GetFrameStateOffsetFromSp()); + sp_ = reinterpret_cast(state->prev); +} + +void OptimizedFrameHandler::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const +{ + uintptr_t *current = fp_; + if (current != nullptr) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + std::set slotAddrs; + auto returnAddr = reinterpret_cast(*(current + 1)); + LOG_ECMA(INFO) << __FUNCTION__ << " returnAddr :" << returnAddr << std::endl; + bool ret = kungfu::LLVMStackMapParser::GetInstance().StackMapByFuncAddrFp( + returnAddr, + reinterpret_cast(fp_), + slotAddrs); + if (ret == false) { + return; + } + for (auto &address: slotAddrs) { + v0(Root::ROOT_FRAME, ObjectSlot(address)); + } + } +} + +void OptimizedEntryFrameHandler::PrevFrame() +{ + OptimizedEntryFrameState *state = reinterpret_cast( + reinterpret_cast(sp_) - OptimizedEntryFrameState::GetFrameStateOffsetFromSp()); + sp_ = reinterpret_cast(state->threadFp); +} + +void FrameIterator::HandleRuntimeTrampolines(const RootVisitor &v0, const RootRangeVisitor &v1) const +{ + if (thread_) { + uintptr_t *fp = thread_->GetLastOptCallRuntimePc(); + if (fp == nullptr) { + return; + } + std::set slotAddrs; + auto returnAddr = *(fp + 1); +#ifndef NDEBUG + LOG_ECMA(INFO) << __FUNCTION__ << " returnAddr :" << returnAddr << " fp: " << fp << std::endl; +#endif + bool ret = kungfu::LLVMStackMapParser::GetInstance().StackMapByFuncAddrFp( + reinterpret_cast(returnAddr), + reinterpret_cast(fp), + slotAddrs); + if (ret == false) { +#ifndef NDEBUG + LOG_ECMA(INFO) << " stackmap don't found returnAddr " << std::endl; +#endif + return; + } + for (auto &address: slotAddrs) { +#ifndef NDEBUG + LOG_ECMA(INFO) << "stackmap address : " << std::hex << address << std::endl; +#endif + v0(Root::ROOT_FRAME, ObjectSlot(address)); + } + } +} + + +void FrameIterator::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const +{ + JSTaggedType *current = fp_; + // handle runtimeTrampolines Frame in order get stub returnAddress which used by + // stackMap + HandleRuntimeTrampolines(v0, v1); + while (current) { + FrameType type = FrameHandler(current).GetFrameType(); + LOG_ECMA(INFO) << __FUNCTION__ << "type = " << static_cast(type) << std::endl; + if (type == FrameType::INTERPRETER_FRAME) { + FrameState *state = reinterpret_cast(current) - 1; + InterpretedFrameHandler(current).Iterate(v0, v1); + current = state->base.prev; + } else if (type == FrameType::OPTIMIZED_FRAME) { + OptimizedFrameStateBase *state = reinterpret_cast( + reinterpret_cast(current) - + MEMBER_OFFSET(OptimizedFrameStateBase, prev)); + OptimizedFrameHandler(reinterpret_cast(current)).Iterate(v0, v1); + current = reinterpret_cast(state->prev); + } else { + ASSERT(type == FrameType::OPTIMIZED_ENTRY_FRAME); + OptimizedEntryFrameState *state = reinterpret_cast( + reinterpret_cast(current) - + MEMBER_OFFSET(OptimizedEntryFrameState, base.prev)); + current = reinterpret_cast(state->threadFp); + } + } +} } // namespace panda::ecmascript diff --git a/ecmascript/interpreter/frame_handler.h b/ecmascript/interpreter/frame_handler.h index ad82f3723649049c2155188d8baf6354f9aeff11..870f48add9b0199f55d3a83cf64032a5540dd4f1 100644 --- a/ecmascript/interpreter/frame_handler.h +++ b/ecmascript/interpreter/frame_handler.h @@ -16,9 +16,11 @@ #ifndef ECMASCRIPT_INTERPRETER_FRAME_HANDLER_H #define ECMASCRIPT_INTERPRETER_FRAME_HANDLER_H +#include "ecmascript/interpreter/interpreter.h" #include "ecmascript/js_method.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/mem/heap_roots.h" +#include "ecmascript/frames.h" namespace panda { namespace ecmascript { @@ -26,18 +28,50 @@ class JSThread; class JSFunction; class ConstantPool; -class EcmaFrameHandler { +class FrameHandler { public: - explicit EcmaFrameHandler(JSTaggedType *sp) : sp_(sp) {} - explicit EcmaFrameHandler(const JSThread *thread); - ~EcmaFrameHandler() = default; - DEFAULT_COPY_SEMANTIC(EcmaFrameHandler); - DEFAULT_MOVE_SEMANTIC(EcmaFrameHandler); + explicit FrameHandler(JSTaggedType *sp) : sp_(sp) {} + ~FrameHandler() = default; + DEFAULT_COPY_SEMANTIC(FrameHandler); + DEFAULT_MOVE_SEMANTIC(FrameHandler); + bool HasFrame() const + { + // Breakframe also is a frame + return sp_ != nullptr; + } + bool IsBreakFrame() const + { + ASSERT(HasFrame()); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + FrameState *state = reinterpret_cast(sp_) - 1; + return state->sp == nullptr; + } + void PrevFrame(); + + FrameType GetFrameType() const + { + ASSERT(HasFrame()); + FrameType type = *(reinterpret_cast( + reinterpret_cast(sp_) + FrameConst::FRAME_TYPE_OFFSET)); + return type; + } +private: + friend class InterpretedFrameHandler; + friend class OptimizedFrameHandler; + friend class OptimizedEntryFrameHandler; + JSTaggedType *sp_ {nullptr}; +}; + +class InterpretedFrameHandler : public FrameHandler { +public: + explicit InterpretedFrameHandler(JSThread *thread); + explicit InterpretedFrameHandler(JSTaggedType *sp) : FrameHandler(sp) {} + DEFAULT_COPY_SEMANTIC(InterpretedFrameHandler); + DEFAULT_MOVE_SEMANTIC(InterpretedFrameHandler); - bool HasFrame() const; - bool IsBreakFrame() const; void PrevFrame(); - EcmaFrameHandler GetPrevFrame() const; + void PrevInterpretedFrame(); + InterpretedFrameHandler GetPrevFrame() const; JSTaggedValue GetVRegValue(size_t index) const; void SetVRegValue(size_t index, JSTaggedValue value); @@ -64,10 +98,41 @@ public: { DumpPC(std::cout, pc); } +}; + +class OptimizedFrameHandler : public FrameHandler { +public: + explicit OptimizedFrameHandler(uintptr_t *fp) + : FrameHandler(reinterpret_cast(fp)), fp_(fp) {} + explicit OptimizedFrameHandler(const JSThread *thread); + ~OptimizedFrameHandler() = default; + void PrevFrame(); + void Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const; +private: + uintptr_t *fp_ {nullptr}; +}; +class OptimizedEntryFrameHandler : public FrameHandler { +public: + explicit OptimizedEntryFrameHandler(uintptr_t *fp) + : FrameHandler(reinterpret_cast(fp)), fp_(fp) {} + explicit OptimizedEntryFrameHandler(const JSThread *thread); + ~OptimizedEntryFrameHandler() = default; + void PrevFrame(); +private: + uintptr_t *fp_ {nullptr}; +}; + +class FrameIterator { +public: + explicit FrameIterator(JSTaggedType *fp, const JSThread *thread) : fp_(fp), thread_(thread) {} + ~FrameIterator() = default; + void Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) const; + void HandleRuntimeTrampolines(const RootVisitor &v0, const RootRangeVisitor &v1) const; private: - JSTaggedType *sp_{nullptr}; + JSTaggedType *fp_ {nullptr}; + const JSThread *thread_ {nullptr}; }; -} // namespace ecmascript +} // namespace ecmascript } // namespace panda #endif // ECMASCRIPT_INTERPRETER_FRAME_HANDLER_H diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index a9232e5d886caf49d355db5461a2867628caa538..a92d165ddb44d94d03dc0f38d43b801a0863e00f 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -23,6 +23,7 @@ #include "ecmascript/ic/ic_runtime_stub-inl.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" #include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/slow_runtime_stub.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/js_tagged_value.h" @@ -203,10 +204,25 @@ namespace panda::ecmascript { #define GET_ACC() (acc) // NOLINT(cppcoreguidelines-macro-usage) #define SET_ACC(val) (acc = val); // NOLINT(cppcoreguidelines-macro-usage) +JSTaggedType *EcmaInterpreter::GetCurrentInterpretedFrameSp(JSThread *thread) +{ + JSTaggedType *originalPrevSp = const_cast(thread->GetCurrentSPFrame()); + auto current = originalPrevSp; + FrameType type = *(reinterpret_cast( + reinterpret_cast(current) + FrameConst::FRAME_TYPE_OFFSET)); + JSTaggedType *sp = originalPrevSp; + if (type != FrameType::INTERPRETER_FRAME) { + JSTaggedType *lastSp = const_cast(thread->GetLastInterpretedFrameSp()); + sp = lastSp; + } + return sp; +} + JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *thread, const CallParams& params) { INTERPRETER_TRACE(thread, ExecuteNative); - JSTaggedType *sp = const_cast(thread->GetCurrentSPFrame()); + JSTaggedType *sp = GetCurrentInterpretedFrameSp(thread); + JSMethod *methodToCall = params.callTarget->GetCallTarget(); ASSERT(methodToCall->GetNumVregs() == 0); uint32_t numActualArgs = params.argc + RESERVED_CALL_ARGCOUNT; @@ -228,7 +244,8 @@ JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *thread, const CallParams& } FrameState *state = GET_FRAME(newSp); - state->prev = sp; + state->base.prev = sp; + state->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); state->pc = nullptr; state->sp = newSp; state->method = methodToCall; @@ -249,19 +266,20 @@ JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, const CallParams& param if (method->IsNative()) { return EcmaInterpreter::ExecuteNative(thread, params); } - JSTaggedType *originalPrevSp = const_cast(thread->GetCurrentSPFrame()); + JSTaggedType *sp = GetCurrentInterpretedFrameSp(thread); + JSTaggedType *newSp = sp - FRAME_STATE_SIZE; // push break state // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - JSTaggedType *newSp = originalPrevSp - FRAME_STATE_SIZE; if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { return JSTaggedValue::Undefined(); } FrameState *breakState = GET_FRAME(newSp); breakState->pc = nullptr; breakState->sp = nullptr; - breakState->prev = originalPrevSp; + breakState->base.prev = originalPrevSp; + breakState->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); breakState->numActualArgs = 0; JSTaggedType *prevSp = newSp; @@ -300,7 +318,8 @@ JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, const CallParams& param ConstantPool *constpool = ConstantPool::Cast(thisFunc->GetConstantPool().GetTaggedObject()); state->constpool = constpool; state->profileTypeInfo = thisFunc->GetProfileTypeInfo(); - state->prev = prevSp; + state->base.prev = prevSp; + state->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); state->numActualArgs = numActualArgs; JSTaggedValue env = thisFunc->GetLexicalEnv(); @@ -338,7 +357,8 @@ JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSH FrameState *breakState = GET_FRAME(breakSp); breakState->pc = nullptr; breakState->sp = nullptr; - breakState->prev = currentSp; + breakState->base.prev = currentSp; + breakState->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); breakState->numActualArgs = 0; // create new frame and resume sp and pc @@ -368,7 +388,8 @@ JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSH state->profileTypeInfo = func->GetProfileTypeInfo(); state->acc = context->GetAcc(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - state->prev = breakSp; + state->base.prev = breakSp; + state->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); JSTaggedValue env = context->GetLexicalEnv(); state->env = env; // execute interpreter @@ -399,7 +420,8 @@ void EcmaInterpreter::ChangeGenContext(JSThread *thread, JSHandlepc = nullptr; breakState->sp = nullptr; - breakState->prev = currentSp; + breakState->base.prev = currentSp; + breakState->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); // create new frame and resume sp and pc uint32_t nregs = context->GetNRegs().GetInt(); @@ -428,7 +450,8 @@ void EcmaInterpreter::ChangeGenContext(JSThread *thread, JSHandleprofileTypeInfo = func->GetProfileTypeInfo(); state->acc = context->GetAcc(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - state->prev = breakSp; + state->base.prev = breakSp; + state->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); state->env = context->GetLexicalEnv(); thread->SetCurrentSPFrame(newSp); @@ -438,13 +461,13 @@ void EcmaInterpreter::ResumeContext(JSThread *thread) { JSTaggedType *sp = const_cast(thread->GetCurrentSPFrame()); FrameState *state = GET_FRAME(sp); - thread->SetCurrentSPFrame(state->prev); + thread->SetCurrentSPFrame(state->base.prev); } void EcmaInterpreter::NotifyBytecodePcChanged(JSThread *thread) { - EcmaFrameHandler frameHandler(thread); - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + InterpretedFrameHandler frameHandler(thread); + for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { if (frameHandler.IsBreakFrame()) { continue; } @@ -454,7 +477,7 @@ void EcmaInterpreter::NotifyBytecodePcChanged(JSThread *thread) continue; } auto bcOffset = frameHandler.GetBytecodeOffset(); - Runtime::GetCurrent()->GetNotificationManager()->BytecodePcChangedEvent(thread, method, bcOffset); + thread->GetEcmaVM()->GetNotificationManager()->BytecodePcChangedEvent(thread, method, bcOffset); return; } } @@ -771,7 +794,8 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool } FrameState *state = GET_FRAME(newSp); - state->prev = sp; + state->base.prev = sp; + state->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); state->pc = nullptr; state->sp = newSp; state->method = methodToCall; @@ -854,7 +878,8 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool InterpreterFrameCopyArgs(newSp, numVregs, actualNumArgs, numDeclaredArgs); FrameState *state = GET_FRAME(newSp); - state->prev = sp; + state->base.prev = sp; + state->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); state->pc = pc = JSMethod::Cast(methodToCall)->GetBytecodeArray(); state->sp = sp = newSp; state->method = methodToCall; @@ -874,13 +899,13 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool } } HANDLE_OPCODE(HANDLE_RETURN_DYN) { - LOG_INST() << "return.dyn"; + LOG_INST() << "returnla "; FrameState *state = GET_FRAME(sp); LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call " << std::hex << reinterpret_cast(state->sp) << " " << std::hex << reinterpret_cast(state->pc); [[maybe_unused]] auto fistPC = state->method->GetInstructions(); UPDATE_HOTNESS_COUNTER(-(pc - fistPC)); - sp = state->prev; + sp = state->base.prev; ASSERT(sp != nullptr); FrameState *prevState = GET_FRAME(sp); pc = prevState->pc; @@ -904,7 +929,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool << std::hex << reinterpret_cast(state->pc); [[maybe_unused]] auto fistPC = state->method->GetInstructions(); UPDATE_HOTNESS_COUNTER_NON_ACC(-(pc - fistPC)); - sp = state->prev; + sp = state->base.prev; ASSERT(sp != nullptr); FrameState *prevState = GET_FRAME(sp); pc = prevState->pc; @@ -1113,7 +1138,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool } HANDLE_OPCODE(HANDLE_TYPEOFDYN_PREF) { LOG_INST() << "intrinsics::typeofdyn"; +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(FastTypeOf)); + typedef JSTaggedValue (*PFFastTypeOf)(JSThread *, JSTaggedValue); + auto fastTypeOfPtr = reinterpret_cast(stubAddr); + JSTaggedValue res = fastTypeOfPtr(thread, GET_ACC()); +#else JSTaggedValue res = FastRuntimeStub::FastTypeOf(thread, GET_ACC()); +#endif SET_ACC(res); DISPATCH(BytecodeInstruction::Format::PREF_NONE); } @@ -1306,8 +1338,15 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool << " v" << vs; JSTaggedValue left = GET_VREG_VALUE(vs); JSTaggedValue right = GET_ACC(); - // fast path + +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(FastMod)); + typedef JSTaggedValue (*PFFastMod)(JSTaggedValue, JSTaggedValue); + auto fastModPtr = reinterpret_cast(stubAddr); + JSTaggedValue res = fastModPtr(left, right); +#else JSTaggedValue res = FastRuntimeStub::FastMod(left, right); +#endif if (!res.IsHole()) { SET_ACC(res); } else { @@ -1325,7 +1364,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool << " v" << v0; JSTaggedValue left = GET_VREG_VALUE(v0); JSTaggedValue right = acc; +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(FastEqual)); + typedef JSTaggedValue (*PFFastEqual)(JSTaggedValue, JSTaggedValue); + auto fastEqualPtr = reinterpret_cast(stubAddr); + JSTaggedValue res = fastEqualPtr(left, right); +#else JSTaggedValue res = FastRuntimeStub::FastEqual(left, right); +#endif if (!res.IsHole()) { SET_ACC(res); } else { @@ -1708,10 +1754,13 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); ASSERT(result != nullptr); if (result->IsResolved()) { + SAVE_ACC(); auto res = SlowRuntimeStub::DefineNCFuncDyn(thread, result); INTERPRETER_RETURN_IF_ABRUPT(res); result = JSFunction::Cast(res.GetTaggedObject()); result->SetConstantPool(thread, JSTaggedValue(constpool)); + RESTORE_ACC(); + homeObject = GET_ACC(); } else { result->SetResolved(thread); } @@ -2003,7 +2052,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool UPDATE_HOTNESS_COUNTER(-(pc - fistPC)); LOG(DEBUG, INTERPRETER) << "Exit: SuspendGenerator " << std::hex << reinterpret_cast(sp) << " " << std::hex << reinterpret_cast(state->pc); - sp = state->prev; + sp = state->base.prev; ASSERT(sp != nullptr); FrameState *prevState = GET_FRAME(sp); pc = prevState->pc; @@ -2430,7 +2479,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool JSTaggedValue receiver = GET_VREG_VALUE(v0); // fast path if (LIKELY(receiver.IsHeapObject())) { +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByIndex)); + typedef JSTaggedValue (*PFGetPropertyByIndex)(JSThread *, JSTaggedValue, uint32_t); + auto getPropertyByIndex = reinterpret_cast(stubAddr); + JSTaggedValue res = getPropertyByIndex(thread, receiver, idx); +#else JSTaggedValue res = FastRuntimeStub::GetPropertyByIndex(thread, receiver, idx); +#endif if (!res.IsHole()) { INTERPRETER_RETURN_IF_ABRUPT(res); SET_ACC(res); @@ -2455,7 +2511,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool SAVE_ACC(); JSTaggedValue value = GET_ACC(); // fast path +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(SetPropertyByIndex)); + typedef JSTaggedValue (*PFSetPropertyByIndex)(JSThread *, JSTaggedValue, uint32_t, JSTaggedValue); + auto setPropertyByIndex = reinterpret_cast(stubAddr); + JSTaggedValue res = setPropertyByIndex(thread, receiver, index, value); +#else JSTaggedValue res = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value); +#endif if (!res.IsHole()) { INTERPRETER_RETURN_IF_ABRUPT(res); RESTORE_ACC(); @@ -2492,7 +2555,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool if (LIKELY(firstValue.IsHeapObject())) { JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); res = ICRuntimeStub::TryLoadICByValue(thread, receiver, propKey, firstValue, secondValue); - } else if (firstValue.IsUndefined()) { + } + // IC miss and not enter the megamorphic state, store as polymorphic + if (res.IsHole() && !firstValue.IsHole()) { res = ICRuntimeStub::LoadICByValue(thread, profileTypeArray, receiver, propKey, slotId); @@ -2507,7 +2572,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool #endif // fast path if (LIKELY(receiver.IsHeapObject())) { +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByValue)); + typedef JSTaggedValue (*PFGetPropertyByValue)(JSThread *, JSTaggedValue, JSTaggedValue); + auto getPropertyByValuePtr = reinterpret_cast(stubAddr); + JSTaggedValue res = getPropertyByValuePtr(thread, receiver, propKey); +#else JSTaggedValue res = FastRuntimeStub::GetPropertyByValue(thread, receiver, propKey); +#endif if (!res.IsHole()) { ASSERT(!res.IsAccessor()); INTERPRETER_RETURN_IF_ABRUPT(res); @@ -2543,7 +2615,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool if (LIKELY(firstValue.IsHeapObject())) { JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); res = ICRuntimeStub::TryStoreICByValue(thread, receiver, propKey, firstValue, secondValue, value); - } else if (firstValue.IsUndefined()) { + } + // IC miss and not enter the megamorphic state, store as polymorphic + if (res.IsHole() && !firstValue.IsHole()) { res = ICRuntimeStub::StoreICByValue(thread, profileTypeArray, receiver, propKey, value, slotId); @@ -2640,7 +2714,7 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool // order: 1. global record 2. global object JSTaggedValue result = SlowRuntimeStub::LdGlobalRecord(thread, prop, &found); if (found) { - SET_ACC(result); + SET_ACC(PropertyBox::Cast(result.GetTaggedObject())->GetValue()); } else { JSTaggedValue globalResult = FastRuntimeStub::GetGlobalOwnProperty(globalObj, prop, &found); if (found) { @@ -2855,7 +2929,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool if (LIKELY(firstValue.IsHeapObject())) { JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); res = ICRuntimeStub::TryLoadICByName(thread, receiver, firstValue, secondValue); - } else if (firstValue.IsUndefined()) { + } + // IC miss and not enter the megamorphic state, store as polymorphic + if (res.IsHole() && !firstValue.IsHole()) { uint32_t stringId = READ_INST_32_1(); JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); res = ICRuntimeStub::LoadICByName(thread, @@ -2878,7 +2954,14 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool if (LIKELY(receiver.IsHeapObject())) { // fast path +#ifdef ECMASCRIPT_ENABLE_STUB_AOT + auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByName)); + typedef JSTaggedValue (*PFGetPropertyByName)(JSThread *, JSTaggedValue, JSTaggedValue); + auto getPropertyByNamePtr = reinterpret_cast(stubAddr); + JSTaggedValue res = getPropertyByNamePtr(thread, receiver, propKey); +#else JSTaggedValue res = FastRuntimeStub::GetPropertyByName(thread, receiver, propKey); +#endif if (!res.IsHole()) { ASSERT(!res.IsAccessor()); INTERPRETER_RETURN_IF_ABRUPT(res); @@ -2909,7 +2992,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool if (LIKELY(firstValue.IsHeapObject())) { JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); res = ICRuntimeStub::TryStoreICByName(thread, receiver, firstValue, secondValue, value); - } else if (firstValue.IsUndefined()) { + } + // IC miss and not enter the megamorphic state, store as polymorphic + if (res.IsHole() && !firstValue.IsHole()) { uint32_t stringId = READ_INST_32_1(); JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); res = ICRuntimeStub::StoreICByName(thread, @@ -3174,9 +3259,9 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool HANDLE_OPCODE(EXCEPTION_HANDLER) { auto exception = thread->GetException(); - EcmaFrameHandler frameHandler(sp); + InterpretedFrameHandler frameHandler(sp); uint32_t pcOffset = panda_file::INVALID_OFFSET; - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { if (frameHandler.IsBreakFrame()) { return; } @@ -3215,7 +3300,8 @@ void EcmaInterpreter::InitStackFrame(JSThread *thread) state->acc = JSTaggedValue::Hole(); state->constpool = nullptr; state->profileTypeInfo = JSTaggedValue::Undefined(); - state->prev = nullptr; + state->base.frameType = static_cast(FrameType::INTERPRETER_FRAME); + state->base.prev = nullptr; state->numActualArgs = 0; } diff --git a/ecmascript/interpreter/interpreter.h b/ecmascript/interpreter/interpreter.h index cb988f370138aae771da0c4d057671abfa2a8989..9de98319dca16a8b1ee6f517a4076e333d631647 100644 --- a/ecmascript/interpreter/interpreter.h +++ b/ecmascript/interpreter/interpreter.h @@ -20,19 +20,19 @@ #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_thread.h" +#include "ecmascript/frames.h" namespace panda::ecmascript { +using TaggedType = coretypes::TaggedType; class ConstantPool; class ECMAObject; class GeneratorContext; -using TaggedType = coretypes::TaggedType; // align with 8 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) struct FrameState { const uint8_t *pc; JSTaggedType *sp; - uint64_t *prev; JSMethod *method; // aligned with 8 bits alignas(sizeof(uint64_t)) ConstantPool *constpool; @@ -40,6 +40,7 @@ struct FrameState { JSTaggedValue acc; JSTaggedValue env; uint64_t numActualArgs; + InterpretedFrameStateBase base; }; // NOLINTNEXTLINE(bugprone-sizeof-expression) @@ -65,6 +66,7 @@ public: static inline JSTaggedValue Execute(JSThread *thread, const CallParams& params); static inline JSTaggedValue ExecuteNative(JSThread *thread, const CallParams& params); + static inline JSTaggedType *GetCurrentInterpretedFrameSp(JSThread *thread); static inline JSTaggedValue GeneratorReEnterInterpreter(JSThread *thread, JSHandle context); static inline void ChangeGenContext(JSThread *thread, JSHandle context); static inline void ResumeContext(JSThread *thread); diff --git a/ecmascript/interpreter/slow_runtime_helper.cpp b/ecmascript/interpreter/slow_runtime_helper.cpp index 4d89e3df16226072199b2fa40905a00a2d0c8212..1d9a9a8096ed273d4b488c14945e97c4ce1fa0e5 100644 --- a/ecmascript/interpreter/slow_runtime_helper.cpp +++ b/ecmascript/interpreter/slow_runtime_helper.cpp @@ -82,7 +82,7 @@ JSTaggedValue SlowRuntimeHelper::NewObject(JSThread *thread, JSHandle context) { - EcmaFrameHandler frameHandler(thread); + InterpretedFrameHandler frameHandler(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); uint32_t nregs = frameHandler.GetSize(); JSHandle regsArray = factory->NewTaggedArray(nregs); @@ -122,7 +122,7 @@ JSTaggedValue ConstructGeneric(JSThread *thread, JSHandle ctor, JSHa } // Add the input parameter - EcmaFrameHandler frameHandler(thread); + InterpretedFrameHandler frameHandler(thread); CallParams params; params.callTarget = ECMAObject::Cast(*ctor); params.newTarget = newTgt.GetTaggedType(); @@ -221,7 +221,7 @@ JSTaggedValue ConstructProxy(JSThread *thread, JSHandle ctor, JSHandle< args->Set(thread, i, value); } } - EcmaFrameHandler frameHandler(thread); + InterpretedFrameHandler frameHandler(thread); for (array_size_t i = 0; i < argsCount; ++i) { JSTaggedValue value = frameHandler.GetVRegValue(baseArgLocation + i); args->Set(thread, i + preArgsSize, value); diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp index 43f35cdbf2573f8539308c13aed35cf0d8c19f2c..c12cb3b192107b79acbc337dfe0af3ebd8aedbd5 100644 --- a/ecmascript/interpreter/slow_runtime_stub.cpp +++ b/ecmascript/interpreter/slow_runtime_stub.cpp @@ -23,6 +23,7 @@ #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/fast_runtime_stub-inl.h" +#include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/interpreter/slow_runtime_helper.h" #include "ecmascript/js_arguments.h" #include "ecmascript/js_array.h" @@ -439,7 +440,7 @@ JSTaggedValue SlowRuntimeStub::CreateObjectWithExcludedKeys(JSThread *thread, ui JSHandle obj(thread, objVal); array_size_t numExcludedKeys = 0; JSHandle excludedKeys = factory->NewTaggedArray(numKeys + 1); - EcmaFrameHandler frameHandler(thread); + InterpretedFrameHandler frameHandler(thread); JSTaggedValue excludedKey = frameHandler.GetVRegValue(firstArgRegIdx); if (!excludedKey.IsUndefined()) { numExcludedKeys = numKeys + 1; @@ -1380,16 +1381,21 @@ JSTaggedValue SlowRuntimeStub::TryUpdateGlobalRecord(JSThread *thread, JSTaggedV EcmaVM *vm = thread->GetEcmaVM(); JSHandle env = vm->GetGlobalEnv(); - NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); + GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); int entry = dict->FindEntry(prop); + ASSERT(entry != -1); + if (dict->GetAttributes(entry).IsConstProps()) { - return ThrowSyntaxError(thread, " const can not be modified"); + return ThrowSyntaxError(thread, "const variable can not be modified"); } - dict->UpdateValue(thread, entry, value); + + PropertyBox *box = dict->GetBox(entry); + box->SetValue(thread, value); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return JSTaggedValue::True(); } +// return box JSTaggedValue SlowRuntimeStub::LdGlobalRecord(JSThread *thread, JSTaggedValue key, bool *found) { INTERPRETER_TRACE(thread, LdGlobalRecord); @@ -1397,11 +1403,11 @@ JSTaggedValue SlowRuntimeStub::LdGlobalRecord(JSThread *thread, JSTaggedValue ke EcmaVM *vm = thread->GetEcmaVM(); JSHandle env = vm->GetGlobalEnv(); - NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); + GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); int entry = dict->FindEntry(key); if (entry != -1) { *found = true; - return dict->GetValue(entry); + return JSTaggedValue(dict->GetBox(entry)); } return JSTaggedValue::Undefined(); } @@ -1413,19 +1419,30 @@ JSTaggedValue SlowRuntimeStub::StGlobalRecord(JSThread *thread, JSTaggedValue pr EcmaVM *vm = thread->GetEcmaVM(); JSHandle env = vm->GetGlobalEnv(); - NameDictionary *dict = NameDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); + GlobalDictionary *dict = GlobalDictionary::Cast(env->GetGlobalRecord()->GetTaggedObject()); + // cross files global record name binding judgment int entry = dict->FindEntry(prop); if (entry != -1) { - return ThrowReferenceError(thread, prop, " is not defined"); + return ThrowSyntaxError(thread, "Duplicate identifier"); } + PropertyAttributes attributes; - attributes.SetIsConstProps(isConst); + if (isConst) { + attributes.SetIsConstProps(true); + } JSHandle propHandle(thread, prop); JSHandle valueHandle(thread, value); - JSHandle dictHandle(thread, dict); - dict->PutIfAbsent(thread, dictHandle, propHandle, valueHandle, attributes); + JSHandle dictHandle(thread, dict); + + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle box = factory->NewPropertyBox(valueHandle); + PropertyBoxType boxType = valueHandle->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT; + attributes.SetBoxType(boxType); + + dict = GlobalDictionary::PutIfAbsent(thread, dictHandle, propHandle, JSHandle(box), attributes); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + env->SetGlobalRecord(thread, JSTaggedValue(dict)); return JSTaggedValue::True(); } @@ -1716,7 +1733,7 @@ JSTaggedValue SlowRuntimeStub::SuperCall(JSThread *thread, JSTaggedValue func, J INTERPRETER_TRACE(thread, SuperCall); [[maybe_unused]] EcmaHandleScope handleScope(thread); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - EcmaFrameHandler frameHandler(thread); + InterpretedFrameHandler frameHandler(thread); JSHandle funcHandle(thread, func); JSHandle newTargetHandle(thread, newTarget); @@ -1741,7 +1758,7 @@ JSTaggedValue SlowRuntimeStub::SuperCallSpread(JSThread *thread, JSTaggedValue f { INTERPRETER_TRACE(thread, SuperCallSpread); [[maybe_unused]] EcmaHandleScope handleScope(thread); - EcmaFrameHandler frameHandler(thread); + InterpretedFrameHandler frameHandler(thread); JSHandle funcHandle(thread, func); JSHandle newTargetHandle(thread, newTarget); diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h index afa120f0ce5363cf0377931671767a785f508afd..48bb088d7ef2806ca6ef0b20fb67fc42dcbdf41a 100644 --- a/ecmascript/interpreter/slow_runtime_stub.h +++ b/ecmascript/interpreter/slow_runtime_stub.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H #define ECMASCRIPT_INTERPRETER_SLOW_RUNTIME_STUB_H +#include "ecmascript/class_linker/program_object.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/js_thread.h" diff --git a/ecmascript/jobs/micro_job_queue.cpp b/ecmascript/jobs/micro_job_queue.cpp index 52eee1b41e352368f43e41fe9a9be48470b2666e..87605df7366e19ff2ce39a4df20eba2f5681c49e 100644 --- a/ecmascript/jobs/micro_job_queue.cpp +++ b/ecmascript/jobs/micro_job_queue.cpp @@ -27,8 +27,8 @@ #include "utils/expected.h" namespace panda::ecmascript::job { -void MicroJobQueue::EnqueueJob(JSThread *thread, QueueType queueType, const JSHandle &job, - const JSHandle &argv) +void MicroJobQueue::EnqueueJob(JSThread *thread, JSHandle jobQueue, QueueType queueType, + const JSHandle &job, const JSHandle &argv) { // 1. Assert: Type(queueName) is String and its value is the name of a Job Queue recognized by this implementation. // 2. Assert: job is the name of a Job. @@ -39,24 +39,22 @@ void MicroJobQueue::EnqueueJob(JSThread *thread, QueueType queueType, const JSHa [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle pendingJob(factory->NewPendingJob(job, argv)); if (queueType == QueueType::QUEUE_PROMISE) { - JSHandle promiseQueue(thread, GetPromiseJobQueue()); + JSHandle promiseQueue(thread, jobQueue->GetPromiseJobQueue()); LOG_ECMA(DEBUG) << "promiseQueue start length: " << promiseQueue->Size(); - JSHandle newPromiseQueue( - thread, TaggedQueue::Push(thread, promiseQueue, JSHandle::Cast(pendingJob))); - SetPromiseJobQueue(thread, newPromiseQueue.GetTaggedValue()); + TaggedQueue *newPromiseQueue = TaggedQueue::Push(thread, promiseQueue, JSHandle(pendingJob)); + jobQueue->SetPromiseJobQueue(thread, JSTaggedValue(newPromiseQueue)); LOG_ECMA(DEBUG) << "promiseQueue end length: " << newPromiseQueue->Size(); } else if (queueType == QueueType::QUEUE_SCRIPT) { - JSHandle scriptQueue(thread, GetScriptJobQueue()); - JSHandle newScriptQueue( - thread, TaggedQueue::Push(thread, scriptQueue, JSHandle::Cast(pendingJob))); - SetScriptJobQueue(thread, newScriptQueue.GetTaggedValue()); + JSHandle scriptQueue(thread, jobQueue->GetScriptJobQueue()); + TaggedQueue *newScriptQueue = TaggedQueue::Push(thread, scriptQueue, JSHandle(pendingJob)); + jobQueue->SetScriptJobQueue(thread, JSTaggedValue(newScriptQueue)); } } -void MicroJobQueue::ExecutePendingJob(JSThread *thread) +void MicroJobQueue::ExecutePendingJob(JSThread *thread, JSHandle jobQueue) { [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle promiseQueue(thread, GetPromiseJobQueue()); + JSMutableHandle promiseQueue(thread, jobQueue->GetPromiseJobQueue()); JSMutableHandle pendingJob(thread, JSTaggedValue::Undefined()); while (!promiseQueue->Empty()) { LOG_ECMA(DEBUG) << "promiseQueue start length: " << promiseQueue->Size(); @@ -66,10 +64,10 @@ void MicroJobQueue::ExecutePendingJob(JSThread *thread) if (thread->HasPendingException()) { return; } - promiseQueue = JSHandle(thread, GetPromiseJobQueue()); + promiseQueue.Update(jobQueue->GetPromiseJobQueue()); } - JSHandle scriptQueue(thread, GetScriptJobQueue()); + JSHandle scriptQueue(thread, jobQueue->GetScriptJobQueue()); while (!scriptQueue->Empty()) { pendingJob.Update(scriptQueue->Pop(thread)); PendingJob::ExecutePendingJob(pendingJob, thread); diff --git a/ecmascript/jobs/micro_job_queue.h b/ecmascript/jobs/micro_job_queue.h index c2b4d128a4efdbd52ce331e9416b0f25d95162cb..73ab7e159a79c934ebd7d6bcb4f27eed338abfe4 100644 --- a/ecmascript/jobs/micro_job_queue.h +++ b/ecmascript/jobs/micro_job_queue.h @@ -40,9 +40,9 @@ public: return static_cast(object); } - void EnqueueJob(JSThread *thread, QueueType queueType, const JSHandle &job, - const JSHandle &argv); - void ExecutePendingJob(JSThread *thread); + static void EnqueueJob(JSThread *thread, JSHandle jobQueue, QueueType queueType, + const JSHandle &job, const JSHandle &argv); + static void ExecutePendingJob(JSThread *thread, JSHandle jobQueue); static constexpr size_t PROMISE_JOB_QUEUE_OFFSET = Record::SIZE; ACCESSORS(PromiseJobQueue, PROMISE_JOB_QUEUE_OFFSET, SCRIPT_JOB_QUEUE_OFFSET); diff --git a/ecmascript/js_array.cpp b/ecmascript/js_array.cpp index c48c280693a07e308aa9ac460be31b7e37687455..fa31ce04165ed2d4aa05f45560b0918b2f8b1ec3 100644 --- a/ecmascript/js_array.cpp +++ b/ecmascript/js_array.cpp @@ -190,8 +190,8 @@ void JSArray::SetCapacity(JSThread *thread, const JSHandle &array, uin uint32_t attr = dictHandle->GetAttributes(entry).GetValue(); PropertyAttributes propAttr(attr); if (propAttr.IsConfigurable()) { - NumberDictionary *dictionary = NumberDictionary::Remove(thread, dictHandle, entry); - array->SetElements(thread, JSTaggedValue(dictionary)); + NumberDictionary *newDict = NumberDictionary::Remove(thread, dictHandle, entry); + array->SetElements(thread, JSTaggedValue(newDict)); if (i == 0) { newNumOfElements = i; break; diff --git a/ecmascript/js_collator.h b/ecmascript/js_collator.h index 77b21885bf3eb8111eab861d78b7d5be3e2d174f..e757119d01795d41173e5d95bcb3af18b5087f85 100644 --- a/ecmascript/js_collator.h +++ b/ecmascript/js_collator.h @@ -54,6 +54,7 @@ public: ACCESSORS(BoundCompare, BOUND_COMPARE_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, ICU_FIELD_OFFSET, SIZE) + DECL_DUMP() icu::Collator *GetIcuCollator() const { diff --git a/ecmascript/js_date_time_format.h b/ecmascript/js_date_time_format.h index eaedd7f34c8734bfaedf19a239695627f4e725b1..77f8d4918937a006f63e8073937c637d18455cf7 100644 --- a/ecmascript/js_date_time_format.h +++ b/ecmascript/js_date_time_format.h @@ -107,6 +107,7 @@ public: ACCESSORS(BoundFormat, BOUND_FORMAT_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LOCALE_OFFSET, SIZE) + DECL_DUMP() icu::Locale *GetIcuLocale() const; void SetIcuLocale(JSThread *thread, const icu::Locale &icuLocale, const DeleteEntryPoint &callback); diff --git a/ecmascript/js_for_in_iterator.cpp b/ecmascript/js_for_in_iterator.cpp index 7568ade4b813daff0e471fac27addbc03d0ede5a..73a20f5815f8ba08b97b1076e4c7de580b2461cf 100644 --- a/ecmascript/js_for_in_iterator.cpp +++ b/ecmascript/js_for_in_iterator.cpp @@ -197,7 +197,8 @@ void JSForInIterator::SlowGetAllEnumKeys(JSThread *thread, const JSHandleGet(i)); if (value->IsString()) { - remaining.Update(JSTaggedValue(TaggedQueue::Push(thread, remaining, value))); + TaggedQueue *newQueue = TaggedQueue::Push(thread, remaining, value); + remaining.Update(JSTaggedValue(newQueue)); } } it->SetRemainingKeys(thread, remaining); @@ -244,9 +245,9 @@ std::pair JSForInIterator::NextInternal(JSThread *thread, c PropertyDescriptor desc(thread); bool has = JSTaggedValue::GetOwnProperty(thread, object, key, desc); if (has) { - auto queue = JSTaggedValue(TaggedQueue::Push(thread, visited, key)); - visited.Update(queue); - it->SetVisitedKeys(thread, queue); + auto newQueue = JSTaggedValue(TaggedQueue::Push(thread, visited, key)); + visited.Update(newQueue); + it->SetVisitedKeys(thread, newQueue); if (desc.IsEnumerable()) { return std::make_pair(key.GetTaggedValue(), false); } diff --git a/ecmascript/js_for_in_iterator.h b/ecmascript/js_for_in_iterator.h index a33690a249383cf9287a4668696053df8b2e2130..e5a6a4536ee3a7f8a0975abdf9ca2c06ba8a9037 100644 --- a/ecmascript/js_for_in_iterator.h +++ b/ecmascript/js_for_in_iterator.h @@ -52,6 +52,7 @@ public: ACCESSORS(RemainingKeys, REMAINING_KEYS_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, OBJECT_OFFSET, SIZE) + DECL_DUMP() }; } // namespace panda::ecmascript diff --git a/ecmascript/js_function.h b/ecmascript/js_function.h index 316399e1aaeb4c8b2894f4406506734c3750dba0..5d6f3b264b800bf5eaa43b7c98ab4caf5bc730c0 100644 --- a/ecmascript/js_function.h +++ b/ecmascript/js_function.h @@ -431,6 +431,7 @@ public: ACCESSORS(Collator, COLLATOR_OFFSET, SIZE); DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSFunction, NUMBER_FORMAT_OFFSET, SIZE) + DECL_DUMP() }; } // namespace panda::ecmascript diff --git a/ecmascript/js_function_extra_info.h b/ecmascript/js_function_extra_info.h index 5c789e86a979daeb36bd0430c9eb30834f489153..364048917cd5125d9da70c188747ae2013f90d89 100644 --- a/ecmascript/js_function_extra_info.h +++ b/ecmascript/js_function_extra_info.h @@ -36,6 +36,7 @@ public: ACCESSORS(Data, DATA_OFFSET, SIZE); DECL_VISIT_OBJECT(CALL_BACK_OFFSET, SIZE) + DECL_DUMP() }; } // namespace panda::ecmascript #endif diff --git a/ecmascript/js_generator_object.h b/ecmascript/js_generator_object.h index faf1796618f7251ff848ef378747d3250f8813c7..effe125d953fd3ba475e4a44a1cf42d11b60456a 100644 --- a/ecmascript/js_generator_object.h +++ b/ecmascript/js_generator_object.h @@ -46,6 +46,7 @@ public: ACCESSORS(LexicalEnv, GENERATOR_LEXICALENV_OFFSET, SIZE) DECL_VISIT_OBJECT(GENERATOR_REGS_ARRAY_OFFSET, SIZE) + DECL_DUMP() }; class JSGeneratorObject : public JSObject { @@ -84,6 +85,7 @@ public: } DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, GENERATOR_STATE_OFFSET, SIZE) + DECL_DUMP() }; class JSAsyncFuncObject : public JSGeneratorObject { @@ -98,6 +100,7 @@ public: ACCESSORS(Promise, GENERATOR_PROMISE_OFFSET, SIZE); DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSGeneratorObject, GENERATOR_PROMISE_OFFSET, SIZE) + DECL_DUMP() }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/js_hclass-inl.h b/ecmascript/js_hclass-inl.h index 2eeccd944ccb4c876ce040b134c19d046ce15d6a..2ab5b76166ebe3c491a0235dce91f57265d5f9ea 100644 --- a/ecmascript/js_hclass-inl.h +++ b/ecmascript/js_hclass-inl.h @@ -38,6 +38,7 @@ void JSHClass::AddTransitions(const JSThread *thread, const JSHandle & child->SetParent(thread, parent.GetTaggedValue()); return; } + JSMutableHandle dict(thread, JSTaggedValue::Undefined()); if (transitions.IsJSHClass()) { auto cachedHClass = JSHClass::Cast(transitions.GetTaggedObject()); int last = cachedHClass->GetPropertiesNumber() - 1; @@ -45,11 +46,11 @@ void JSHClass::AddTransitions(const JSThread *thread, const JSHandle & auto attr = JSHandle(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); auto lastKey = JSHandle(thread, layoutInfo->GetKey(last)); auto lastHClass = JSHandle(thread, cachedHClass); - auto dict = JSHandle(thread, TransitionsDictionary::Create(thread)); + dict.Update(JSTaggedValue(TransitionsDictionary::Create(thread))); transitions = JSTaggedValue(TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr)); } auto attr = JSHandle(thread, JSTaggedValue(attributes.GetPropertyMetaData())); - JSHandle dict(thread, transitions); + dict.Update(transitions); transitions = JSTaggedValue(TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle(child), attr)); parent->SetTransitions(thread, transitions); @@ -68,6 +69,7 @@ void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle &proto) { JSTaggedValue transitions = parent->GetTransitions(); + JSMutableHandle dict(thread, JSTaggedValue::Undefined()); if (transitions.IsNull()) { transitions = JSTaggedValue(TransitionsDictionary::Create(thread)); } else if (transitions.IsJSHClass()) { @@ -77,11 +79,11 @@ void JSHClass::AddProtoTransitions(const JSThread *thread, const JSHandle(thread, JSTaggedValue(layoutInfo->GetAttr(last).GetPropertyMetaData())); auto lastKey = JSHandle(thread, layoutInfo->GetKey(last)); auto lastHClass = JSHandle(thread, cachedHClass); - auto dict = JSHandle(thread, TransitionsDictionary::Create(thread)); + dict.Update(JSTaggedValue(TransitionsDictionary::Create(thread))); transitions = JSTaggedValue(TransitionsDictionary::PutIfAbsent(thread, dict, lastKey, lastHClass, attr)); } - JSHandle dict(thread, transitions); + dict.Update(transitions); transitions = JSTaggedValue(TransitionsDictionary::PutIfAbsent(thread, dict, key, JSHandle(child), proto)); parent->SetTransitions(thread, transitions); diff --git a/ecmascript/js_hclass.h b/ecmascript/js_hclass.h index 7f29a4976a82fc03ea09532c689d0f1a5d39347e..e12d76cbfb84f47e3788c56b7c3ebe5982fc581d 100644 --- a/ecmascript/js_hclass.h +++ b/ecmascript/js_hclass.h @@ -91,7 +91,6 @@ class ProtoChangeDetails; JS_FLOAT32_ARRAY, /* ////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_FLOAT64_ARRAY, /* JS_TYPED_ARRAY_END ///////////////////////////////////////////////////////////// */ \ JS_PRIMITIVE_REF, /* number\boolean\string. SPECIAL indexed objects end, DON'T CHANGE HERE ////////-PADDING */ \ - JS_NATIVE_OBJECT, /* //////////////////////////////////////////////////////////////////////////////-PADDING */ \ JS_GLOBAL_OBJECT, /* JS_OBJECT_END/////////////////////////////////////////////////////////////////-PADDING */ \ JS_PROXY, /* ECMA_OBJECT_END ////////////////////////////////////////////////////////////////////////////// */ \ \ @@ -335,11 +334,6 @@ public: return GetObjectType() == JSType::JS_NATIVE_POINTER; } - inline bool IsJSNativeObject() const - { - return GetObjectType() == JSType::JS_NATIVE_OBJECT; - } - inline bool IsJSSymbol() const { return GetObjectType() == JSType::SYMBOL; diff --git a/ecmascript/js_intl.h b/ecmascript/js_intl.h index d4c91a60f4c240e4935d7af8672f35e595b82e09..2b1de0b626ea6eb68b226dcdf6a3800ba5f96eae 100644 --- a/ecmascript/js_intl.h +++ b/ecmascript/js_intl.h @@ -32,6 +32,7 @@ public: ACCESSORS(FallbackSymbol, FALLBACK_SYMBOL, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, FALLBACK_SYMBOL, SIZE) + DECL_DUMP() }; } // namespace panda::ecmascript diff --git a/ecmascript/js_locale.h b/ecmascript/js_locale.h index e553afef86fe6b1543abc97ad6e6c941bbde3a0e..7606423beb79d8d8d8f1ebc55e4e5e7037c092c6 100644 --- a/ecmascript/js_locale.h +++ b/ecmascript/js_locale.h @@ -159,6 +159,7 @@ public: ACCESSORS(IcuField, ICU_FIELD_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, ICU_FIELD_OFFSET, SIZE) + DECL_DUMP() icu::Locale *GetIcuLocale() const { diff --git a/ecmascript/js_map.cpp b/ecmascript/js_map.cpp index 9dc01305388be3d4faf06dd9f0a334579b77311f..d51326b4ee6d12530a12a2bf8af562b1114dd77c 100644 --- a/ecmascript/js_map.cpp +++ b/ecmascript/js_map.cpp @@ -28,8 +28,8 @@ void JSMap::Set(JSThread *thread, const JSHandle &map, const JSHandle mapHandle(thread, LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())); - auto result = LinkedHashMap::Set(thread, mapHandle, key, value); - map->SetLinkedMap(thread, result); + JSTaggedValue newMap = LinkedHashMap::Set(thread, mapHandle, key, value); + map->SetLinkedMap(thread, newMap); } bool JSMap::Delete(const JSThread *thread, const JSHandle &map, const JSHandle &key) @@ -41,8 +41,8 @@ bool JSMap::Delete(const JSThread *thread, const JSHandle &map, const JSH } mapHandle->RemoveEntry(thread, entry); - auto result = LinkedHashMap::Shrink(thread, mapHandle); - map->SetLinkedMap(thread, result); + JSTaggedValue newMap = LinkedHashMap::Shrink(thread, mapHandle); + map->SetLinkedMap(thread, newMap); return true; } diff --git a/ecmascript/js_native_object.h b/ecmascript/js_native_object.h deleted file mode 100644 index 0b73f52bd233e5cf8b9706b846458d8b3bd9dd94..0000000000000000000000000000000000000000 --- a/ecmascript/js_native_object.h +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2021 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_JSNATIVEOBJECT_H -#define ECMASCRIPT_JSNATIVEOBJECT_H - -#include "js_object.h" -#include "js_native_pointer.h" - -namespace panda::ecmascript { -class JSNativeObject : JSObject { -public: - static JSNativeObject *Cast(TaggedObject *object) - { - ASSERT(JSTaggedValue(object).IsJSNativeObject()); - return static_cast(object); - } - - inline void SetDeleter(DeleteEntryPoint deleter) - { - if (!GetJSNativePointer().IsJSNativePointer()) { - return; - } - JSNativePointer::Cast(GetJSNativePointer().GetHeapObject())->SetDeleter(deleter); - } - - inline void SetData(void *data) - { - if (!GetJSNativePointer().IsJSNativePointer()) { - return; - } - JSNativePointer::Cast(GetJSNativePointer().GetHeapObject())->SetData(data); - } - - inline const void *GetData() const - { - if (!GetJSNativePointer().IsJSNativePointer()) { - return nullptr; - } - return JSNativePointer::Cast(GetJSNativePointer().GetHeapObject())->GetData(); - } - - inline void Destroy() - { - if (!GetJSNativePointer().IsJSNativePointer()) { - return; - } - JSNativePointer::Cast(GetJSNativePointer().GetHeapObject())->Destroy(); - } - - inline void *GetExternalPointer() const - { - if (!GetJSNativePointer().IsJSNativePointer()) { - return nullptr; - } - return JSNativePointer::Cast(GetJSNativePointer().GetHeapObject())->GetExternalPointer(); - } - - static constexpr size_t OBJECT_OFFSET = JSObject::SIZE; - ACCESSORS(JSNativePointer, OBJECT_OFFSET, SIZE) - - DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, OBJECT_OFFSET, SIZE) -}; -} // namespace panda::ecmascript - -#endif // ECMASCRIPT_JSNATIVEOBJECT_H diff --git a/ecmascript/js_number_format.h b/ecmascript/js_number_format.h index bf0791b9c87366711cdbac0d3c715e19c881580f..2493064d8c9b151f565fa4a49d4d6466f006fa5b 100644 --- a/ecmascript/js_number_format.h +++ b/ecmascript/js_number_format.h @@ -83,6 +83,7 @@ public: ACCESSORS(IcuField, BOUND_FORMAT_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LOCALE_OFFSET, SIZE) + DECL_DUMP() icu::number::LocalizedNumberFormatter *GetIcuCallTarget() const { diff --git a/ecmascript/js_object.cpp b/ecmascript/js_object.cpp index 718f5526885da400161f4d39f042e02addc44359..768265630ba64e7bc9c07bacf10424dada615c87 100644 --- a/ecmascript/js_object.cpp +++ b/ecmascript/js_object.cpp @@ -127,7 +127,8 @@ JSHandle JSObject::TransitionToDictionary(const JSThread *thread attr.SetBoxType(PropertyBoxType::UNDEFINED); valueHandle.Update(value); keyHandle.Update(key); - dict.Update(JSTaggedValue(NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr))); + NameDictionary *newDict = NameDictionary::PutIfAbsent(thread, dict, keyHandle, valueHandle, attr); + dict.Update(JSTaggedValue(newDict)); } receiver->SetProperties(thread, dict); @@ -152,7 +153,8 @@ void JSObject::ElementsToDictionary(const JSThread *thread, JSHandle o } key.Update(JSTaggedValue(i)); valueHandle.Update(value); - dict.Update(JSTaggedValue(NumberDictionary::PutIfAbsent(thread, dict, key, valueHandle, attr))); + NumberDictionary *newDict = NumberDictionary::PutIfAbsent(thread, dict, key, valueHandle, attr); + dict.Update(JSTaggedValue(newDict)); } obj->SetElements(thread, dict); @@ -193,9 +195,9 @@ bool JSObject::AddElementInternal(JSThread *thread, const JSHandle &re if (isDictionary) { ASSERT(elements->IsDictionaryMode()); JSHandle keyHandle(thread, JSTaggedValue(static_cast(index))); - NumberDictionary *dict = + NumberDictionary *newDict = NumberDictionary::Put(thread, JSHandle(thread, elements), keyHandle, value, attr); - receiver->SetElements(thread, JSTaggedValue(dict)); + receiver->SetElements(thread, JSTaggedValue(newDict)); return true; } @@ -205,8 +207,8 @@ bool JSObject::AddElementInternal(JSThread *thread, const JSHandle &re JSObject::ElementsToDictionary(thread, receiver); JSHandle keyHandle(thread, JSTaggedValue(static_cast(index))); JSHandle dict(thread, receiver->GetElements()); - auto key = JSTaggedValue(NumberDictionary::Put(thread, dict, keyHandle, value, attr)); - receiver->SetElements(thread, key); + NumberDictionary *newKey = NumberDictionary::Put(thread, dict, keyHandle, value, attr); + receiver->SetElements(thread, JSTaggedValue(newKey)); return true; } elements = *JSObject::GrowElementsCapacity(thread, receiver, index + 1); @@ -223,8 +225,8 @@ void JSObject::DeletePropertyInternal(JSThread *thread, const JSHandle if (obj->IsJSGlobalObject()) { JSHandle dictHandle(thread, obj->GetProperties()); - GlobalDictionary *dict = GlobalDictionary::Remove(thread, dictHandle, index); - obj->SetProperties(thread, JSTaggedValue(dict)); + GlobalDictionary *newDict = GlobalDictionary::Remove(thread, dictHandle, index); + obj->SetProperties(thread, JSTaggedValue(newDict)); return; } @@ -232,14 +234,14 @@ void JSObject::DeletePropertyInternal(JSThread *thread, const JSHandle JSHandle dictHandle(TransitionToDictionary(thread, obj)); int entry = dictHandle->FindEntry(key.GetTaggedValue()); ASSERT(entry != -1); - NameDictionary *dict = NameDictionary::Remove(thread, dictHandle, entry); - obj->SetProperties(thread, JSTaggedValue(dict)); + NameDictionary *newDict = NameDictionary::Remove(thread, dictHandle, entry); + obj->SetProperties(thread, JSTaggedValue(newDict)); return; } JSHandle dictHandle(array); - NameDictionary *dict = NameDictionary::Remove(thread, dictHandle, index); - obj->SetProperties(thread, JSTaggedValue(dict)); + NameDictionary *newDict = NameDictionary::Remove(thread, dictHandle, index); + obj->SetProperties(thread, JSTaggedValue(newDict)); } void JSObject::GetAllKeys(const JSThread *thread, const JSHandle &obj, int offset, @@ -1946,7 +1948,8 @@ void *ECMAObject::GetNativePointerField(int32_t index) const return nullptr; } -void ECMAObject::SetNativePointerField(int32_t index, void *data) +void ECMAObject::SetNativePointerField(int32_t index, void *nativePointer, + const DeleteEntryPoint &callBack, void *data) { JSTaggedType hashField = Barriers::GetDynValue(this, HASH_OFFSET); JSTaggedValue value(hashField); @@ -1954,7 +1957,12 @@ void ECMAObject::SetNativePointerField(int32_t index, void *data) JSThread *thread = this->GetJSThread(); JSHandle array(thread, value); if (static_cast(array->GetLength()) > index + 1) { - JSHandle pointer = thread->GetEcmaVM()->GetFactory()->NewJSNativePointer(data); + EcmaVM *vm = thread->GetEcmaVM(); + JSHandle pointer = vm->GetFactory()->NewJSNativePointer( + nativePointer, callBack, data); + if (callBack != nullptr) { + vm->PushToArrayDataList(*pointer); + } array->Set(thread, index + 1, pointer.GetTaggedValue()); } } diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index 9030b10ef678b22ae3c335ce8fd41b5e2fec85e8..b426a36d1f234166161b23ed652849d5fe1a48b2 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -345,7 +345,8 @@ public: } void* GetNativePointerField(int32_t index) const; - void SetNativePointerField(int32_t index, void *data); + void SetNativePointerField(int32_t index, void *nativePointer, + const DeleteEntryPoint &callBack, void *data); int32_t GetNativePointerFieldCount() const; void SetNativePointerFieldCount(int32_t count); @@ -590,7 +591,7 @@ public: ACCESSORS(Properties, PROPERTIES_OFFSET, ELEMENTS_OFFSET); ACCESSORS(Elements, ELEMENTS_OFFSET, SIZE); - + DECL_VISIT_OBJECT_FOR_JS_OBJECT(ECMAObject, PROPERTIES_OFFSET, SIZE) DECL_DUMP() diff --git a/ecmascript/js_plural_rules.h b/ecmascript/js_plural_rules.h index 1e87fa0287fb286b4b24fb7c30923d17f1e595d0..4faa7315928d27e83071dd7225de7bdbac5e891a 100644 --- a/ecmascript/js_plural_rules.h +++ b/ecmascript/js_plural_rules.h @@ -50,6 +50,7 @@ public: ACCESSORS(IcuNF, ICU_NUMBER_FORMAT_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LOCALE_OFFSET, SIZE) + DECL_DUMP() icu::number::LocalizedNumberFormatter *GetIcuNumberFormatter() const; diff --git a/ecmascript/js_promise.cpp b/ecmascript/js_promise.cpp index a8a3a1f41e5326e418385dc647153e0244088fe5..ef1ff241102acc3f2d3e9ccd003c9c5326e5a24c 100644 --- a/ecmascript/js_promise.cpp +++ b/ecmascript/js_promise.cpp @@ -178,7 +178,7 @@ JSTaggedValue JSPromise::TriggerPromiseReactions(JSThread *thread, const JSHandl JSHandle arguments = factory->NewTaggedArray(2); // 2 means the length of new array arguments->Set(thread, 0, reaction); arguments->Set(thread, 1, argument); - job->EnqueueJob(thread, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, arguments); + job::MicroJobQueue::EnqueueJob(thread, job, job::QueueType::QUEUE_PROMISE, promiseReactionsJob, arguments); } // 2. Return undefined. return globalConst->GetUndefined(); diff --git a/ecmascript/js_realm.h b/ecmascript/js_realm.h index 0372898caa9dcbee4623dbf26398a67cf4fcb030..6d201190f26a908f086f31bc6504c83f8be0a415 100644 --- a/ecmascript/js_realm.h +++ b/ecmascript/js_realm.h @@ -29,6 +29,9 @@ public: static constexpr size_t VALUE_OFFSET = JSObject::SIZE; ACCESSORS(Value, VALUE_OFFSET, GLOBAL_ENV_OFFSET) ACCESSORS(GlobalEnv, GLOBAL_ENV_OFFSET, SIZE) + + DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, VALUE_OFFSET, SIZE) + DECL_DUMP() }; } // namespace panda::ecmascript diff --git a/ecmascript/js_relative_time_format.h b/ecmascript/js_relative_time_format.h index 2c5fdc261906cb362c6e224494ac07d4cc550fe2..418c6f4e2a4983d6eeb45d73a55ff2673e4da324 100644 --- a/ecmascript/js_relative_time_format.h +++ b/ecmascript/js_relative_time_format.h @@ -55,6 +55,7 @@ public: ACCESSORS(IcuField, ICU_FIELD_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, LOCALE_OFFSET, SIZE) + DECL_DUMP() // 14.1.1 InitializeRelativeTimeFormat ( relativeTimeFormat, locales, options ) static JSHandle InitializeRelativeTimeFormat( diff --git a/ecmascript/js_runtime_options.h b/ecmascript/js_runtime_options.h new file mode 100644 index 0000000000000000000000000000000000000000..fa4d7ac22d79f7dafea4b9a8969fc6b643af9394 --- /dev/null +++ b/ecmascript/js_runtime_options.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2021 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_JS_RUNTIME_OPTIONS_H_ +#define ECMASCRIPT_JS_RUNTIME_OPTIONS_H_ + +#include "runtime/include/runtime_options.h" +#include "utils/logger.h" + +// namespace panda { +namespace panda::ecmascript { +class JSRuntimeOptions : public RuntimeOptions { +public: + explicit JSRuntimeOptions(const std::string &exe_path = "") : RuntimeOptions(exe_path) {} + ~JSRuntimeOptions() = default; + DEFAULT_COPY_SEMANTIC(JSRuntimeOptions); + DEFAULT_MOVE_SEMANTIC(JSRuntimeOptions); + + void AddOptions(PandArgParser *parser) + { + RuntimeOptions::AddOptions(parser); + parser->Add(&enable_ark_tools_); + parser->Add(&enable_stub_aot_); + parser->Add(&stub_module_file_); + } + + bool IsEnableArkTools() const + { + return enable_ark_tools_.GetValue(); + } + + void SetEnableArkTools(bool value) + { + enable_ark_tools_.SetValue(value); + } + + bool WasSetEnableArkTools() const + { + return enable_ark_tools_.WasSet(); + } + + bool IsEnableStubAot() const + { + return enable_stub_aot_.GetValue(); + } + + void SetEnableStubAot(bool value) + { + enable_stub_aot_.SetValue(value); + } + + bool WasSetEnableStubAot() const + { + return enable_stub_aot_.WasSet(); + } + + std::string GetStubModuleFile() const + { + return stub_module_file_.GetValue(); + } + + void SetStubModuleFile(std::string value) + { + stub_module_file_.SetValue(std::move(value)); + } + + bool WasSetStubModuleFile() const + { + return stub_module_file_.WasSet(); + } + +private: + PandArg enable_ark_tools_{"enable-ark-tools", false, R"(Enable ark tools to debug. Default: false)"}; + PandArg enable_stub_aot_{"enable-stub-aot", false, R"(enable aot of fast stub. Default: false)"}; + PandArg stub_module_file_{"stub-module-file", R"(stub.m)", + R"(Path to stub module file. Default: "stub.m")"}; +}; +} // namespace panda::ecmascript + +#endif // ECMASCRIPT_JS_RUNTIME_OPTIONS_H_ diff --git a/ecmascript/js_set.cpp b/ecmascript/js_set.cpp index 58a4694ffd6942bfa340fb70c9c865bf678110e9..e83e11e500b69e3edb045c90b44a372478b1822b 100644 --- a/ecmascript/js_set.cpp +++ b/ecmascript/js_set.cpp @@ -28,8 +28,8 @@ void JSSet::Add(JSThread *thread, const JSHandle &set, const JSHandle setHandle(thread, LinkedHashSet::Cast(set->GetLinkedSet().GetTaggedObject())); - auto table = LinkedHashSet::Add(thread, setHandle, value); - set->SetLinkedSet(thread, table); + JSTaggedValue newSet = LinkedHashSet::Add(thread, setHandle, value); + set->SetLinkedSet(thread, newSet); } bool JSSet::Delete(const JSThread *thread, const JSHandle &set, const JSHandle &value) @@ -40,8 +40,8 @@ bool JSSet::Delete(const JSThread *thread, const JSHandle &set, const JSH return false; } setHandle->RemoveEntry(thread, entry); - auto table = LinkedHashSet::Shrink(thread, setHandle); - set->SetLinkedSet(thread, table); + JSTaggedValue newSet = LinkedHashSet::Shrink(thread, setHandle); + set->SetLinkedSet(thread, newSet); return true; } diff --git a/ecmascript/js_string_iterator.h b/ecmascript/js_string_iterator.h index d13304be5967fc22ca5890d2a33985b2637a2601..db465bf6bd4703e78c135cbf562c1dec8c73ced1 100644 --- a/ecmascript/js_string_iterator.h +++ b/ecmascript/js_string_iterator.h @@ -38,6 +38,7 @@ public: ACCESSORS(StringIteratorNextIndex, STRING_ITERATOR_NEXT_INDEX_OFFSET, SIZE) DECL_VISIT_OBJECT_FOR_JS_OBJECT(JSObject, ITERATED_STRING_OFFSET, SIZE) + DECL_DUMP() }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/js_tagged_value-inl.h b/ecmascript/js_tagged_value-inl.h index 27d6f86f29bebe0707ff1c7341510edef4681a8b..56c75d06a2e2541692bb678fc60464efffba7b04 100644 --- a/ecmascript/js_tagged_value-inl.h +++ b/ecmascript/js_tagged_value-inl.h @@ -382,11 +382,6 @@ inline bool JSTaggedValue::IsNativePointer() const return IsJSNativePointer(); } -inline bool JSTaggedValue::IsJSNativeObject() const -{ - return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSNativeObject(); -} - inline bool JSTaggedValue::IsJSNativePointer() const { return IsHeapObject() && GetTaggedObject()->GetClass()->IsJSNativePointer(); diff --git a/ecmascript/js_tagged_value.cpp b/ecmascript/js_tagged_value.cpp index b86a3f164ad775970c1e680665035206b5d3f282..3b7ca1440ae3b7413a2f083f9c33af36a77ae5ea 100644 --- a/ecmascript/js_tagged_value.cpp +++ b/ecmascript/js_tagged_value.cpp @@ -261,11 +261,10 @@ JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandleIsECMAObject()) { - JSHandle object(tagged); EcmaVM *vm = thread->GetEcmaVM(); JSHandle keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol(); - JSHandle exoticToprim = JSObject::GetProperty(thread, object, keyString).GetValue(); + JSHandle exoticToprim = GetProperty(thread, tagged, keyString).GetValue(); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); if (!exoticToprim->IsUndefined()) { JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue(); @@ -298,7 +297,7 @@ JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandl } else { keyString = globalConst->GetHandledValueOfString(); } - JSHandle entryfunc = JSObject::GetProperty(thread, tagged, keyString).GetValue(); + JSHandle entryfunc = GetProperty(thread, tagged, keyString).GetValue(); if (entryfunc->IsCallable()) { JSTaggedValue valueResult = JSFunction::Call(thread, entryfunc, tagged, 0, nullptr); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); diff --git a/ecmascript/js_tagged_value.h b/ecmascript/js_tagged_value.h index 1cd220490dd6fc7d75ad3c795751300579a5a017..2d018f1982485c10a7be227256fe6087d6a1aea0 100644 --- a/ecmascript/js_tagged_value.h +++ b/ecmascript/js_tagged_value.h @@ -233,7 +233,6 @@ public: bool IsTaggedArray() const; bool IsNativePointer() const; bool IsJSNativePointer() const; - bool IsJSNativeObject() const; bool IsBoolean() const; bool IsSymbol() const; bool IsJSObject() const; @@ -333,7 +332,8 @@ public: void DumpTaggedValue(JSThread *thread, std::ostream &os) const DUMP_API_ATTR; void Dump(JSThread *thread, std::ostream &os) const DUMP_API_ATTR; void Dump(JSThread *thread) const DUMP_API_ATTR; - void DumpForSnapshot(JSThread *thread, std::vector> &vec) const; + void DumpForSnapshot(JSThread *thread, std::vector> &vec, + bool isVmMode = true) const; static void DumpVal(JSThread *thread, JSTaggedType val) DUMP_API_ATTR; private: diff --git a/ecmascript/js_thread.cpp b/ecmascript/js_thread.cpp index 5ed583444cebe147c94114f43939bf83e09da12e..5a1879da11dadcddd6f65cf33f1426c1ba6b5268 100644 --- a/ecmascript/js_thread.cpp +++ b/ecmascript/js_thread.cpp @@ -13,6 +13,7 @@ * limitations under the License. */ +#include "ecmascript/compiler/llvm/llvm_stackmap_parser.h" #include "ecmascript/global_env_constants-inl.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/interpreter/interpreter-inl.h" @@ -78,7 +79,7 @@ void JSThread::ClearException() JSTaggedValue JSThread::GetCurrentLexenv() const { - return EcmaFrameHandler(currentFrame_).GetEnv(); + return InterpretedFrameHandler(currentFrame_).GetEnv(); } void JSThread::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) @@ -86,14 +87,19 @@ void JSThread::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) if (!exception_.IsHole()) { v0(Root::ROOT_VM, ObjectSlot(ToUintPtr(&exception_))); } - + if (!stubCode_.IsHole()) { + v0(Root::ROOT_VM, ObjectSlot(ToUintPtr(&stubCode_))); + } + if (!stubStackMap_.IsHole()) { + v0(Root::ROOT_VM, ObjectSlot(ToUintPtr(&stubStackMap_))); + } // visit global Constant globalConst_.VisitRangeSlot(v1); // visit stack roots - EcmaFrameHandler(currentFrame_).Iterate(v0, v1); - // visit internal call params + FrameIterator iterator(currentFrame_, this); + iterator.Iterate(v0, v1); + // visit internal call params; internalCallParams_->Iterate(v1); - // visit tagged handle storage roots if (currentHandleStorageIndex_ != -1) { int32_t nid = currentHandleStorageIndex_; @@ -220,6 +226,14 @@ void JSThread::LoadFastStubModule(const char *moduleFile) for (int i = 0; i < kungfu::FAST_STUB_MAXCOUNT; i++) { fastStubEntires_[i] = stubModule.GetStubEntry(i); } + uint8_t *ptr = reinterpret_cast(stubModule.GetStackMapAddr()); + Address hostCodeSectionAddr = stubModule.GetHostCodeSectionAddr(); + uintptr_t deviceCodeSectionAddr = stubModule.GetDeviceCodeSectionAddr(); + kungfu::LLVMStackMapParser::GetInstance().CalculateStackMap(ptr, hostCodeSectionAddr, deviceCodeSectionAddr); +#ifdef NDEBUG + kungfu::LLVMStackMapParser::GetInstance().Print(); +#endif stubCode_ = stubModule.GetCode(); + stubStackMap_ = stubModule.GetStackMapData(); } } // namespace panda::ecmascript diff --git a/ecmascript/js_thread.h b/ecmascript/js_thread.h index 7f597de23a65b35fa6c0577ff362e6a939355c17..9a822dbfd2a4dd8f79d7ae1896875d9e9a0a237b 100644 --- a/ecmascript/js_thread.h +++ b/ecmascript/js_thread.h @@ -19,9 +19,9 @@ #include "ecmascript/compiler/fast_stub_define.h" #include "ecmascript/ecma_global_storage.h" #include "ecmascript/global_env_constants.h" -#include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/mem/heap_roots.h" #include "include/thread.h" +#include "ecmascript/frames.h" namespace panda::ecmascript { class EcmaVM; @@ -75,6 +75,16 @@ public: currentFrame_ = sp; } + const JSTaggedType *GetLastInterpretedFrameSp() const + { + return lastIFrame_; + } + + void SetLastIFrameSp(JSTaggedType *sp) + { + lastIFrame_ = sp; + } + bool DoStackOverflowCheck(const JSTaggedType *sp); bool IsEcmaInterpreter() const @@ -169,6 +179,14 @@ public: return fastStubEntires_[id]; } + void SetFastStubEntry(uint32_t id, Address entry) + { + ASSERT(id < kungfu::FAST_STUB_MAXCOUNT); + fastStubEntires_[id] = entry; + } + + void InitializeFastRuntimeStubs(); + void LoadFastStubModule(const char *moduleFile); static uint32_t GetRuntimeFunctionsOffset() @@ -181,6 +199,16 @@ public: return MEMBER_OFFSET(JSThread, currentFrame_); } + static uint64_t GetGlobalConstantOffset() + { + return MEMBER_OFFSET(JSThread, globalConst_); + } + + static uint64_t GetFastStubEntryOffset() + { + return MEMBER_OFFSET(JSThread, fastStubEntires_); + } + InternalCallParams *GetInternalCallParams() const { return internalCallParams_; @@ -198,6 +226,14 @@ public: void IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor); + uintptr_t* GetLastOptCallRuntimePc() const + { + return lastOptCallRuntimePc_; + } + void SetLastOptCallRuntimePc(uintptr_t* pc) + { + lastOptCallRuntimePc_ = pc; + } private: NO_COPY_SEMANTIC(JSThread); NO_MOVE_SEMANTIC(JSThread); @@ -214,12 +250,14 @@ private: Address runtimeFunctions_[MAX_RUNTIME_FUNCTIONS]; Address fastStubEntires_[kungfu::FAST_STUB_MAXCOUNT]; JSTaggedValue stubCode_ {JSTaggedValue::Hole()}; + JSTaggedValue stubStackMap_ {JSTaggedValue::Hole()}; EcmaGlobalStorage *globalStorage_ {nullptr}; os::memory::ConditionVariable initializationVar_ GUARDED_BY(initializationLock_); os::memory::Mutex initializationLock_; int nestedLevel_ = 0; JSTaggedType *currentFrame_ {nullptr}; + JSTaggedType *lastIFrame_ {nullptr}; JSTaggedType *frameBase_ {nullptr}; bool isSnapshotMode_ {false}; bool isEcmaInterpreter_ {false}; @@ -232,6 +270,7 @@ private: bool stableArrayElementsGuardians_ {true}; GlobalEnvConstants globalConst_; // Place-Holder InternalCallParams *internalCallParams_ {nullptr}; + uintptr_t *lastOptCallRuntimePc_ {nullptr}; friend class EcmaHandleScope; friend class GlobalHandleCollection; diff --git a/ecmascript/js_vm/main.cpp b/ecmascript/js_vm/main.cpp index a3bad4b9ed4861c2b6459d07abec7cc6640c0780..c03701c8eb8792391a7605a63ef9c1400af4599f 100644 --- a/ecmascript/js_vm/main.cpp +++ b/ecmascript/js_vm/main.cpp @@ -23,6 +23,7 @@ #include "ecmascript/ecma_language_context.h" #include "ecmascript/ecma_string.h" #include "ecmascript/ecma_vm.h" +#include "ecmascript/js_runtime_options.h" #include "ecmascript/napi/include/jsnapi.h" #include "include/runtime.h" #include "libpandabase/os/native_stack.h" @@ -59,12 +60,12 @@ int Main(const int argc, const char **argv) BlockSignals(); Span sp(argv, argc); - RuntimeOptions runtimeOptions(sp[0]); + JSRuntimeOptions runtimeOptions(sp[0]); panda::PandArg help("help", false, "Print this message and exit"); panda::PandArg options("options", false, "Print compiler and runtime options"); // tail arguments - panda::PandArg file("file", "", "path to pandafile"); + panda::PandArg files("files", {""}, "path to pandafiles", ":"); panda::PandArg entrypoint("entrypoint", "_GLOBAL::func_main_0", "full name of entrypoint function or method"); panda::PandArgParser paParser; @@ -73,16 +74,16 @@ int Main(const int argc, const char **argv) paParser.Add(&help); paParser.Add(&options); - paParser.PushBackTail(&file); + paParser.PushBackTail(&files); paParser.PushBackTail(&entrypoint); paParser.EnableTail(); paParser.EnableRemainder(); - if (!paParser.Parse(argc, argv) || file.GetValue().empty() || entrypoint.GetValue().empty() || help.GetValue()) { + if (!paParser.Parse(argc, argv) || files.GetValue().empty() || entrypoint.GetValue().empty() || help.GetValue()) { std::cerr << paParser.GetErrorString() << std::endl; std::cerr << "Usage: " << "panda" - << " [OPTIONS] [file] [entrypoint] -- [arguments]" << std::endl; + << " [OPTIONS] [file1:file2:file3] [entrypoint] -- [arguments]" << std::endl; std::cerr << std::endl; std::cerr << "optional arguments:" << std::endl; std::cerr << paParser.GetHelpString() << std::endl; @@ -106,6 +107,7 @@ int Main(const int argc, const char **argv) runtimeOptions.SetShouldInitializeIntrinsics(false); runtimeOptions.SetBootClassSpaces({"ecmascript"}); runtimeOptions.SetRuntimeType("ecmascript"); + JSNApi::SetOptions(runtimeOptions); static EcmaLanguageContext lcEcma; bool ret = Runtime::Create(runtimeOptions, {&lcEcma}); if (!ret) { @@ -118,16 +120,20 @@ int Main(const int argc, const char **argv) std::cout << paParser.GetRegularArgs() << std::endl; } - std::string fileName = file.GetValue(); - std::string entry = entrypoint.GetValue(); - EcmaVM *vm = EcmaVM::Cast(runtime->GetPandaVM()); - auto fileNameRef = StringRef::NewFromUtf8(vm, fileName.c_str(), fileName.size()); + + std::string entry = entrypoint.GetValue(); auto entryRef = StringRef::NewFromUtf8(vm, entry.c_str(), entry.size()); - auto res = JSNApi::Execute(vm, fileNameRef, entryRef); - if (!res) { - std::cerr << "Cannot execute panda file '" << fileName << "' with entry '" << entry << "'" << std::endl; - ret = false; + + arg_list_t fileNames = files.GetValue(); + for (const auto &fileName : fileNames) { + auto fileNameRef = StringRef::NewFromUtf8(vm, fileName.c_str(), fileName.size()); + auto res = JSNApi::Execute(vm, fileNameRef, entryRef); + if (!res) { + std::cerr << "Cannot execute panda file '" << fileName << "' with entry '" << entry << "'" << std::endl; + ret = false; + break; + } } if (!Runtime::Destroy()) { diff --git a/ecmascript/js_weak_container.cpp b/ecmascript/js_weak_container.cpp index 7a4a132d934a107bf9c373845239694626b2b25b..0616ee7528560f0f15e67d743e4408b67d4374cc 100644 --- a/ecmascript/js_weak_container.cpp +++ b/ecmascript/js_weak_container.cpp @@ -30,8 +30,8 @@ void JSWeakMap::Set(JSThread *thread, const JSHandle &map, const JSHa } JSHandle mapHandle(thread, LinkedHashMap::Cast(map->GetLinkedMap().GetTaggedObject())); - auto result = LinkedHashMap::SetWeakRef(thread, mapHandle, key, value); - map->SetLinkedMap(thread, result); + JSTaggedValue newMap = LinkedHashMap::SetWeakRef(thread, mapHandle, key, value); + map->SetLinkedMap(thread, newMap); } bool JSWeakMap::Delete(JSThread *thread, const JSHandle &map, const JSHandle &key) @@ -43,8 +43,8 @@ bool JSWeakMap::Delete(JSThread *thread, const JSHandle &map, const J } mapHandle->RemoveEntry(thread, entry); - auto result = LinkedHashMap::Shrink(thread, mapHandle); - map->SetLinkedMap(thread, result); + JSTaggedValue newMap = LinkedHashMap::Shrink(thread, mapHandle); + map->SetLinkedMap(thread, newMap); return true; } @@ -70,8 +70,8 @@ void JSWeakSet::Add(JSThread *thread, const JSHandle &weakSet, const } JSHandle weakSetHandle(thread, LinkedHashSet::Cast(weakSet->GetLinkedSet().GetTaggedObject())); - auto result = LinkedHashSet::AddWeakRef(thread, weakSetHandle, value); - weakSet->SetLinkedSet(thread, result); + JSTaggedValue newSet = LinkedHashSet::AddWeakRef(thread, weakSetHandle, value); + weakSet->SetLinkedSet(thread, newSet); } bool JSWeakSet::Delete(JSThread *thread, const JSHandle &weakSet, const JSHandle &value) @@ -82,8 +82,8 @@ bool JSWeakSet::Delete(JSThread *thread, const JSHandle &weakSet, con return false; } weakSetHandle->RemoveEntry(thread, entry); - auto result = LinkedHashSet::Shrink(thread, weakSetHandle); - weakSet->SetLinkedSet(thread, result); + JSTaggedValue newSet = LinkedHashSet::Shrink(thread, weakSetHandle); + weakSet->SetLinkedSet(thread, newSet); return true; } diff --git a/ecmascript/linked_hash_table-inl.h b/ecmascript/linked_hash_table-inl.h index b64e2c57a6e9960e5900e76634c5c0b56206c083..c4a8976b2a11e4901dd2711c58ed9abf66c92483 100644 --- a/ecmascript/linked_hash_table-inl.h +++ b/ecmascript/linked_hash_table-inl.h @@ -24,18 +24,14 @@ namespace panda::ecmascript { template JSTaggedValue LinkedHashTable::GetElement(int index) const { - if (UNLIKELY((index < 0 || index > static_cast(GetLength())))) { - return JSTaggedValue::Undefined(); - } + ASSERT(index >= 0 && index < static_cast(GetLength())); return Get(index); } template void LinkedHashTable::SetElement(const JSThread *thread, int index, JSTaggedValue element) { - if (UNLIKELY((index < 0 || index > static_cast(GetLength())))) { - return; - } + ASSERT(index >= 0 && index < static_cast(GetLength())); Set(thread, index, element); } @@ -272,4 +268,4 @@ bool LinkedHashMapObject::IsMatch(JSTaggedValue key, JSTaggedValue other) return JSTaggedValue::SameValueZero(key, other); } } // namespace panda::ecmascript -#endif // ECMASCRIPT_LINKED_HASH_TABLE_INL_H \ No newline at end of file +#endif // ECMASCRIPT_LINKED_HASH_TABLE_INL_H diff --git a/ecmascript/mem/allocator-inl.h b/ecmascript/mem/allocator-inl.h index bf0d150fcbc0a28e2fc5243701bd585e0dee33a7..476839d18386fae2ae640ef546e73543dc1c40e0 100644 --- a/ecmascript/mem/allocator-inl.h +++ b/ecmascript/mem/allocator-inl.h @@ -19,6 +19,7 @@ #include #include "ecmascript/mem/allocator.h" +#include "ecmascript/mem/concurrent_sweeper.h" #include "ecmascript/mem/heap-inl.h" #include "ecmascript/mem/space.h" #include "ecmascript/free_object.h" @@ -67,13 +68,13 @@ uintptr_t BumpPointerAllocator::Allocate(size_t size) return result; } -FreeListAllocator::FreeListAllocator(const Space *space) +FreeListAllocator::FreeListAllocator(const Space *space) : heap_(space->GetHeap()), type_(space->GetSpaceType()) { freeList_ = std::make_unique(); - heap_ = space->GetHeap(); uintptr_t begin = space->GetCurrentRegion()->GetBegin(); size_t size = space->GetCurrentRegion()->GetSize(); FreeObject::Cast(begin)->SetAvailable(size); + FreeObject::Cast(begin)->SetNext(nullptr); freeList_->Free(begin, size); } @@ -96,18 +97,39 @@ uintptr_t FreeListAllocator::Allocate(size_t size) } FreeObject *object = freeList_->Allocator(size); if (LIKELY(object != nullptr && !object->IsEmpty())) { - FreeBumpPoint(); - bpAllocator_.Reset(object->GetBegin(), object->GetEnd()); - ret = bpAllocator_.Allocate(size); - if (ret != 0 && bpAllocator_.Available() > 0) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), bpAllocator_.GetTop(), bpAllocator_.Available()); + return Allocate(object, size); + } + + if (sweeping_) { + // Concurrent sweep maybe sweep same region + heap_->GetSweeper()->FillSweptRegion(type_); + object = freeList_->Allocator(size); + if (LIKELY(object != nullptr && !object->IsEmpty())) { + return Allocate(object, size); + } + + // Parallel + heap_->GetSweeper()->WaitingTaskFinish(type_); + object = freeList_->Allocator(size); + if (LIKELY(object != nullptr && !object->IsEmpty())) { + return Allocate(object, size); } - return ret; } return 0; } +uintptr_t FreeListAllocator::Allocate(FreeObject *object, size_t size) +{ + FreeBumpPoint(); + bpAllocator_.Reset(object->GetBegin(), object->GetEnd()); + auto ret = bpAllocator_.Allocate(size); + if (ret != 0 && bpAllocator_.Available() > 0) { + FreeObject::FillFreeObject(heap_->GetEcmaVM(), bpAllocator_.GetTop(), bpAllocator_.Available()); + } + return ret; +} + void FreeListAllocator::FreeBumpPoint() { auto begin = bpAllocator_.GetTop(); @@ -116,16 +138,16 @@ void FreeListAllocator::FreeBumpPoint() bpAllocator_.Reset(); } -void FreeListAllocator::Free(uintptr_t begin, uintptr_t end) +void FreeListAllocator::Free(uintptr_t begin, uintptr_t end, bool isAdd) { ASSERT(heap_ != nullptr); size_t size = end - begin; + FreeObject::FillFreeObject(heap_->GetEcmaVM(), begin, size); if (UNLIKELY(size < FreeObject::SIZE_OFFSET)) { return; } - FreeObject::FillFreeObject(heap_->GetEcmaVM(), begin, size); - freeList_->Free(begin, static_cast(end - begin)); + freeList_->Free(begin, size, isAdd); } void FreeListAllocator::RebuildFreeList() @@ -133,5 +155,18 @@ void FreeListAllocator::RebuildFreeList() bpAllocator_.Reset(); freeList_->Rebuild(); } + +void FreeListAllocator::FillFreeList(FreeObjectKind *kind) +{ + freeList_->AddKind(kind); +} + +size_t FreeListAllocator::GetAvailableSize() const +{ + if (sweeping_) { + heap_->GetSweeper()->WaitingTaskFinish(type_); + } + return freeList_->GetFreeObjectSize(); +} } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_ALLOCATOR_INL_H diff --git a/ecmascript/mem/allocator.h b/ecmascript/mem/allocator.h index 25b3d3d4cc8841bdc9475f92e0af6125b9978c59..0ea0cf0f086e2a42e943e59a71aea7e8d5c45c78 100644 --- a/ecmascript/mem/allocator.h +++ b/ecmascript/mem/allocator.h @@ -91,28 +91,37 @@ public: inline void AddFree(Region *region); inline void RebuildFreeList(); + inline void FillFreeList(FreeObjectKind *kind); void Swap(FreeListAllocator &other) { heap_ = other.heap_; bpAllocator_.Swap(other.bpAllocator_); freeList_.swap(other.freeList_); + type_ = other.type_; + sweeping_ = other.sweeping_; } inline void FreeBumpPoint(); - inline void Free(uintptr_t begin, uintptr_t end); + inline void Free(uintptr_t begin, uintptr_t end, bool isAdd = true); inline void SplitFreeObject(FreeObject *current, size_t allocateSize); - size_t GetAvailableSize() const + inline size_t GetAvailableSize() const; + + void SetSweeping(bool sweeping) { - return freeList_->GetFreeObjectSize(); + sweeping_ = sweeping; } private: + inline uintptr_t Allocate(FreeObject *object, size_t size); + BumpPointerAllocator bpAllocator_; std::unique_ptr freeList_; Heap *heap_{nullptr}; + MemSpaceType type_ = OLD_SPACE; + bool sweeping_ = false; }; } // namespace panda::ecmascript diff --git a/ecmascript/mem/compress_collector.cpp b/ecmascript/mem/compress_collector.cpp index db3759594c3e193fd0be8a585f48de9cd9037310..8fd14bbb395dbcae4ba6ec0a64061db65937c143 100644 --- a/ecmascript/mem/compress_collector.cpp +++ b/ecmascript/mem/compress_collector.cpp @@ -13,9 +13,10 @@ * limitations under the License. */ +#include "ecmascript/mem/compress_collector.h" + #include "ecmascript/ecma_vm.h" #include "ecmascript/mem/clock_scope.h" -#include "ecmascript/mem/compress_collector.h" #include "ecmascript/mem/compress_gc_marker-inl.h" #include "ecmascript/mem/ecma_heap_manager.h" #include "ecmascript/mem/heap-inl.h" @@ -58,6 +59,7 @@ void CompressCollector::RunPhases() void CompressCollector::InitializePhase() { heap_->GetThreadPool()->WaitTaskFinish(); + heap_->GetSweeper()->EnsureAllTaskFinish(); auto compressSpace = const_cast(heap_->GetCompressSpace()); if (compressSpace->GetCommittedSize() == 0) { compressSpace->Initialize(); @@ -70,8 +72,6 @@ void CompressCollector::InitializePhase() FreeListAllocator compressAllocator(compressSpace); oldSpaceAllocator_.Swap(compressAllocator); fromSpaceAllocator_.Reset(fromSpace); - auto heapManager = heap_->GetHeapManager(); - nonMovableAllocator_.Swap(heapManager->GetNonMovableSpaceAllocator()); auto callback = [](Region *current) { // ensure mark bitmap @@ -87,6 +87,7 @@ void CompressCollector::InitializePhase() } }; heap_->GetNonMovableSpace()->EnumerateRegions(callback); + heap_->GetMachineCodeSpace()->EnumerateRegions(callback); heap_->GetSnapShotSpace()->EnumerateRegions(callback); heap_->GetHugeObjectSpace()->EnumerateRegions(callback); @@ -116,7 +117,6 @@ void CompressCollector::FinishPhase() workList_->Finish(youngAndOldAliveSize_); auto heapManager = heap_->GetHeapManager(); heapManager->GetOldSpaceAllocator().Swap(oldSpaceAllocator_); - heapManager->GetNonMovableSpaceAllocator().Swap(nonMovableAllocator_); heapManager->GetNewSpaceAllocator().Swap(fromSpaceAllocator_); } @@ -230,60 +230,7 @@ void CompressCollector::SweepPhases() heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak); heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak); - SweepSpace(const_cast(heap_->GetNonMovableSpace()), nonMovableAllocator_); - SweepSpace(const_cast(heap_->GetHugeObjectSpace())); -} - -void CompressCollector::SweepSpace(HugeObjectSpace *space) -{ - Region *currentRegion = space->GetRegionList().GetFirst(); - while (currentRegion != nullptr) { - Region *next = currentRegion->GetNext(); - auto markBitmap = currentRegion->GetMarkBitmap(); - bool isMarked = false; - markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; }); - if (!isMarked) { - space->GetRegionList().RemoveNode(currentRegion); - space->ClearAndFreeRegion(currentRegion); - } - currentRegion = next; - } -} - -void CompressCollector::SweepSpace(Space *space, FreeListAllocator &allocator) -{ - allocator.RebuildFreeList(); - space->EnumerateRegions([this, &allocator](Region *current) { - auto markBitmap = current->GetMarkBitmap(); - ASSERT(markBitmap != nullptr); - uintptr_t freeStart = current->GetBegin(); - markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator](void *mem) { - ASSERT(current->InRange(ToUintPtr(mem))); - auto header = reinterpret_cast(mem); - auto klass = header->GetClass(); - JSType jsType = klass->GetObjectType(); - auto size = klass->SizeFromJSHClass(jsType, header); - size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); - - uintptr_t freeEnd = ToUintPtr(mem); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - freeStart = freeEnd + size; - }); - uintptr_t freeEnd = current->GetEnd(); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - }); -} - -void CompressCollector::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, - uintptr_t freeEnd) -{ - allocator.Free(freeStart, freeEnd); - nonMoveSpaceFreeSize_ += freeEnd - freeStart; - heap_->ClearSlotsRange(current, freeStart, freeEnd); + heap_->GetSweeper()->SweepPhases(true); } uintptr_t CompressCollector::AllocateOld(size_t size) diff --git a/ecmascript/mem/compress_collector.h b/ecmascript/mem/compress_collector.h index 535a3f47a05f1a9942922a8ec2cc5bb6e114a874..8cfb405ed12ae38dd66b517404d5e390ae5bcdb3 100644 --- a/ecmascript/mem/compress_collector.h +++ b/ecmascript/mem/compress_collector.h @@ -61,7 +61,6 @@ private: os::memory::Mutex mtx_; BumpPointerAllocator fromSpaceAllocator_{}; FreeListAllocator oldSpaceAllocator_{}; - FreeListAllocator nonMovableAllocator_{}; size_t youngAndOldAliveSize_ = 0; size_t nonMoveSpaceFreeSize_ = 0; diff --git a/ecmascript/mem/concurrent_sweeper.cpp b/ecmascript/mem/concurrent_sweeper.cpp new file mode 100644 index 0000000000000000000000000000000000000000..59068857bba9055edfdbe321fee2e324ff5a5595 --- /dev/null +++ b/ecmascript/mem/concurrent_sweeper.cpp @@ -0,0 +1,247 @@ +/* + * Copyright (c) 2021 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/mem/concurrent_sweeper.h" + +#include "ecmascript/js_hclass-inl.h" +#include "ecmascript/mem/allocator-inl.h" +#include "ecmascript/mem/ecma_heap_manager.h" +#include "ecmascript/mem/free_object_list.h" +#include "ecmascript/mem/heap.h" +#include "ecmascript/platform/platform.h" + +namespace panda::ecmascript { +ConcurrentSweeper::ConcurrentSweeper(Heap *heap, bool concurrentSweep) + : heap_(heap), concurrentSweep_(concurrentSweep) +{ +} + +void ConcurrentSweeper::SweepPhases(bool compressGC) +{ + if (concurrentSweep_) { + // Add all region to region list. Ensure all task finish + trace::ScopedTrace scoped_trace("ConcurrentSweeper::SweepPhases"); + if (!compressGC) { + heap_->GetOldSpace()->EnumerateRegions([this](Region *current) { AddRegion(OLD_SPACE, current); }); + } + heap_->GetNonMovableSpace()->EnumerateRegions([this](Region *current) { AddRegion(NON_MOVABLE, current); }); + heap_->GetMachineCodeSpace()->EnumerateRegions([this](Region *current) { + AddRegion(MACHINE_CODE_SPACE, current); + }); + + // Prepare + isSweeping_ = true; + startSpaceType_ = compressGC ? NON_MOVABLE : OLD_SPACE; + for (int type = startSpaceType_; type < FREE_LIST_NUM; type++) { + auto spaceType = static_cast(type); + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(spaceType); + remainderTaskNum_[type] = FREE_LIST_NUM - startSpaceType_; + allocator.SetSweeping(true); + allocator.RebuildFreeList(); + } + + if (!compressGC) { + Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, OLD_SPACE)); + } + Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, NON_MOVABLE)); + Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, MACHINE_CODE_SPACE)); + } else { + if (!compressGC) { + SweepSpace(const_cast(heap_->GetOldSpace()), heap_->GetHeapManager()->GetOldSpaceAllocator()); + } + SweepSpace(const_cast(heap_->GetNonMovableSpace()), + heap_->GetHeapManager()->GetNonMovableSpaceAllocator()); + SweepSpace(const_cast(heap_->GetMachineCodeSpace()), + heap_->GetHeapManager()->GetMachineCodeSpaceAllocator()); + } + SweepHugeSpace(); +} + +void ConcurrentSweeper::SweepSpace(MemSpaceType type, bool isMain) +{ + trace::ScopedTrace scoped_trace("Sweeper::SweepSpace"); + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type); + Region *current = GetRegionSafe(type); + while (current != nullptr) { + FreeRegion(current, allocator, isMain); + // Main thread sweeping region is added; + if (!isMain) { + AddSweptRegionSafe(type, current); + } + current = GetRegionSafe(type); + } + + if (!isMain) { + os::memory::LockHolder holder(mutexs_[type]); + remainderTaskNum_[type]--; + if (remainderTaskNum_[type] == 0) { + cvs_[type].SignalAll(); + } + } +} + +void ConcurrentSweeper::SweepSpace(Space *space, FreeListAllocator &allocator) +{ + allocator.RebuildFreeList(); + space->EnumerateRegions([this, &allocator](Region *current) { FreeRegion(current, allocator); }); +} + +void ConcurrentSweeper::SweepHugeSpace() +{ + trace::ScopedTrace scoped_trace("SweepSpace HugeObject"); + HugeObjectSpace *space = const_cast(heap_->GetHugeObjectSpace()); + Region *currentRegion = space->GetRegionList().GetFirst(); + + while (currentRegion != nullptr) { + Region *next = currentRegion->GetNext(); + auto markBitmap = currentRegion->GetMarkBitmap(); + bool isMarked = false; + markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; }); + if (!isMarked) { + space->GetRegionList().RemoveNode(currentRegion); + space->ClearAndFreeRegion(currentRegion); + } + currentRegion = next; + } +} + +void ConcurrentSweeper::FreeRegion(Region *current, FreeListAllocator &allocator, bool isMain) +{ + auto markBitmap = current->GetMarkBitmap(); + ASSERT(markBitmap != nullptr); + uintptr_t freeStart = current->GetBegin(); + markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator, isMain](void *mem) { + ASSERT(current->InRange(ToUintPtr(mem))); + auto header = reinterpret_cast(mem); + auto klass = header->GetClass(); + JSType jsType = klass->GetObjectType(); + auto size = klass->SizeFromJSHClass(jsType, header); + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + + uintptr_t freeEnd = ToUintPtr(mem); + if (freeStart != freeEnd) { + FreeLiveRange(allocator, current, freeStart, freeEnd, isMain); + } + freeStart = freeEnd + size; + }); + uintptr_t freeEnd = current->GetEnd(); + if (freeStart != freeEnd) { + FreeLiveRange(allocator, current, freeStart, freeEnd, isMain); + } +} + +void ConcurrentSweeper::FillSweptRegion(MemSpaceType type) +{ + trace::ScopedTrace scoped_trace("Sweeper::FillSweptRegion"); + if (sweptList_[type].empty()) { + return; + } + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type); + Region *region = nullptr; + while ((region = GetSweptRegionSafe(type)) != nullptr) { + region->EnumerateKinds([&allocator](FreeObjectKind *kind) { + if (kind == nullptr || kind->Empty()) { + return; + } + allocator.FillFreeList(kind); + }); + } +} + +void ConcurrentSweeper::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, + uintptr_t freeEnd, bool isMain) +{ + allocator.Free(freeStart, freeEnd, isMain); + heap_->ClearSlotsRange(current, freeStart, freeEnd); +} + +void ConcurrentSweeper::AddRegion(MemSpaceType type, Region *region) +{ + sweepingList_[type].emplace_back(region); +} + +Region *ConcurrentSweeper::GetRegionSafe(MemSpaceType type) +{ + os::memory::LockHolder holder(mutexs_[type]); + Region *region = nullptr; + if (!sweepingList_[type].empty()) { + region = sweepingList_[type].back(); + sweepingList_[type].pop_back(); + } + return region; +} + +void ConcurrentSweeper::AddSweptRegionSafe(MemSpaceType type, Region *region) +{ + os::memory::LockHolder holder(mutexs_[type]); + sweptList_[type].emplace_back(region); +} + +Region *ConcurrentSweeper::GetSweptRegionSafe(MemSpaceType type) +{ + os::memory::LockHolder holder(mutexs_[type]); + Region *region = nullptr; + if (!sweptList_[type].empty()) { + region = sweptList_[type].back(); + sweptList_[type].pop_back(); + } + return region; +} + +void ConcurrentSweeper::EnsureAllTaskFinish() +{ + if (!isSweeping_) { + return; + } + for (int i = startSpaceType_; i < FREE_LIST_NUM; i++) { + WaitingTaskFinish(static_cast(i)); + } + isSweeping_ = false; +} + +void ConcurrentSweeper::WaitingTaskFinish(MemSpaceType type) +{ + if (remainderTaskNum_[type] > 0) { + SweepSpace(type); + { + os::memory::LockHolder holder(mutexs_[type]); + while (remainderTaskNum_[type] > 0) { + cvs_[type].Wait(&mutexs_[type]); + } + } + } + FinishSweeping(type); +} + +void ConcurrentSweeper::FinishSweeping(MemSpaceType type) +{ + FillSweptRegion(type); + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type); + allocator.SetSweeping(false); + if (type == OLD_SPACE) { + heap_->RecomputeLimits(); + } +} + +bool ConcurrentSweeper::SweeperTask::Run() +{ + int sweepTypeNum = FREE_LIST_NUM - sweeper_->startSpaceType_; + for (size_t i = sweeper_->startSpaceType_; i < FREE_LIST_NUM; i++) { + auto type = static_cast(((i + type_) % sweepTypeNum) + sweeper_->startSpaceType_); + sweeper_->SweepSpace(type, false); + } + return true; +} +} // namespace panda::ecmascript diff --git a/ecmascript/mem/concurrent_sweeper.h b/ecmascript/mem/concurrent_sweeper.h new file mode 100644 index 0000000000000000000000000000000000000000..b24b5a65f5e21ddb40d65bcafeef5706c90bcc48 --- /dev/null +++ b/ecmascript/mem/concurrent_sweeper.h @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2021 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_MEM_CONCURRENT_SWEEPER_H +#define ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H + +#include +#include + +#include "ecmascript/mem/space.h" +#include "ecmascript/platform/task.h" +#include "os/mutex.h" + +namespace panda::ecmascript { +class FreeListAllocator; + +class ConcurrentSweeper { +public: + ConcurrentSweeper(Heap *heap, bool concurrentSweep); + ~ConcurrentSweeper() = default; + + NO_COPY_SEMANTIC(ConcurrentSweeper); + NO_MOVE_SEMANTIC(ConcurrentSweeper); + + void SweepPhases(bool compressGC = false); + + void EnsureAllTaskFinish(); + // Ensure task finish + void WaitingTaskFinish(MemSpaceType type); + + void FillSweptRegion(MemSpaceType type); + + bool IsConcurrentSweepEnabled() + { + return concurrentSweep_; + } + +private: + class SweeperTask : public Task { + public: + SweeperTask(ConcurrentSweeper *sweeper, MemSpaceType type) : sweeper_(sweeper), type_(type) {}; + ~SweeperTask() override = default; + bool Run() override; + + NO_COPY_SEMANTIC(SweeperTask); + NO_MOVE_SEMANTIC(SweeperTask); + + private: + ConcurrentSweeper *sweeper_; + MemSpaceType type_; + }; + + void SweepSpace(MemSpaceType type, bool isMain = true); + void SweepSpace(Space *space, FreeListAllocator &allocator); + void SweepHugeSpace(); + void FinishSweeping(MemSpaceType type); + + void FreeRegion(Region *current, FreeListAllocator &allocator, bool isMain = true); + void FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, uintptr_t freeEnd, + bool isMain); + + void AddRegion(MemSpaceType type, Region *region); + Region *GetRegionSafe(MemSpaceType type); + + void AddSweptRegionSafe(MemSpaceType type, Region *region); + Region *GetSweptRegionSafe(MemSpaceType type); + + std::array mutexs_; + std::array cvs_; + std::array remainderTaskNum_ = {0, 0, 0}; + + std::array, FREE_LIST_NUM> sweepingList_; + std::array, FREE_LIST_NUM> sweptList_; + + Heap *heap_; + bool concurrentSweep_ = false; + bool isSweeping_ = false; + MemSpaceType startSpaceType_ = MemSpaceType::OLD_SPACE; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H diff --git a/ecmascript/mem/ecma_heap_manager-inl.h b/ecmascript/mem/ecma_heap_manager-inl.h index 4b65d6c33767a955b2ca0a60e62c019c37e0d961..8b9f0e146b9b9784bfcd1ec0a351bef472ae806f 100644 --- a/ecmascript/mem/ecma_heap_manager-inl.h +++ b/ecmascript/mem/ecma_heap_manager-inl.h @@ -83,18 +83,18 @@ TaggedObject *EcmaHeapManager::AllocateNonMovableOrHugeObject(JSHClass *hclass, if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { return AllocateHugeObject(hclass, size); } - auto object = reinterpret_cast(nonMovableAllocator_.Allocate(size)); + auto object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { if (heap_->CheckAndTriggerNonMovableGC()) { - object = reinterpret_cast(nonMovableAllocator_.Allocate(size)); + object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size)); } if (UNLIKELY(object == nullptr)) { // hclass must be nonmovable - if (!heap_->FillNonMovableSpaceAndTryGC(&nonMovableAllocator_)) { + if (!heap_->FillNonMovableSpaceAndTryGC(&GetNonMovableSpaceAllocator())) { LOG_ECMA_MEM(FATAL) << "OOM : extend failed"; UNREACHABLE(); } - object = reinterpret_cast(nonMovableAllocator_.Allocate(size)); + object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { heap_->ThrowOutOfMemoryError(size); UNREACHABLE(); @@ -140,18 +140,18 @@ TaggedObject *EcmaHeapManager::AllocateOldGenerationOrHugeObject(JSHClass *hclas if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { return AllocateHugeObject(hclass, size); } - auto object = reinterpret_cast(oldSpaceAllocator_.Allocate(size)); + auto object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { if (heap_->CheckAndTriggerOldGC()) { - object = reinterpret_cast(oldSpaceAllocator_.Allocate(size)); + object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size)); } if (UNLIKELY(object == nullptr)) { // hclass must nonmovable - if (!heap_->FillOldSpaceAndTryGC(&oldSpaceAllocator_)) { + if (!heap_->FillOldSpaceAndTryGC(&GetOldSpaceAllocator())) { LOG_ECMA_MEM(FATAL) << "OOM : extend failed"; UNREACHABLE(); } - object = reinterpret_cast(oldSpaceAllocator_.Allocate(size)); + object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { heap_->ThrowOutOfMemoryError(size); UNREACHABLE(); @@ -186,12 +186,12 @@ TaggedObject *EcmaHeapManager::AllocateHugeObject(JSHClass *hclass, size_t size) TaggedObject *EcmaHeapManager::AllocateMachineCodeSpaceObject(JSHClass *hclass, size_t size) { - auto object = reinterpret_cast(machineCodeSpaceAllocator_.Allocate(size)); + auto object = reinterpret_cast(GetMachineCodeSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { - if (!heap_->FillMachineCodeSpaceAndTryGC(&machineCodeSpaceAllocator_)) { + if (!heap_->FillMachineCodeSpaceAndTryGC(&GetMachineCodeSpaceAllocator())) { return nullptr; } - object = reinterpret_cast(machineCodeSpaceAllocator_.Allocate(size)); + object = reinterpret_cast(GetMachineCodeSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { heap_->ThrowOutOfMemoryError(size); return nullptr; diff --git a/ecmascript/mem/ecma_heap_manager.cpp b/ecmascript/mem/ecma_heap_manager.cpp index ea3d0b982696759e6cf968acb841bb36268aec9f..43148826728a9e35ce159758e9eb85aca02962b3 100644 --- a/ecmascript/mem/ecma_heap_manager.cpp +++ b/ecmascript/mem/ecma_heap_manager.cpp @@ -20,9 +20,8 @@ namespace panda::ecmascript { EcmaHeapManager::EcmaHeapManager(Heap *heap) : heap_(heap), newSpaceAllocator_(heap->GetNewSpace()), - nonMovableAllocator_(heap->GetNonMovableSpace()), - oldSpaceAllocator_(heap->GetOldSpace()), - machineCodeSpaceAllocator_(heap->GetMachineCodeSpace()) + freeListAllocator_ { FreeListAllocator(heap->GetOldSpace()), FreeListAllocator(heap_->GetNonMovableSpace()), + FreeListAllocator(heap->GetMachineCodeSpace()) } { ASSERT(heap != nullptr); heap->SetHeapManager(this); diff --git a/ecmascript/mem/ecma_heap_manager.h b/ecmascript/mem/ecma_heap_manager.h index 6bfd120149acc41d73eeeccef3f94f125b9fcfb2..82ec7bc71d7a14cf1e2c6ceadc288ecc5ee7963e 100644 --- a/ecmascript/mem/ecma_heap_manager.h +++ b/ecmascript/mem/ecma_heap_manager.h @@ -48,9 +48,14 @@ public: return heap_; } - FreeListAllocator &GetOldSpaceAllocator() + FreeListAllocator &GetFreeListAllocator(MemSpaceType type) { - return oldSpaceAllocator_; + return freeListAllocator_[type]; + } + + inline FreeListAllocator &GetOldSpaceAllocator() + { + return freeListAllocator_[OLD_SPACE]; } BumpPointerAllocator &GetNewSpaceAllocator() @@ -58,9 +63,9 @@ public: return newSpaceAllocator_; } - FreeListAllocator &GetNonMovableSpaceAllocator() + inline FreeListAllocator &GetNonMovableSpaceAllocator() { - return nonMovableAllocator_; + return freeListAllocator_[NON_MOVABLE]; } const BumpPointerAllocator &GetSnapShotSpaceAllocator() const @@ -68,18 +73,16 @@ public: return snapshotSpaceAllocator_; } - FreeListAllocator &GetMachineCodeSpaceAllocator() + inline FreeListAllocator &GetMachineCodeSpaceAllocator() { - return machineCodeSpaceAllocator_; + return freeListAllocator_[MACHINE_CODE_SPACE]; } private: Heap *heap_{nullptr}; BumpPointerAllocator newSpaceAllocator_; - FreeListAllocator nonMovableAllocator_; - FreeListAllocator oldSpaceAllocator_; + std::array freeListAllocator_; BumpPointerAllocator snapshotSpaceAllocator_; - FreeListAllocator machineCodeSpaceAllocator_; }; } // namespace panda::ecmascript diff --git a/ecmascript/mem/free_object_kind.cpp b/ecmascript/mem/free_object_kind.cpp index 951871f25276b489301f68b343c81a5cb7d650c0..94829d653a0a83d7dd4a93bf0dcad83f9ac7c791 100644 --- a/ecmascript/mem/free_object_kind.cpp +++ b/ecmascript/mem/free_object_kind.cpp @@ -31,6 +31,9 @@ void FreeObjectKind::Rebuild() { freeObject_ = nullptr; available_ = 0; + isAdded_ = false; + next_ = nullptr; + prev_ = nullptr; } FreeObject *FreeObjectKind::SearchSmallFreeObject(size_t size) diff --git a/ecmascript/mem/free_object_kind.h b/ecmascript/mem/free_object_kind.h index 869689c5fb87a2e109e96d34b1f1ce770dadb99d..057968a16d1ed4c98c9b5cb1941c33b0fb766859 100644 --- a/ecmascript/mem/free_object_kind.h +++ b/ecmascript/mem/free_object_kind.h @@ -27,9 +27,9 @@ class FreeObject; class FreeObjectKind { public: - FreeObjectKind(KindType type, uintptr_t begin, size_t size) : kindType_(type) + FreeObjectKind(KindType type) : kindType_(type) { - Free(begin, size); + Rebuild(); } ~FreeObjectKind() = default; @@ -60,6 +60,7 @@ private: FreeObjectKind *prev_ = nullptr; KindType kindType_ = INVALID_KIND_TYPE; size_t available_ = 0; + bool isAdded_ = false; FreeObject *freeObject_ = nullptr; friend class FreeObjectList; diff --git a/ecmascript/mem/free_object_list.cpp b/ecmascript/mem/free_object_list.cpp index 43e220f78e4fa0f7dc54117e286f06528e31be06..e25e2880a71744d243efc8fdf1de0642254d6f39 100644 --- a/ecmascript/mem/free_object_list.cpp +++ b/ecmascript/mem/free_object_list.cpp @@ -20,17 +20,16 @@ #include "ecmascript/mem/mem.h" namespace panda::ecmascript { -FreeObjectList::FreeObjectList() +FreeObjectList::FreeObjectList() : kinds_(new FreeObjectKind *[NUMBER_OF_KINDS](), NUMBER_OF_KINDS) { - kinds_ = Span(new FreeObjectKind *[NUMBER_OF_KINDS](), NUMBER_OF_KINDS); + for (int i = 0; i < NUMBER_OF_KINDS; i++) { + kinds_[i] = nullptr; + } noneEmptyKindBitMap_ = 0; } FreeObjectList::~FreeObjectList() { - for (auto it : kinds_) { - delete it; - } delete[] kinds_.data(); noneEmptyKindBitMap_ = 0; } @@ -49,33 +48,39 @@ FreeObject *FreeObjectList::Allocator(size_t size) KindType lastType = type - 1; for (type = CalcNextNoneEmptyIndex(type); type > lastType && type < NUMBER_OF_KINDS; - type = CalcNextNoneEmptyIndex(type + 1)) { + type = CalcNextNoneEmptyIndex(type + 1)) { lastType = type; - FreeObjectKind *top = kinds_[type]; - if (top == nullptr || top->Available() < size) { - continue; - } - FreeObject *current = nullptr; - if (type <= SMALL_KIND_MAX_INDEX) { - current = top->SearchSmallFreeObject(size); - } else { - current = top->SearchLargeFreeObject(size); - } - if (top->Empty()) { - RemoveKind(top); - } - if (current != nullptr) { - size_t currentSize = current->Available(); - available_ -= currentSize; - if (currentSize >= size) { - return current; + FreeObjectKind *current = kinds_[type]; + while (current != nullptr) { + if (current->Available() < size) { + current = current->next_; + continue; } + FreeObjectKind *next = nullptr; + FreeObject *object = nullptr; + if (type <= SMALL_KIND_MAX_INDEX) { + object = current->SearchSmallFreeObject(size); + } else { + next = current->next_; + object = current->SearchLargeFreeObject(size); + } + if (current->Empty()) { + RemoveKind(current); + } + if (object != nullptr) { + size_t objectSize = object->Available(); + available_ -= objectSize; + if (objectSize >= size) { + return object; + } + } + current = next; } } return nullptr; } -void FreeObjectList::Free(uintptr_t start, size_t size) +void FreeObjectList::Free(uintptr_t start, size_t size, bool isAdd) { if (start == 0 || size == 0) { return; @@ -86,26 +91,28 @@ void FreeObjectList::Free(uintptr_t start, size_t size) return; } - auto kind = kinds_[type]; + Region *region = Region::ObjectAddressToRange(reinterpret_cast(start)); + auto kind = region->GetFreeObjectKind(type); if (kind == nullptr) { - kind = new FreeObjectKind(type, start, size); - if (!AddKind(kind)) { - delete kind; - return; + LOG_ECMA(FATAL) << "The kind of region is nullptr"; + return; + } + kind->Free(start, size); + + if (isAdd) { + if (kind->isAdded_) { + available_ += size; + } else { + AddKind(kind); } - } else { - kind->Free(start, size); } - available_ += size; } void FreeObjectList::Rebuild() { - for (auto kind : kinds_) { - if (kind != nullptr) { - kind->Rebuild(); - RemoveKind(kind); - } + EnumerateKinds([](FreeObjectKind *kind) { kind->Rebuild(); }); + for (int i = 0; i < NUMBER_OF_KINDS; i++) { + kinds_[i] = nullptr; } available_ = 0; noneEmptyKindBitMap_ = 0; @@ -118,20 +125,22 @@ size_t FreeObjectList::GetFreeObjectSize() const bool FreeObjectList::AddKind(FreeObjectKind *kind) { - if (kind == nullptr || kind->Empty()) { + if (kind == nullptr || kind->Empty() || kind->isAdded_) { return false; } KindType type = kind->kindType_; FreeObjectKind *top = kinds_[type]; if (kind == top) { - return true; + return false; } if (top != nullptr) { top->prev_ = kind; } + kind->isAdded_ = true; kind->next_ = top; kinds_[type] = kind; SetNoneEmptyBit(type); + available_ += kind->Available(); return true; } @@ -151,11 +160,30 @@ void FreeObjectList::RemoveKind(FreeObjectKind *kind) if (kind->next_ != nullptr) { kind->next_->prev_ = kind->prev_; } - kind->prev_ = nullptr; - kind->next_ = nullptr; if (kinds_[type] == nullptr) { ClearNoneEmptyBit(type); } - delete kind; + available_ -= kind->Available(); + kind->Rebuild(); +} + +template +void FreeObjectList::EnumerateKinds(const Callback &cb) const +{ + for (KindType i = 0; i < NUMBER_OF_KINDS; i++) { + EnumerateKinds(i, cb); + } +} + +template +void FreeObjectList::EnumerateKinds(KindType type, const Callback &cb) const +{ + FreeObjectKind *current = kinds_[type]; + while (current != nullptr) { + // maybe reset + FreeObjectKind *next = current->next_; + cb(current); + current = next; + } } } // namespace panda::ecmascript diff --git a/ecmascript/mem/free_object_list.h b/ecmascript/mem/free_object_list.h index c7db11126e86734ad79e2ac5cedcfa0837b2f150..553dd5d4c4722e867e9e033faffc63b710b86022 100644 --- a/ecmascript/mem/free_object_list.h +++ b/ecmascript/mem/free_object_list.h @@ -29,15 +29,30 @@ public: FreeObject *Allocator(size_t size); - void Free(uintptr_t start, size_t size); + void Free(uintptr_t start, size_t size, bool isAdd = true); void Rebuild(); + bool AddKind(FreeObjectKind *kind); + + void RemoveKind(FreeObjectKind *kind); + + template + void EnumerateKinds(const Callback &cb) const; + + template + void EnumerateKinds(KindType type, const Callback &cb) const; + NO_COPY_SEMANTIC(FreeObjectList); NO_MOVE_SEMANTIC(FreeObjectList); size_t GetFreeObjectSize() const; + static int NumberOfKinds() + { + return NUMBER_OF_KINDS; + } + private: static constexpr int NUMBER_OF_KINDS = 39; static constexpr size_t MIN_SIZE = 16; @@ -58,9 +73,6 @@ private: inline void ClearNoneEmptyBit(KindType type); inline size_t CalcNextNoneEmptyIndex(KindType start); - bool AddKind(FreeObjectKind *kind); - void RemoveKind(FreeObjectKind *kind); - size_t available_ = 0; uint64_t noneEmptyKindBitMap_; Span kinds_ {}; diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index 61aba40a8b2ae6d2c76e280ddf0ad80c42dda48f..76bfc94b4c6795ef08d2fa696bb6e4e049d1d9bf 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -20,6 +20,7 @@ #include "ecmascript/ecma_vm.h" #include "ecmascript/mem/assert_scope-inl.h" #include "ecmascript/mem/compress_collector.h" +#include "ecmascript/mem/concurrent_sweeper.h" #include "ecmascript/mem/ecma_heap_manager.h" #include "ecmascript/mem/mark_stack.h" #include "ecmascript/mem/mem_controller.h" @@ -54,8 +55,6 @@ void Heap::Initialize() machineCodeSpace_ = new MachineCodeSpace(this); machineCodeSpace_->Initialize(); hugeObjectSpace_ = new HugeObjectSpace(this); - markStack_ = new MarkStack(this); - weakProcessQueue_ = new ProcessQueue(this); bool paralledGc = ecmaVm_->GetOptions().IsEnableParalledYoungGc(); if (paralledGc) { int numOfCpuCore = get_nprocs(); @@ -63,12 +62,15 @@ void Heap::Initialize() pool_ = new ThreadPool(numThread); semiSpaceCollector_ = new SemiSpaceCollector(this, true); compressCollector_ = new CompressCollector(this, true); + oldSpaceCollector_ = new OldSpaceCollector(this, true); } else { pool_ = new ThreadPool(1); semiSpaceCollector_ = new SemiSpaceCollector(this, false); compressCollector_ = new CompressCollector(this, false); + oldSpaceCollector_ = new OldSpaceCollector(this, false); } - oldSpaceCollector_ = new OldSpaceCollector(this); + // After EcmaOptions merged, it will modified to EcmaOptions configuration + sweeper_ = new ConcurrentSweeper(this, true); } void Heap::FlipNewSpace() @@ -87,6 +89,7 @@ void Heap::FlipCompressSpace() void Heap::Destroy() { pool_->WaitTaskFinish(); + sweeper_->EnsureAllTaskFinish(); toSpace_->Destroy(); delete toSpace_; toSpace_ = nullptr; @@ -109,16 +112,10 @@ void Heap::Destroy() machineCodeSpace_->Destroy(); delete machineCodeSpace_; machineCodeSpace_ = nullptr; - markStack_->Destroy(); - delete markStack_; - markStack_ = nullptr; hugeObjectSpace_->Destroy(); delete hugeObjectSpace_; hugeObjectSpace_ = nullptr; - weakProcessQueue_->Destroy(); - delete weakProcessQueue_; - weakProcessQueue_ = nullptr; delete semiSpaceCollector_; semiSpaceCollector_ = nullptr; delete oldSpaceCollector_; @@ -130,6 +127,8 @@ void Heap::Destroy() memController_ = nullptr; delete pool_; pool_ = nullptr; + delete sweeper_; + sweeper_ = nullptr; } void Heap::CollectGarbage(TriggerGCType gcType) @@ -138,6 +137,7 @@ void Heap::CollectGarbage(TriggerGCType gcType) // pre gc heap verify { if (ecmaVm_->GetOptions().IsPreGcHeapVerifyEnabled()) { + sweeper_->EnsureAllTaskFinish(); auto failCount = Verification(this).VerifyAll(); if (failCount > 0) { LOG(FATAL, GC) << "Before gc heap corrupted and " << failCount << " corruptions"; @@ -158,18 +158,18 @@ void Heap::CollectGarbage(TriggerGCType gcType) } break; case TriggerGCType::OLD_GC: - if (oldSpace_->GetHeapObjectSize() < OLD_SPACE_LIMIT_BEGIN) { - oldSpaceCollector_->RunPhases(); - } else { - compressCollector_->RunPhases(); + oldSpaceCollector_->RunPhases(); + if (!sweeper_->IsConcurrentSweepEnabled()) { + RecomputeLimits(); } - RecomputeLimits(); break; case TriggerGCType::NON_MOVE_GC: case TriggerGCType::HUGE_GC: case TriggerGCType::MACHINE_CODE_GC: oldSpaceCollector_->RunPhases(); - RecomputeLimits(); + if (!sweeper_->IsConcurrentSweepEnabled()) { + RecomputeLimits(); + } break; case TriggerGCType::COMPRESS_FULL_GC: compressCollector_->RunPhases(); @@ -183,6 +183,7 @@ void Heap::CollectGarbage(TriggerGCType gcType) // post gc heap verify { if (ecmaVm_->GetOptions().IsPreGcHeapVerifyEnabled()) { + sweeper_->EnsureAllTaskFinish(); auto failCount = Verification(this).VerifyAll(); if (failCount > 0) { LOG(FATAL, GC) << "After gc heap corrupted and " << failCount << " corruptions"; diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index bc112f2f877b7714dab00ce70cf545c5d8276cb2..55ce680c727044f1837cd06f9c3069a9571491b8 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -31,6 +31,7 @@ class FreeListAllocator; class RegionFactory; class HeapTracker; class MemController; +class ConcurrentSweeper; class Heap { public: @@ -93,16 +94,6 @@ public: return machineCodeSpace_; } - MarkStack *GetMarkStack() const - { - return markStack_; - } - - ProcessQueue *GetProcessQueue() const - { - return weakProcessQueue_; - } - SemiSpaceCollector *GetSemiSpaceCollector() const { return semiSpaceCollector_; @@ -118,6 +109,11 @@ public: return compressCollector_; } + ConcurrentSweeper *GetSweeper() const + { + return sweeper_; + } + EcmaVM *GetEcmaVM() const { return ecmaVm_; @@ -271,11 +267,10 @@ private: SnapShotSpace *snapshotSpace_ {nullptr}; NonMovableSpace *nonMovableSpace_ {nullptr}; MachineCodeSpace *machineCodeSpace_ {nullptr}; - MarkStack *markStack_ {nullptr}; - ProcessQueue *weakProcessQueue_ {nullptr}; SemiSpaceCollector *semiSpaceCollector_ {nullptr}; OldSpaceCollector *oldSpaceCollector_ {nullptr}; CompressCollector *compressCollector_ {nullptr}; + ConcurrentSweeper *sweeper_ {nullptr}; EcmaHeapManager *heapManager_ {nullptr}; RegionFactory *regionFactory_ {nullptr}; HeapTracker *tracker_ {nullptr}; diff --git a/ecmascript/mem/heap_roots-inl.h b/ecmascript/mem/heap_roots-inl.h index e05ed383b470743aea354038745ac5ebdcdabced..ec2769bf5d157589f089bd6f6dd0820303ab3a54 100644 --- a/ecmascript/mem/heap_roots-inl.h +++ b/ecmascript/mem/heap_roots-inl.h @@ -30,6 +30,7 @@ #include "ecmascript/js_array_iterator.h" #include "ecmascript/js_arraybuffer.h" #include "ecmascript/js_async_function.h" +#include "ecmascript/js_collator.h" #include "ecmascript/js_dataview.h" #include "ecmascript/js_date.h" #include "ecmascript/js_date_time_format.h" @@ -41,11 +42,12 @@ #include "ecmascript/js_locale.h" #include "ecmascript/js_map.h" #include "ecmascript/js_map_iterator.h" -#include "ecmascript/js_native_object.h" #include "ecmascript/js_number_format.h" #include "ecmascript/js_object-inl.h" +#include "ecmascript/js_plural_rules.h" #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_promise.h" +#include "ecmascript/js_realm.h" #include "ecmascript/js_regexp.h" #include "ecmascript/js_relative_time_format.h" #include "ecmascript/js_set.h" @@ -54,6 +56,7 @@ #include "ecmascript/js_typed_array.h" #include "ecmascript/js_weak_container.h" #include "ecmascript/mem/heap_roots.h" +#include "ecmascript/mem/machine_code.h" #include "ecmascript/mem/mem.h" namespace panda::ecmascript { @@ -197,6 +200,7 @@ void HeapRootManager::MarkObjectBody(TaggedObject *object, JSHClass *klass, cons break; case JSType::TAGGED_ARRAY: case JSType::TAGGED_DICTIONARY: + case JSType::TEMPLATE_MAP: TaggedArray::Cast(object)->VisitRangeSlot(visitor); break; case JSType::GLOBAL_ENV: @@ -226,9 +230,6 @@ void HeapRootManager::MarkObjectBody(TaggedObject *object, JSHClass *klass, cons case JSType::PROTOTYPE_INFO: ProtoChangeDetails::Cast(object)->VisitRangeSlot(visitor); break; - case JSType::TEMPLATE_MAP: - UNREACHABLE(); - break; case JSType::PROMISE_CAPABILITY: PromiseCapability::Cast(object)->VisitRangeSlot(visitor); break; @@ -283,8 +284,17 @@ void HeapRootManager::MarkObjectBody(TaggedObject *object, JSHClass *klass, cons case JSType::JS_INTL_BOUND_FUNCTION: JSIntlBoundFunction::Cast(object)->VisitRangeSlot(visitor); break; - case JSType::JS_NATIVE_OBJECT: - JSNativeObject::Cast(object)->VisitRangeSlot(visitor); + case JSType::JS_REALM: + JSRealm::Cast(object)->VisitRangeSlot(visitor); + break; + case JSType::JS_COLLATOR: + JSCollator::Cast(object)->VisitRangeSlot(visitor); + break; + case JSType::JS_PLURAL_RULES: + JSPluralRules::Cast(object)->VisitRangeSlot(visitor); + break; + case JSType::MACHINE_CODE_OBJECT: + MachineCode::Cast(object)->VisitRangeSlot(visitor); break; default: UNREACHABLE(); diff --git a/ecmascript/mem/machine_code.h b/ecmascript/mem/machine_code.h index 6cfca754fe576599b6e7ec0854a91d59a26464ac..ad4217cd263effb7f1ab3631fbc247a486fc2c4c 100644 --- a/ecmascript/mem/machine_code.h +++ b/ecmascript/mem/machine_code.h @@ -24,8 +24,6 @@ namespace panda { namespace ecmascript { class MachineCode : public TaggedObject { public: - MachineCode(); - ~MachineCode(); NO_COPY_SEMANTIC(MachineCode); NO_MOVE_SEMANTIC(MachineCode); static MachineCode *Cast(ObjectHeader *object) @@ -36,28 +34,41 @@ public: static constexpr size_t INS_SIZE_OFFSET = TaggedObjectSize(); ACCESSORS(InstructionSizeInBytes, INS_SIZE_OFFSET, DATA_OFFSET); + static constexpr size_t SIZE = DATA_OFFSET; + + DECL_DUMP() uintptr_t GetDataOffsetAddress(void) { - return reinterpret_cast(this + DATA_OFFSET); + return reinterpret_cast(this) + DATA_OFFSET; } - void SetData(const uint8_t *codeData, size_t codeLength) + void SetData(const uint8_t *stackMapData, size_t codeLength) { - if (codeData == nullptr) { + if (stackMapData == nullptr) { LOG_ECMA_MEM(ERROR) << "data is null in creating new code object"; return; } if (memcpy_s(reinterpret_cast(this->GetDataOffsetAddress()), - this->GetInstructionSizeInBytes().GetInt(), codeData, codeLength) != EOK) { + this->GetInstructionSizeInBytes().GetInt(), stackMapData, codeLength) != EOK) { LOG_ECMA_MEM(ERROR) << "memcpy fail in creating new code object "; return; } } + void VisitRangeSlot(const EcmaObjectRangeVisitor &v) + { + // left blank deliberately,only need to visit TaggedObject type object. + } + + void VisitObjects([[maybe_unused]] const EcmaObjectRangeVisitor &visitor) const + { + // left blank deliberately,only need to visit TaggedObject type object. + } + size_t GetMachineCodeObjectSize(void) { - return sizeof(MachineCode) + this->GetInstructionSizeInBytes().GetInt(); + return SIZE + this->GetInstructionSizeInBytes().GetInt(); } }; } // namespace ecmascript diff --git a/ecmascript/mem/old_space_collector-inl.h b/ecmascript/mem/old_space_collector-inl.h index a8f88de5598d382c9d9a2786cbff2bc571958915..b6c82b7de0e0d473aadb33c7df1c561d6ca9b436 100644 --- a/ecmascript/mem/old_space_collector-inl.h +++ b/ecmascript/mem/old_space_collector-inl.h @@ -24,31 +24,19 @@ #include "ecmascript/js_hclass-inl.h" namespace panda::ecmascript { -void OldSpaceCollector::MarkObject(TaggedObject *object) +void OldSpaceCollector::MarkObject(uint64_t threadId, TaggedObject *object) { Region *objectRegion = Region::ObjectAddressToRange(object); auto markBitmap = objectRegion->GetMarkBitmap(); - if (!markBitmap->Test(object)) { - markBitmap->Set(object); - markStack_.PushBack(object); + if (!markBitmap->AtomicTestAndSet(object)) { + workList_->Push(threadId, object); } } -void OldSpaceCollector::RecordWeakReference(JSTaggedType *ref) +void OldSpaceCollector::RecordWeakReference(uint64_t threadId, JSTaggedType *ref) { - Region *objectRegion = Region::ObjectAddressToRange(reinterpret_cast(ref)); - if (!objectRegion->InYoungGeneration()) { - weakProcessQueue_.PushBack(ref); - } -} - -void OldSpaceCollector::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, - uintptr_t freeEnd) -{ - allocator.Free(freeStart, freeEnd); - freeSize_ += freeEnd - freeStart; - heap_->ClearSlotsRange(current, freeStart, freeEnd); + workList_->PushWeakReference(threadId, ref); } } // namespace panda::ecmascript diff --git a/ecmascript/mem/old_space_collector.cpp b/ecmascript/mem/old_space_collector.cpp index 3572760030bc5a72f1440173fb54d5204987a955..343f7c7e037395b1334360e5f3ab4c75505c1821 100644 --- a/ecmascript/mem/old_space_collector.cpp +++ b/ecmascript/mem/old_space_collector.cpp @@ -27,7 +27,11 @@ #include "ecmascript/vmstat/runtime_stat.h" namespace panda::ecmascript { -OldSpaceCollector::OldSpaceCollector(Heap *heap) : heap_(heap), rootManager_(heap->GetEcmaVM()) {} +OldSpaceCollector::OldSpaceCollector(Heap *heap, bool parallelGc) + : heap_(heap), rootManager_(heap->GetEcmaVM()), paralledGC_(parallelGc) +{ + workList_ = new OldGCWorker(heap_, heap_->GetThreadPool()->GetThreadNum()); +} void OldSpaceCollector::RunPhases() { @@ -45,12 +49,8 @@ void OldSpaceCollector::RunPhases() void OldSpaceCollector::InitializePhase() { - markStack_.BeginMarking(heap_, heap_->GetMarkStack()); - weakProcessQueue_.BeginMarking(heap_, heap_->GetProcessQueue()); - auto heapManager = heap_->GetHeapManager(); - oldSpaceAllocator_.Swap(heapManager->GetOldSpaceAllocator()); - nonMovableAllocator_.Swap(heapManager->GetNonMovableSpaceAllocator()); - machineCodeSpaceAllocator_.Swap(heapManager->GetMachineCodeSpaceAllocator()); + heap_->GetThreadPool()->WaitTaskFinish(); + heap_->GetSweeper()->EnsureAllTaskFinish(); heap_->EnumerateRegions([](Region *current) { // ensure mark bitmap auto bitmap = current->GetMarkBitmap(); @@ -60,6 +60,7 @@ void OldSpaceCollector::InitializePhase() bitmap->ClearAllBits(); } }); + workList_->Initialize(); freeSize_ = 0; hugeSpaceFreeSize_ = 0; oldSpaceCommitSize_ = heap_->GetOldSpace()->GetCommittedSize(); @@ -68,13 +69,8 @@ void OldSpaceCollector::InitializePhase() void OldSpaceCollector::FinishPhase() { - // swap - markStack_.FinishMarking(heap_->GetMarkStack()); - weakProcessQueue_.FinishMarking(heap_->GetProcessQueue()); - auto heapManager = heap_->GetHeapManager(); - heapManager->GetOldSpaceAllocator().Swap(oldSpaceAllocator_); - heapManager->GetNonMovableSpaceAllocator().Swap(nonMovableAllocator_); - heapManager->GetMachineCodeSpaceAllocator().Swap(machineCodeSpaceAllocator_); + size_t aliveSize = 0; + workList_->Finish(aliveSize); } void OldSpaceCollector::MarkingPhase() @@ -83,112 +79,72 @@ void OldSpaceCollector::MarkingPhase() RootVisitor gcMarkYoung = [this]([[maybe_unused]] Root type, ObjectSlot slot) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsHeapObject()) { - MarkObject(value.GetTaggedObject()); + MarkObject(0, value.GetTaggedObject()); } }; RootRangeVisitor gcMarkRangeYoung = [this]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) { for (ObjectSlot slot = start; slot < end; slot++) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsHeapObject()) { - MarkObject(value.GetTaggedObject()); + MarkObject(0, value.GetTaggedObject()); } } }; rootManager_.VisitVMRoots(gcMarkYoung, gcMarkRangeYoung); - ProcessMarkStack(); + ProcessMarkStack(0); + if (paralledGC_) { + heap_->GetThreadPool()->WaitTaskFinish(); + } } -void OldSpaceCollector::ProcessMarkStack() +void OldSpaceCollector::ProcessMarkStack(uint64_t threadId) { while (true) { - auto obj = markStack_.PopBack(); - if (UNLIKELY(obj == nullptr)) { + TaggedObject *obj = nullptr; + if (!workList_->Pop(threadId, &obj)) { break; } auto jsHclass = obj->GetClass(); // mark dynClass - MarkObject(jsHclass); + MarkObject(threadId, jsHclass); rootManager_.MarkObjectBody( - obj, jsHclass, [this]([[maybe_unused]] TaggedObject *root, ObjectSlot start, ObjectSlot end) { + obj, jsHclass, [this, &threadId]([[maybe_unused]] TaggedObject *root, ObjectSlot start, ObjectSlot end) { for (ObjectSlot slot = start; slot < end; slot++) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsWeak()) { - RecordWeakReference(reinterpret_cast(slot.SlotAddress())); + RecordWeakReference(threadId, reinterpret_cast(slot.SlotAddress())); continue; } if (value.IsHeapObject()) { - MarkObject(value.GetTaggedObject()); + MarkObject(threadId, value.GetTaggedObject()); } } }); } } -void OldSpaceCollector::SweepSpace(Space *space, FreeListAllocator &allocator) -{ - allocator.RebuildFreeList(); - space->EnumerateRegions([this, &allocator](Region *current) { - auto markBitmap = current->GetMarkBitmap(); - ASSERT(markBitmap != nullptr); - uintptr_t freeStart = current->GetBegin(); - markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator](void *mem) { - ASSERT(current->InRange(ToUintPtr(mem))); - auto header = reinterpret_cast(mem); - auto klass = header->GetClass(); - JSType jsType = klass->GetObjectType(); - auto size = klass->SizeFromJSHClass(jsType, header); - size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); - - uintptr_t freeEnd = ToUintPtr(mem); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - freeStart = freeEnd + size; - }); - uintptr_t freeEnd = current->GetEnd(); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - }); -} - -void OldSpaceCollector::SweepSpace(HugeObjectSpace *space) -{ - Region *currentRegion = space->GetRegionList().GetFirst(); - - while (currentRegion != nullptr) { - Region *next = currentRegion->GetNext(); - auto markBitmap = currentRegion->GetMarkBitmap(); - bool isMarked = false; - markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; }); - if (!isMarked) { - space->GetRegionList().RemoveNode(currentRegion); - hugeSpaceFreeSize_ += currentRegion->GetCapacity(); - space->ClearAndFreeRegion(currentRegion); - } - currentRegion = next; - } -} - void OldSpaceCollector::SweepPhases() { trace::ScopedTrace scoped_trace("OldSpaceCollector::SweepPhases"); // process weak reference - while (true) { - auto obj = weakProcessQueue_.PopBack(); - if (UNLIKELY(obj == nullptr)) { - break; - } - ObjectSlot slot(ToUintPtr(obj)); - JSTaggedValue value(slot.GetTaggedType()); - auto header = value.GetTaggedWeakRef(); + for (uint32_t i = 0; i < heap_->GetThreadPool()->GetThreadNum(); i++) { + ProcessQueue *queue = workList_->GetWeakReferenceQueue(i); + while (true) { + auto obj = queue->PopBack(); + if (UNLIKELY(obj == nullptr)) { + break; + } + ObjectSlot slot(ToUintPtr(obj)); + JSTaggedValue value(slot.GetTaggedType()); + auto header = value.GetTaggedWeakRef(); - Region *objectRegion = Region::ObjectAddressToRange(header); - auto markBitmap = objectRegion->GetMarkBitmap(); - if (!markBitmap->Test(header)) { - slot.Update(static_cast(JSTaggedValue::Undefined().GetRawData())); + Region *objectRegion = Region::ObjectAddressToRange(header); + auto markBitmap = objectRegion->GetMarkBitmap(); + if (!markBitmap->Test(header)) { + slot.Update(static_cast(JSTaggedValue::Undefined().GetRawData())); + } } } @@ -209,9 +165,6 @@ void OldSpaceCollector::SweepPhases() heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak); heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak); - SweepSpace(const_cast(heap_->GetOldSpace()), oldSpaceAllocator_); - SweepSpace(const_cast(heap_->GetNonMovableSpace()), nonMovableAllocator_); - SweepSpace(const_cast(heap_->GetHugeObjectSpace())); - SweepSpace(const_cast(heap_->GetMachineCodeSpace()), machineCodeSpaceAllocator_); + heap_->GetSweeper()->SweepPhases(); } } // namespace panda::ecmascript diff --git a/ecmascript/mem/old_space_collector.h b/ecmascript/mem/old_space_collector.h index 64940351b60214b02f4a9a2ac2d0653162e1fc07..5da8b520717d0ee6818eb10b411025da10b5c8f2 100644 --- a/ecmascript/mem/old_space_collector.h +++ b/ecmascript/mem/old_space_collector.h @@ -21,6 +21,7 @@ #include "ecmascript/mem/allocator.h" #include "ecmascript/mem/mark_stack-inl.h" #include "ecmascript/mem/mark_word.h" +#include "ecmascript/mem/semi_space_worker.h" #include "ecmascript/mem/slots.h" #include "ecmascript/mem/heap_roots.h" #include "ecmascript/mem/remembered_set.h" @@ -33,7 +34,7 @@ class JSHClass; class OldSpaceCollector : public GarbageCollector { public: - explicit OldSpaceCollector(Heap *heap); + explicit OldSpaceCollector(Heap *heap, bool parallelGc); ~OldSpaceCollector() override = default; NO_COPY_SEMANTIC(OldSpaceCollector); NO_MOVE_SEMANTIC(OldSpaceCollector); @@ -50,26 +51,22 @@ private: void SweepPhases(); void FinishPhase(); - void ProcessMarkStack(); + void ProcessMarkStack(uint64_t threadId); void MarkObjectBody(TaggedObject *object, JSHClass *klass, const EcmaObjectRangeVisitor &visitor); - inline void MarkObject(TaggedObject *object); - inline void FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, uintptr_t freeEnd); - inline void RecordWeakReference(JSTaggedType *ref); - void SweepSpace(Space *space, FreeListAllocator &allocator); - void SweepSpace(HugeObjectSpace *space); // Only sweep huge space. + inline void MarkObject(uint64_t threadId, TaggedObject *object); + inline void RecordWeakReference(uint64_t threadId, JSTaggedType *ref); Heap *heap_; HeapRootManager rootManager_; - MarkStack markStack_; - ProcessQueue weakProcessQueue_; - FreeListAllocator oldSpaceAllocator_ {}; - FreeListAllocator nonMovableAllocator_ {}; - FreeListAllocator machineCodeSpaceAllocator_ {}; + bool paralledGC_{false}; + OldGCWorker *workList_{nullptr}; size_t freeSize_{0}; size_t hugeSpaceFreeSize_ = 0; size_t oldSpaceCommitSize_ = 0; size_t nonMoveSpaceCommitSize_ = 0; + + friend class OldGCWorker; }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/mem/region.h b/ecmascript/mem/region.h index 4e541d18e504c4a85f9e65ad9727e4689e13aa1d..207abda5fdf0cab3ae03e6c2502b4cf7c979f39d 100644 --- a/ecmascript/mem/region.h +++ b/ecmascript/mem/region.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_MEM_REGION_H #define ECMASCRIPT_MEM_REGION_H +#include "ecmascript/mem/free_object_list.h" #include "ecmascript/mem/mem.h" #include "mem/gc/bitmap.h" @@ -41,9 +42,11 @@ enum RegionFlags { // NOLINTNEXTLINE(hicpp-signed-bitwise) IS_IN_OLD_GENERATION = 1 << 6, // NOLINTNEXTLINE(hicpp-signed-bitwise) + IS_IN_NON_MOVABLE_GENERATION = 1 << 7, + // NOLINTNEXTLINE(hicpp-signed-bitwise) IS_IN_YOUNG_OR_OLD_GENERATION = IS_IN_YOUNG_GENERATION | IS_IN_OLD_GENERATION, // NOLINTNEXTLINE(hicpp-signed-bitwise) - IS_INVALID = 1 << 7, + IS_INVALID = 1 << 8, }; class Region { @@ -206,6 +209,36 @@ public: return res; } + void InitializeKind() + { + kinds_ = Span(new FreeObjectKind *[FreeObjectList::NumberOfKinds()](), + FreeObjectList::NumberOfKinds()); + for (int i = 0; i < FreeObjectList::NumberOfKinds(); i++) { + kinds_[i] = new FreeObjectKind(i); + } + } + + void DestoryKind() + { + for (auto kind : kinds_) { + delete kind; + } + delete[] kinds_.data(); + } + + FreeObjectKind *GetFreeObjectKind(KindType type) + { + return kinds_[type]; + } + + template + void EnumerateKinds(Callback cb) + { + for (auto kind : kinds_) { + cb(kind); + } + } + private: Space *space_; uintptr_t flags_; // Memory alignment, only low 32bits are used now @@ -218,6 +251,7 @@ private: RangeBitmap *markBitmap_{nullptr}; RememberedSet *crossRegionSet_{nullptr}; RememberedSet *oldToNewSet_{nullptr}; + Span kinds_; friend class SnapShot; }; } // namespace ecmascript diff --git a/ecmascript/mem/semi_space_collector.cpp b/ecmascript/mem/semi_space_collector.cpp index ef6975066f4328a0f4a42b5b9701b7fd21bfccc2..0cc31fd8f1a21f1d3e0b579c66ab187d32c8464a 100644 --- a/ecmascript/mem/semi_space_collector.cpp +++ b/ecmascript/mem/semi_space_collector.cpp @@ -59,7 +59,7 @@ void SemiSpaceCollector::RunPhases() void SemiSpaceCollector::InitializePhase() { heap_->GetThreadPool()->WaitTaskFinish(); - gcTime_++; + heap_->GetSweeper()->EnsureAllTaskFinish(); auto fromSpace = heap_->GetFromSpace(); if (fromSpace->GetCommittedSize() == 0) { heap_->InitializeFromSpace(); diff --git a/ecmascript/mem/semi_space_collector.h b/ecmascript/mem/semi_space_collector.h index 6e5a31f62468b10c25ffdcd70d77bb02382042f0..3a76149e5c181dabf648422ac28ecca3f1f6721f 100644 --- a/ecmascript/mem/semi_space_collector.h +++ b/ecmascript/mem/semi_space_collector.h @@ -91,7 +91,6 @@ private: size_t semiCopiedSize_{0}; size_t commitSize_ = 0; uintptr_t ageMark_{0}; - size_t gcTime_{0}; friend class TlabAllocator; friend class SemiSpaceWorker; friend class SemiSpaceMarker; diff --git a/ecmascript/mem/semi_space_worker.cpp b/ecmascript/mem/semi_space_worker.cpp index dbaa62b62335f572f5a05d69ff4b9923a8080017..0df831f442d5bac5585cb79ecb728c8a322e6c55 100644 --- a/ecmascript/mem/semi_space_worker.cpp +++ b/ecmascript/mem/semi_space_worker.cpp @@ -19,6 +19,7 @@ #include "ecmascript/mem/compress_collector.h" #include "ecmascript/mem/heap.h" #include "ecmascript/mem/mark_stack.h" +#include "ecmascript/mem/old_space_collector.h" #include "ecmascript/mem/region_factory.h" #include "ecmascript/mem/tlab_allocator-inl.h" @@ -197,4 +198,32 @@ void CompressGCWorker::Initialize() holder.aliveSize_ = 0; } } + +void OldGCWorker::Initialize() +{ + spaceTop_ = markSpace_; + markSpaceEnd_ = markSpace_ + SPACE_SIZE; + for (uint32_t i = 0; i < threadNum_; i++) { + WorkNodeHolder &holder = workList_[i]; + holder.pushNode_ = AllocalWorkNode(); + holder.popNode_ = AllocalWorkNode(); + holder.weakQueue_ = new ProcessQueue(); + holder.weakQueue_->BeginMarking(heap_, continuousQueue_[i]); + } +} + +void OldGCWorker::PushWorkNodeToGlobal(uint32_t threadId) +{ + WorkNode *&pushNode = workList_[threadId].pushNode_; + if (!pushNode->IsEmpty()) { + globalWork_.Push(pushNode); + pushNode = AllocalWorkNode(); + + auto pool = heap_->GetThreadPool(); + if (pool->GetTaskCount() < pool->GetThreadNum() - 1) { + pool->Submit(std::bind(&OldSpaceCollector::ProcessMarkStack, heap_->GetOldSpaceCollector(), + std::placeholders::_1)); + } + } +} } // namespace panda::ecmascript diff --git a/ecmascript/mem/semi_space_worker.h b/ecmascript/mem/semi_space_worker.h index 2572c475e1e2bb830f8aac2ea3e9c2fb668d3efa..0a88f31f0e07a0bfb273c4ed5da607778a92fa37 100644 --- a/ecmascript/mem/semi_space_worker.h +++ b/ecmascript/mem/semi_space_worker.h @@ -233,6 +233,19 @@ public: NO_COPY_SEMANTIC(CompressGCWorker); NO_MOVE_SEMANTIC(CompressGCWorker); }; -} // namespace panda::ecmascript +class OldGCWorker : public Worker { +public: + OldGCWorker() = delete; + OldGCWorker(Heap *heap, uint32_t threadNum) : Worker(heap, threadNum) {} + + ~OldGCWorker() override = default; + + void PushWorkNodeToGlobal(uint32_t threadId) override; + void Initialize() override; + + NO_COPY_SEMANTIC(OldGCWorker); + NO_MOVE_SEMANTIC(OldGCWorker); +}; +} // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_SEMI_SPACE_WORKER_H diff --git a/ecmascript/mem/space.cpp b/ecmascript/mem/space.cpp index 7a665284bfcfb3637333baf8934c57b159f5dded..c1156bc0eed7de9e7972d1f5e46bb0d01ba3c77f 100644 --- a/ecmascript/mem/space.cpp +++ b/ecmascript/mem/space.cpp @@ -37,11 +37,16 @@ void Space::Initialize() } else if (spaceType_ == MemSpaceType::SNAPSHOT_SPACE) { region->SetFlag(RegionFlags::IS_IN_SNAPSHOT_GENERATION); } else if (spaceType_ == MemSpaceType::OLD_SPACE) { + region->InitializeKind(); region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION); } else if (spaceType_ == MemSpaceType::MACHINE_CODE_SPACE) { + region->InitializeKind(); region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION); int res = region->SetCodeExecutableAndReadable(); LOG_ECMA_MEM(DEBUG) << "Initialize SetCodeExecutableAndReadable" << res; + } else if (spaceType_ == MemSpaceType::NON_MOVABLE) { + region->InitializeKind(); + region->SetFlag(RegionFlags::IS_IN_NON_MOVABLE_GENERATION); } AddRegion(region); @@ -75,6 +80,11 @@ void Space::ClearAndFreeRegion(Region *region) delete rememberedSet; } DecrementCommitted(region->GetCapacity()); + if (spaceType_ == MemSpaceType::OLD_SPACE || + spaceType_ == MemSpaceType::NON_MOVABLE || + spaceType_ == MemSpaceType::MACHINE_CODE_SPACE) { + region->DestoryKind(); + } const_cast(heap_->GetRegionFactory())->FreeRegion(region); } @@ -177,6 +187,7 @@ bool OldSpace::Expand() Region *region = const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE); region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION); + region->InitializeKind(); AddRegion(region); return true; } @@ -231,8 +242,7 @@ size_t OldSpace::GetHeapObjectSize() const { size_t result; size_t availableSize = GetHeap()->GetHeapManager()->GetOldSpaceAllocator().GetAvailableSize(); - size_t regionSize = GetRegionList().GetLength() * DEFAULT_REGION_SIZE; - result = regionSize - availableSize; + result = GetCommittedSize() - availableSize; result += GetHeap()->GetHugeObjectSpace()->GetHeapObjectSize(); return result; } @@ -250,6 +260,8 @@ bool NonMovableSpace::Expand() } Region *region = const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE); + region->SetFlag(IS_IN_NON_MOVABLE_GENERATION); + region->InitializeKind(); AddRegion(region); return true; } @@ -372,6 +384,12 @@ uintptr_t HugeObjectSpace::Allocate(size_t objectSize) return region->GetBegin(); } +void HugeObjectSpace::Free(Region *region) +{ + GetRegionList().RemoveNode(region); + ClearAndFreeRegion(region); +} + bool HugeObjectSpace::ContainObject(TaggedObject *object) const { auto region = GetRegionList().GetFirst(); @@ -391,12 +409,7 @@ bool HugeObjectSpace::IsLive(TaggedObject *object) const size_t HugeObjectSpace::GetHeapObjectSize() const { - size_t result = 0; - EnumerateRegions([&result](Region *current) { - auto obj = reinterpret_cast(current->GetBegin()); - result += obj->GetObjectSize(); - }); - return result; + return GetCommittedSize(); } void HugeObjectSpace::IterateOverObjects(const std::function &objectVisitor) const @@ -420,6 +433,7 @@ bool MachineCodeSpace::Expand() } Region *region = const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE); + region->InitializeKind(); AddRegion(region); int res = region->SetCodeExecutableAndReadable(); LOG_ECMA_MEM(DEBUG) << "MachineCodeSpace::Expand() SetCodeExecutableAndReadable" << res; diff --git a/ecmascript/mem/space.h b/ecmascript/mem/space.h index 7e6012f538ac35246ea9bd61b406878eb6703e89..25f353e2538347b8b04619b35bf56d0240fa4917 100644 --- a/ecmascript/mem/space.h +++ b/ecmascript/mem/space.h @@ -29,13 +29,16 @@ class Heap; class Program; enum MemSpaceType { - SEMI_SPACE, - OLD_SPACE, + OLD_SPACE = 0, NON_MOVABLE, + MACHINE_CODE_SPACE, HUGE_OBJECT_SPACE, + SEMI_SPACE, SNAPSHOT_SPACE, - MACHINE_CODE_SPACE, - SPACE_TYPE_LAST // Count of different types + COMPRESS_SPACE, + SPACE_TYPE_LAST, // Count of different types + + FREE_LIST_NUM = MACHINE_CODE_SPACE - OLD_SPACE + 1, }; enum TriggerGCType { @@ -238,6 +241,7 @@ public: NO_COPY_SEMANTIC(HugeObjectSpace); NO_MOVE_SEMANTIC(HugeObjectSpace); uintptr_t Allocate(size_t objectSize); + void Free(Region *region); size_t GetHeapObjectSize() const; bool ContainObject(TaggedObject *object) const; bool IsLive(TaggedObject *object) const; diff --git a/ecmascript/mem/tlab_allocator-inl.h b/ecmascript/mem/tlab_allocator-inl.h index 9e375449efa015acaab0aa368eaafd3c9c3d053b..32f713e199dae0e274695efd66f864b1e40a329f 100644 --- a/ecmascript/mem/tlab_allocator-inl.h +++ b/ecmascript/mem/tlab_allocator-inl.h @@ -24,7 +24,7 @@ #include "ecmascript/mem/tlab_allocator.h" namespace panda::ecmascript { -static constexpr size_t YOUNG_BUFFER_SIZE = 32 * 1024; +static constexpr size_t YOUNG_BUFFER_SIZE = 31 * 1024; static constexpr size_t OLD_BUFFER_SIZE = 255 * 1024; TlabAllocator::TlabAllocator(Heap *heap, TriggerGCType gcType) diff --git a/ecmascript/message_string.h b/ecmascript/message_string.h index 61a6ba1bfcd501a3dffb9f1db0205012f0bfde38..144f8bdb21edb9a9abfbf5f6dd2eee4bfc747acd 100644 --- a/ecmascript/message_string.h +++ b/ecmascript/message_string.h @@ -20,8 +20,9 @@ namespace panda::ecmascript { // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define MESSAGE_STRING_LIST(V) \ - V(SetReadOnlyProperty, "Cannot set readonly property") \ +#define MESSAGE_STRING_LIST(V) \ + V(SetReadOnlyProperty, "Cannot set readonly property") \ + V(FunctionCallNotConstructor, "class constructor cannot call") \ V(SetPropertyWhenNotExtensible, "Cannot add property in prevent extensions ") class MessageString { diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index ba8933bf568b9732f7d85d009eac417efe3039eb..a3a4885cf4636242e3d6750773582c454e5cf167 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -44,6 +44,7 @@ class JSNApiTests; namespace ecmascript { class EcmaVM; +class JSRuntimeOptions; } // namespace ecmascript using Deleter = void (*)(void *buffer, void *data); @@ -287,7 +288,6 @@ public: bool IsDataView(); bool IsTypedArray(); bool IsNativePointer(); - bool IsNativeObject(); bool IsDate(); bool IsError(); bool IsMap(); @@ -526,7 +526,10 @@ public: void SetNativePointerFieldCount(int32_t count); int32_t GetNativePointerFieldCount(); void *GetNativePointerField(int32_t index); - void SetNativePointerField(int32_t index, void *data); + void SetNativePointerField(int32_t index, + void *nativePointer = nullptr, + NativePointerCallback callBack = nullptr, + void *data = nullptr); }; using FunctionCallback = Local (*)(EcmaVM *, Local, @@ -724,6 +727,10 @@ public: debuggerLibraryPath_ = path; } + void SetEnableArkTools(bool value) { + enableArkTools_ = value; + } + private: std::string GetGcType() const { @@ -782,11 +789,18 @@ private: return debuggerLibraryPath_; } + bool GetEnableArkTools() const + { + return enableArkTools_; + } + + GC_TYPE gcType_ = GC_TYPE::EPSILON; LOG_LEVEL logLevel_ = LOG_LEVEL::DEBUG; uint32_t gcPoolSize_ = DEFAULT_GC_POOL_SIZE; LOG_PRINT logBufPrint_{nullptr}; std::string debuggerLibraryPath_{}; + bool enableArkTools_{false}; friend JSNApi; }; @@ -819,6 +833,7 @@ public: static void* SerializeValue(const EcmaVM *vm, Local data, Local transfer); static Local DeserializeValue(const EcmaVM *vm, void* recoder); static void DeleteSerializationData(void *data); + static void SetOptions(const ecmascript::JSRuntimeOptions &options); private: static bool CreateRuntime(const RuntimeOption &option); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 37a8eaae34c304df617fbf1faf1e12eb807bc0ac..edad0b42654c23113b71a0bdd9b4149176eec08f 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -39,6 +39,7 @@ #include "ecmascript/js_primitive_ref.h" #include "ecmascript/js_promise.h" #include "ecmascript/js_regexp.h" +#include "ecmascript/js_runtime_options.h" #include "ecmascript/js_serializer.h" #include "ecmascript/js_set.h" #include "ecmascript/js_tagged_number.h" @@ -69,7 +70,6 @@ using ecmascript::JSFunctionExtraInfo; using ecmascript::JSHClass; using ecmascript::JSMap; using ecmascript::JSMethod; -using ecmascript::JSNativeObject; using ecmascript::JSNativePointer; using ecmascript::JSObject; using ecmascript::JSPrimitiveRef; @@ -94,6 +94,7 @@ using ecmascript::base::JsonParser; using ecmascript::base::JsonStringifier; using ecmascript::base::StringHelper; using ecmascript::base::TypedArrayHelper; +using ecmascript::JSRuntimeOptions; template using JSHandle = ecmascript::JSHandle; @@ -108,7 +109,7 @@ constexpr std::string_view ENTRY_POINTER = "_GLOBAL::func_main_0"; // ------------------------------------ Panda ----------------------------------------------- bool JSNApi::CreateRuntime(const RuntimeOption &option) { - RuntimeOptions runtimeOptions; + JSRuntimeOptions runtimeOptions; runtimeOptions.SetRuntimeType("ecmascript"); // GC @@ -139,6 +140,8 @@ bool JSNApi::CreateRuntime(const RuntimeOption &option) // Debugger runtimeOptions.SetDebuggerLibraryPath(option.GetDebuggerLibraryPath()); + runtimeOptions.SetEnableArkTools(option.GetEnableArkTools()); + SetOptions(runtimeOptions); static EcmaLanguageContext lcEcma; if (!Runtime::Create(runtimeOptions, {&lcEcma})) { std::cerr << "Error: cannot create runtime" << std::endl; @@ -163,7 +166,7 @@ EcmaVM *JSNApi::CreateJSVM(const RuntimeOption &option) runtime = Runtime::GetCurrent(); return EcmaVM::Cast(runtime->GetPandaVM()); } - RuntimeOptions runtimeOptions; + JSRuntimeOptions runtimeOptions; // GC runtimeOptions.SetGcTriggerType("no-gc-for-start-up"); // A non-production gc strategy. Prohibit stw-gc 10 times. @@ -382,6 +385,11 @@ Local JSNApi::GetExportObject(EcmaVM *vm, const std::string &file, co JSHandle exportObj = moduleManager->GetModuleItem(vm->GetJSThread(), moduleObj, itemString); return JSNApiHelper::ToLocal(exportObj); } + +void JSNApi::SetOptions(const ecmascript::JSRuntimeOptions &options) +{ + ecmascript::EcmaVM::options_ = options; +} // ----------------------------------- HandleScope ------------------------------------- LocalScope::LocalScope(const EcmaVM *vm) : thread_(vm->GetJSThread()) { @@ -522,7 +530,7 @@ Local SymbolRef::GetDescription(const EcmaVM *vm) Local NativePointerRef::New(const EcmaVM *vm, void *nativePointer) { ObjectFactory *factory = vm->GetFactory(); - JSHandle obj = factory->NewJSNativeObject(nativePointer); + JSHandle obj = factory->NewJSNativePointer(nativePointer); return JSNApiHelper::ToLocal(JSHandle(obj)); } @@ -530,14 +538,14 @@ Local NativePointerRef::New( const EcmaVM *vm, void *nativePointer, NativePointerCallback callBack, void *data) { ObjectFactory *factory = vm->GetFactory(); - JSHandle obj = factory->NewJSNativeObject(nativePointer, callBack, data); + JSHandle obj = factory->NewJSNativePointer(nativePointer, callBack, data); return JSNApiHelper::ToLocal(JSHandle(obj)); } void *NativePointerRef::Value() { JSHandle nativePointer = JSNApiHelper::ToJSHandle(this); - return JSHandle(nativePointer)->GetExternalPointer(); + return JSHandle(nativePointer)->GetExternalPointer(); } // ----------------------------------- ObjectRef ---------------------------------------- @@ -592,7 +600,7 @@ Local ObjectRef::Get(const EcmaVM *vm, Local key) OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); if (!ret.GetPropertyMetaData().IsFound()) { - return Local(); + return JSValueRef::Undefined(vm); } return JSNApiHelper::ToLocal(ret.GetValue()); } @@ -731,10 +739,11 @@ void *ObjectRef::GetNativePointerField(int32_t index) return object->GetNativePointerField(index); } -void ObjectRef::SetNativePointerField(int32_t index, void *data) +void ObjectRef::SetNativePointerField(int32_t index, void *nativePointer, + NativePointerCallback callBack, void *data) { JSHandle object(JSNApiHelper::ToJSHandle(this)); - object->SetNativePointerField(index, data); + object->SetNativePointerField(index, nativePointer, callBack, data); } // ----------------------------------- FunctionRef -------------------------------------- @@ -1671,11 +1680,6 @@ bool JSValueRef::IsNativePointer() return JSNApiHelper::ToJSTaggedValue(this).IsJSNativePointer(); } -bool JSValueRef::IsNativeObject() -{ - return JSNApiHelper::ToJSTaggedValue(this).IsJSNativeObject(); -} - bool JSValueRef::IsDate() { return JSNApiHelper::ToJSTaggedValue(this).IsDate(); diff --git a/ecmascript/napi/test/jsnapi_tests.cpp b/ecmascript/napi/test/jsnapi_tests.cpp index 8e146169a4446d8ed9821325139d6fb355cc1494..bb0ce36786feb382363bd12ed6754de6e76a7e9e 100644 --- a/ecmascript/napi/test/jsnapi_tests.cpp +++ b/ecmascript/napi/test/jsnapi_tests.cpp @@ -192,15 +192,28 @@ HWTEST_F_L0(JSNApiTests, Symbol) ASSERT_TRUE(symbol->IsSymbol()); } -HWTEST_F_L0(JSNApiTests, StringUtf8) +HWTEST_F_L0(JSNApiTests, StringUtf8_001) { LocalScope scope(vm_); std::string test = "Hello world"; Local testString = StringRef::NewFromUtf8(vm_, test.c_str()); - ASSERT_TRUE(testString->Utf8Length() == 12); // 12 : length of testString("Hello World") + EXPECT_TRUE(testString->Utf8Length() == 12); // 12 : length of testString("Hello World") char buffer[12]; // 12 : length of testString - ASSERT_TRUE(testString->WriteUtf8(buffer, 12) == 12); // 12 : length of testString("Hello World") + EXPECT_TRUE(testString->WriteUtf8(buffer, 12) == 12); // 12 : length of testString("Hello World") + std::string res(buffer); + ASSERT_EQ(res, test); +} + +HWTEST_F_L0(JSNApiTests, StringUtf8_002) +{ + LocalScope scope(vm_); + std::string test = "年"; + Local testString = StringRef::NewFromUtf8(vm_, test.c_str()); + + EXPECT_TRUE(testString->Utf8Length() == 4); // 4 : length of testString("年") + char buffer[4]; // 4 : length of testString + EXPECT_TRUE(testString->WriteUtf8(buffer, 4) == 4); // 4 : length of testString("年") std::string res(buffer); ASSERT_EQ(res, test); } diff --git a/ecmascript/object_factory-inl.h b/ecmascript/object_factory-inl.h index bc08129f22deef00509812825549dad0d7fe99e4..402bf888b75a5f74d188ee0bfeaaad20bdf94fa5 100644 --- a/ecmascript/object_factory-inl.h +++ b/ecmascript/object_factory-inl.h @@ -32,21 +32,6 @@ EcmaString *ObjectFactory::AllocStringObject(size_t size) return reinterpret_cast(heapHelper_.AllocateYoungGenerationOrHugeObject(stringClass_, size)); } -JSHandle ObjectFactory::NewJSNativePointer(void *externalPointer, bool nonMovable) -{ - TaggedObject *header; - if (nonMovable) { - header = heapHelper_.AllocateNonMovableOrHugeObject(jsNativePointerClass_); - } else { - header = heapHelper_.AllocateYoungGenerationOrHugeObject(jsNativePointerClass_); - } - JSHandle obj(thread_, header); - obj->SetExternalPointer(externalPointer); - obj->SetDeleter(nullptr); - obj->SetData(nullptr); - return obj; -} - JSHandle ObjectFactory::NewJSNativePointer(void *externalPointer, const DeleteEntryPoint &callBack, void *data, diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 554f77f1adc7a646cba828eb632f9ae75493b661..8a2aeaca414aa63630fa9bc487583912da71e424 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -31,6 +31,7 @@ #include "ecmascript/ic/profile_type_info.h" #include "ecmascript/ic/property_box.h" #include "ecmascript/ic/proto_change_details.h" +#include "ecmascript/interpreter/frame_handler.h" #include "ecmascript/internal_call_params.h" #include "ecmascript/jobs/micro_job_queue.h" #include "ecmascript/jobs/pending_job.h" @@ -793,10 +794,12 @@ FreeObject *ObjectFactory::FillFreeObject(uintptr_t address, size_t size, Remove if (size >= FreeObject::SIZE_OFFSET && size < FreeObject::SIZE) { object = reinterpret_cast(address); object->SetClass(freeObjectWithOneFieldClass_); + object->SetNext(nullptr); } else if (size >= FreeObject::SIZE) { object = reinterpret_cast(address); object->SetClass(freeObjectWithTwoFieldClass_); object->SetAvailable(size); + object->SetNext(nullptr); } else if (size == FreeObject::NEXT_OFFSET) { object = reinterpret_cast(address); object->SetClass(freeObjectWithNoneFieldClass_); @@ -1318,14 +1321,14 @@ JSHandle ObjectFactory::NewInternalAccessor(void *setter, void *ge TaggedObject *header = heapHelper_.AllocateNonMovableOrHugeObject(internalAccessorClass_); JSHandle obj(thread_, AccessorData::Cast(header)); if (setter != nullptr) { - JSHandle setFunc = NewJSNativePointer(setter, true); + JSHandle setFunc = NewJSNativePointer(setter, nullptr, nullptr, true); obj->SetSetter(thread_, setFunc.GetTaggedValue()); } else { JSTaggedValue setFunc = JSTaggedValue::Undefined(); obj->SetSetter(thread_, setFunc); ASSERT(!obj->HasSetter()); } - JSHandle getFunc = NewJSNativePointer(getter, true); + JSHandle getFunc = NewJSNativePointer(getter, nullptr, nullptr, true); obj->SetGetter(thread_, getFunc); return obj; } @@ -2088,7 +2091,7 @@ JSHandle ObjectFactory::NewEmptyJSObject() EcmaString *ObjectFactory::ResolveString(uint32_t stringId) { - JSMethod *caller = EcmaFrameHandler(thread_).GetMethod(); + JSMethod *caller = InterpretedFrameHandler(thread_).GetMethod(); auto *pf = caller->GetPandaFile(); auto id = panda_file::File::EntityId(stringId); auto foundStr = pf->GetStringData(id); @@ -2101,26 +2104,10 @@ uintptr_t ObjectFactory::NewSpaceBySnapShotAllocator(size_t size) return heapHelper_.AllocateSnapShotSpace(size); } -JSHandle ObjectFactory::NewJSNativeObject(void *externalPointer) -{ - return NewJSNativeObject(externalPointer, nullptr, nullptr); -} - -JSHandle ObjectFactory::NewJSNativeObject(void *externalPointer, DeleteEntryPoint callback, void *data) -{ - JSHandle env = vm_->GetGlobalEnv(); - JSHandle dynclass(env->GetJSNativeObjectClass()); - JSHandle nativeObject = JSHandle::Cast(NewJSObject(dynclass)); - JSHandle pointer = NewJSNativePointer(externalPointer, callback, data); - nativeObject->SetJSNativePointer(thread_, pointer.GetTaggedValue()); - vm_->PushToArrayDataList(*pointer); - return nativeObject; -} - JSHandle ObjectFactory::NewMachineCodeObject(size_t length, const uint8_t *data) { NewObjectHook(); - TaggedObject *obj = heapHelper_.AllocateMachineCodeSpaceObject(machineCodeClass_, length + sizeof(MachineCode)); + TaggedObject *obj = heapHelper_.AllocateMachineCodeSpaceObject(machineCodeClass_, length + MachineCode::SIZE); MachineCode *code = MachineCode::Cast(obj); code->SetInstructionSizeInBytes(thread_, JSTaggedValue(static_cast(length))); if (data != nullptr) { diff --git a/ecmascript/object_factory.h b/ecmascript/object_factory.h index e4ac085292ef667de9fc544372fb5113c305c62e..c8adba79ddb909d1e90de79561daa3faef63901b 100644 --- a/ecmascript/object_factory.h +++ b/ecmascript/object_factory.h @@ -21,7 +21,6 @@ #include "ecmascript/js_function_kind.h" #include "ecmascript/js_handle.h" #include "ecmascript/js_hclass.h" -#include "ecmascript/js_native_object.h" #include "ecmascript/js_native_pointer.h" #include "ecmascript/js_tagged_value.h" #include "ecmascript/mem/machine_code.h" @@ -105,7 +104,6 @@ using base::ErrorType; using DeleteEntryPoint = void (*)(void *, void *); enum class RemoveSlots { YES, NO }; - class ObjectFactory { public: explicit ObjectFactory(JSThread *thread, Heap *heap); @@ -308,9 +306,10 @@ public: EcmaString *InternString(const JSHandle &key); - inline JSHandle NewJSNativePointer(void *externalPointer, bool nonMovable = false); - inline JSHandle NewJSNativePointer(void *externalPointer, const DeleteEntryPoint &callBack, - void *data, bool nonMovable = false); + inline JSHandle NewJSNativePointer(void *externalPointer, + const DeleteEntryPoint &callBack = nullptr, + void *data = nullptr, + bool nonMovable = false); JSHandle NewJSObjectByClass(const JSHandle &keys, const JSHandle &values); JSHandle NewJSObjectByClass(const JSHandle &properties, size_t length); @@ -333,8 +332,6 @@ public: uintptr_t NewSpaceBySnapShotAllocator(size_t size); JSHandle NewMachineCodeObject(size_t length, const uint8_t *data); - JSHandle NewJSNativeObject(void *externalPointer); - JSHandle NewJSNativeObject(void *externalPointer, DeleteEntryPoint callback, void *data); ~ObjectFactory() = default; @@ -360,6 +357,11 @@ public: JSHandle NewFromString(EcmaString *str); JSHandle ConcatFromString(const JSHandle &prefix, const JSHandle &suffix); + // used for creating Function + JSHandle NewJSObject(const JSHandle &jshclass); + // used for creating jshclass in Builtins, Function, Class_Linker + JSHandle NewEcmaDynClass(uint32_t size, JSType type, const JSHandle &prototype); + private: friend class GlobalEnv; friend class GlobalEnvConstants; @@ -421,11 +423,6 @@ private: JSHandle NewEcmaDynClass(uint32_t size, JSType type); // used for creating jshclass in GlobalEnv, EcmaVM JSHandle NewEcmaDynClass(JSHClass *hclass, uint32_t size, JSType type); - // used for creating jshclass in Builtins, Function, Class_Linker - JSHandle NewEcmaDynClass(uint32_t size, JSType type, const JSHandle &prototype); - - // used for creating Function - JSHandle NewJSObject(const JSHandle &jshclass); // used to create nonmovable js_object JSHandle NewNonMovableJSObject(const JSHandle &jshclass); diff --git a/ecmascript/object_operator.cpp b/ecmascript/object_operator.cpp index a2ca2eb5bf5922e40554b00e5e1f056c07482480..9f719411fa436bd57a63d7db00838d9f439c875c 100644 --- a/ecmascript/object_operator.cpp +++ b/ecmascript/object_operator.cpp @@ -568,8 +568,8 @@ void ObjectOperator::DeleteElementInHolder() const JSObject::ElementsToDictionary(thread_, JSHandle(holder_)); } else { JSHandle dictHandle(thread_, elements); - NumberDictionary *dict = NumberDictionary::Remove(thread_, dictHandle, GetIndex()); - obj->SetElements(thread_, JSTaggedValue(dict)); + NumberDictionary *newDict = NumberDictionary::Remove(thread_, dictHandle, GetIndex()); + obj->SetElements(thread_, JSTaggedValue(newDict)); } } @@ -661,9 +661,9 @@ void ObjectOperator::AddPropertyInternal(const JSHandle &value) PropertyBoxType cellType = value->IsUndefined() ? PropertyBoxType::UNDEFINED : PropertyBoxType::CONSTANT; attr.SetBoxType(cellType); - JSTaggedValue properties( - GlobalDictionary::PutIfAbsent(thread_, dict, key_, JSHandle(cellHandle), attr)); - obj->SetProperties(thread_, properties); + GlobalDictionary *properties = + GlobalDictionary::PutIfAbsent(thread_, dict, key_, JSHandle(cellHandle), attr); + obj->SetProperties(thread_, JSTaggedValue(properties)); // index and fastMode is not essential for global obj; SetFound(0, cellHandle.GetTaggedValue(), attr.GetValue(), true); return; @@ -704,8 +704,8 @@ void ObjectOperator::AddPropertyInternal(const JSHandle &value) // change to dictionary and add one. JSHandle dict(JSObject::TransitionToDictionary(thread_, obj)); attr.SetDictionaryOrder(PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES); - auto result = JSTaggedValue(NameDictionary::PutIfAbsent(thread_, dict, key_, value, attr)); - obj->SetProperties(thread_, result); + NameDictionary *newDict = NameDictionary::PutIfAbsent(thread_, dict, key_, value, attr); + obj->SetProperties(thread_, JSTaggedValue(newDict)); // index is not essential when fastMode is false; SetFound(0, value.GetTaggedValue(), attr.GetValue(), false); return; @@ -724,8 +724,8 @@ void ObjectOperator::AddPropertyInternal(const JSHandle &value) } JSHandle dictHandle(array); - auto result = JSTaggedValue(NameDictionary::PutIfAbsent(thread_, dictHandle, key_, value, attr)); - obj->SetProperties(thread_, result); + NameDictionary *newDict = NameDictionary::PutIfAbsent(thread_, dictHandle, key_, value, attr); + obj->SetProperties(thread_, JSTaggedValue(newDict)); SetFound(0, value.GetTaggedValue(), attr.GetValue(), false); } diff --git a/ecmascript/platform/platform.cpp b/ecmascript/platform/platform.cpp new file mode 100644 index 0000000000000000000000000000000000000000..f589f3807e9a1f370137a6b60e6c52deba0057db --- /dev/null +++ b/ecmascript/platform/platform.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 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/platform/platform.h" + +#include "sys/sysinfo.h" + +namespace panda::ecmascript { +void Platform::Initialize(int threadNum) +{ + os::memory::LockHolder lock(mutex_); + if (isInitialized_++ <= 0) { + runner_ = std::make_unique(TheMostSuitableThreadNum(threadNum)); + } +} + +void Platform::Destory() +{ + os::memory::LockHolder lock(mutex_); + if (--isInitialized_ <= 0) { + runner_->Terminate(); + } +} + +int Platform::TheMostSuitableThreadNum(int threadNum) const +{ + if (threadNum > 0) { + return std::min(threadNum, MAX_PLATFORM_THREAD_NUM); + } + int numOfCpuCore = get_nprocs() - 1; + return std::min(numOfCpuCore, MAX_PLATFORM_THREAD_NUM); +} +} // namespace panda::ecmascript diff --git a/ecmascript/platform/platform.h b/ecmascript/platform/platform.h new file mode 100644 index 0000000000000000000000000000000000000000..d62af797eeac0c26e5578b02f264aafa0debcf76 --- /dev/null +++ b/ecmascript/platform/platform.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 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_PALTFORM_PLATFORM_H +#define ECMASCRIPT_PALTFORM_PLATFORM_H + +#include + +#include "ecmascript/platform/runner.h" +#include "os/mutex.h" + +namespace panda::ecmascript { +class Platform { +public: + static Platform *GetCurrentPlatform() + { + static Platform platform; + return &platform; + } + + Platform() = default; + ~Platform() = default; + + NO_COPY_SEMANTIC(Platform); + NO_MOVE_SEMANTIC(Platform); + + void Initialize(int threadNum = DEFAULT_PLATFORM_THREAD_NUM); + void Destory(); + + void PostTask(std::unique_ptr task) const + { + ASSERT(isInitialized_ > 0); + runner_->PostTask(std::move(task)); + } + +private: + static constexpr uint32_t MAX_PLATFORM_THREAD_NUM = 7; + static constexpr uint32_t DEFAULT_PLATFORM_THREAD_NUM = 0; + + int TheMostSuitableThreadNum(int threadNum) const; + + std::unique_ptr runner_; + int isInitialized_ = 0; + os::memory::Mutex mutex_; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_PALTFORM_PLATFORM_H diff --git a/ecmascript/platform/runner.cpp b/ecmascript/platform/runner.cpp new file mode 100644 index 0000000000000000000000000000000000000000..949607932c47888207d2a1457e4394163990f81c --- /dev/null +++ b/ecmascript/platform/runner.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2021 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/platform/runner.h" + +#include "os/thread.h" + +namespace panda::ecmascript { +Runner::Runner(int threadNum) +{ + for (int i = 0; i < threadNum; i++) { + std::unique_ptr thread = std::make_unique(&Runner::Run, this); + os::thread::SetThreadName(thread->native_handle(), "GC_WorkerThread"); + threadPool_.emplace_back(std::move(thread)); + } +} + +void Runner::Terminate() +{ + taskQueue_.Terminate(); + int threadNum = threadPool_.size(); + for (int i = 0; i < threadNum; i++) { + threadPool_.at(i)->join(); + } + threadPool_.clear(); +} + +void Runner::Run() +{ + while (std::unique_ptr task = taskQueue_.PopTask()) { + task->Run(); + } +} +} // namespace panda::ecmascript diff --git a/ecmascript/platform/runner.h b/ecmascript/platform/runner.h new file mode 100644 index 0000000000000000000000000000000000000000..be0ada02795dae94bd2a6aae7301676b3cdae6e0 --- /dev/null +++ b/ecmascript/platform/runner.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 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_PLATFORM_RUNNER_H +#define ECMASCRIPT_PLATFORM_RUNNER_H + +#include +#include +#include + +#include "ecmascript/platform/task_queue.h" + +namespace panda::ecmascript { +class Runner { +public: + explicit Runner(int threadNum); + ~Runner() = default; + + NO_COPY_SEMANTIC(Runner); + NO_MOVE_SEMANTIC(Runner); + + void PostTask(std::unique_ptr task) + { + taskQueue_.PostTask(std::move(task)); + } + + void Terminate(); + +private: + void Run(); + + std::vector> threadPool_ {}; + TaskQueue taskQueue_ {}; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_PLATFORM_RUNNER_H diff --git a/ecmascript/platform/task.h b/ecmascript/platform/task.h new file mode 100644 index 0000000000000000000000000000000000000000..71eff10111df1d949f1c4521acdfb63f55c0951a --- /dev/null +++ b/ecmascript/platform/task.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 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_PLATFORM_TASK_H +#define ECMASCRIPT_PLATFORM_TASK_H + +#include "macros.h" + +namespace panda::ecmascript { +class Task { +public: + Task() = default; + virtual ~Task() = default; + virtual bool Run() = 0; + + NO_COPY_SEMANTIC(Task); + NO_MOVE_SEMANTIC(Task); +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_PLATFORM_TASK_H diff --git a/ecmascript/platform/task_queue.cpp b/ecmascript/platform/task_queue.cpp new file mode 100644 index 0000000000000000000000000000000000000000..b90c20556984aafedb5315534488305cb2fc6a5a --- /dev/null +++ b/ecmascript/platform/task_queue.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 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/platform/task_queue.h" + +namespace panda::ecmascript { +void TaskQueue::PostTask(std::unique_ptr task) +{ + os::memory::LockHolder holder(mtx_); + ASSERT(!terminate_); + tasks_.push(std::move(task)); + cv_.Signal(); +} + +std::unique_ptr TaskQueue::PopTask() +{ + os::memory::LockHolder holder(mtx_); + while (true) { + if (!tasks_.empty()) { + std::unique_ptr task = std::move(tasks_.front()); + tasks_.pop(); + return task; + } + if (terminate_) { + cv_.SignalAll(); + return nullptr; + } + cv_.Wait(&mtx_); + } +} + +void TaskQueue::Terminate() +{ + os::memory::LockHolder holder(mtx_); + terminate_ = true; + cv_.SignalAll(); +} +} // namespace panda::ecmascript diff --git a/ecmascript/platform/task_queue.h b/ecmascript/platform/task_queue.h new file mode 100644 index 0000000000000000000000000000000000000000..ab8d7b1f763c6dd345c31730718443d6c0d7d7b5 --- /dev/null +++ b/ecmascript/platform/task_queue.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 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_PLATFORM_TASK_QUEUE_H +#define ECMASCRIPT_PLATFORM_TASK_QUEUE_H + +#include +#include +#include +#include + +#include "ecmascript/platform/task.h" +#include "os/mutex.h" + +namespace panda::ecmascript { +class TaskQueue { +public: + TaskQueue() = default; + ~TaskQueue() = default; + + NO_COPY_SEMANTIC(TaskQueue); + NO_MOVE_SEMANTIC(TaskQueue); + + void PostTask(std::unique_ptr task); + std::unique_ptr PopTask(); + + void Terminate(); + +private: + std::queue> tasks_; + + std::atomic_bool terminate_ = false; + os::memory::Mutex mtx_; + os::memory::ConditionVariable cv_; +}; +} // namespace panda::ecmascript +#endif // ECMASCRIPT_PLATFORM_TASK_QUEUE_H diff --git a/ecmascript/runtime_call_id.h b/ecmascript/runtime_call_id.h index a98164358f7ee318ea5ba2bfa3f223d7d01d4cc2..359dfa1110c576d335d391ff4e9f695149ecaad2 100644 --- a/ecmascript/runtime_call_id.h +++ b/ecmascript/runtime_call_id.h @@ -153,7 +153,6 @@ namespace panda::ecmascript { V(AddPropertyByIndex) \ V(GetPropertyByIndex) \ V(GetPropertyByValue) \ - V(SetPropertyByName) \ V(SetPropertyByIndex) \ V(SetPropertyByValue) \ V(FastTypeOf) \ diff --git a/ecmascript/runtime_trampolines.cpp b/ecmascript/runtime_trampolines.cpp index 839459d5e09e02ed0560d85e2b61496b333070d4..ad76986c5cb052ce9f14d6cc27aae4004d9ec8f2 100644 --- a/ecmascript/runtime_trampolines.cpp +++ b/ecmascript/runtime_trampolines.cpp @@ -16,17 +16,24 @@ #include "runtime_trampolines.h" #include "ecmascript/accessor_data.h" #include "ecmascript/ecma_macros.h" +#include "ecmascript/frames.h" +#include "ecmascript/interpreter/interpreter-inl.h" #include "ecmascript/js_object.h" #include "ecmascript/js_proxy.h" #include "ecmascript/layout_info.h" #include "ecmascript/message_string.h" #include "ecmascript/object_factory.h" +#include "ecmascript/tagged_dictionary.h" namespace panda::ecmascript { bool RuntimeTrampolines::AddElementInternal(uint64_t argThread, uint64_t argReceiver, uint32_t argIndex, uint64_t argValue, uint32_t argAttr) { + uintptr_t *curFp = nullptr; auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle receiver(thread, reinterpret_cast(argReceiver)); JSHandle value(thread, JSTaggedValue(reinterpret_cast(argValue))); @@ -37,8 +44,11 @@ bool RuntimeTrampolines::AddElementInternal(uint64_t argThread, uint64_t argRece bool RuntimeTrampolines::CallSetter(uint64_t argThread, uint64_t argSetter, uint64_t argReceiver, uint64_t argValue, bool argMayThrow) { + uintptr_t *curFp = nullptr; auto thread = reinterpret_cast(argThread); - [[maybe_unused]] EcmaHandleScope handleScope(thread); + GET_CURRETN_FP(curFp); + uintptr_t * prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); JSHandle receiver(thread, JSTaggedValue(reinterpret_cast(argReceiver))); JSHandle value(thread, JSTaggedValue(reinterpret_cast(argValue))); auto setter = AccessorData::Cast((reinterpret_cast(argSetter))); @@ -47,7 +57,11 @@ bool RuntimeTrampolines::CallSetter(uint64_t argThread, uint64_t argSetter, uint void RuntimeTrampolines::ThrowTypeError(uint64_t argThread, int argMessageStringId) { + uintptr_t *curFp = nullptr; auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); [[maybe_unused]] EcmaHandleScope handleScope(thread); std::string message = MessageString::GetMessageString(argMessageStringId); ObjectFactory *factory = JSThread::Cast(thread)->GetEcmaVM()->GetFactory(); @@ -58,7 +72,11 @@ void RuntimeTrampolines::ThrowTypeError(uint64_t argThread, int argMessageString bool RuntimeTrampolines::JSProxySetProperty(uint64_t argThread, uint64_t argProxy, uint64_t argKey, uint64_t argValue, uint64_t argReceiver, bool argMayThrow) { + uintptr_t *curFp = nullptr; auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); [[maybe_unused]] EcmaHandleScope handleScope(thread); JSHandle proxy(thread, JSTaggedValue(reinterpret_cast(argProxy))); JSHandle index(thread, JSTaggedValue(reinterpret_cast(argKey))); @@ -76,7 +94,11 @@ uint32_t RuntimeTrampolines::GetHash32(uint64_t key, uint64_t len) uint64_t RuntimeTrampolines::CallGetter(uint64_t argThread, uint64_t argGetter, uint64_t argReceiver) { + uintptr_t *curFp = nullptr; auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); auto accessor = AccessorData::Cast(reinterpret_cast(argGetter)); JSHandle objHandle(thread, JSTaggedValue(reinterpret_cast(argReceiver))); return JSObject::CallGetter(thread, accessor, objHandle).GetRawData(); @@ -84,7 +106,11 @@ uint64_t RuntimeTrampolines::CallGetter(uint64_t argThread, uint64_t argGetter, uint64_t RuntimeTrampolines::AccessorGetter(uint64_t argThread, uint64_t argGetter, uint64_t argReceiver) { + uintptr_t *curFp = nullptr; auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); auto accessor = AccessorData::Cast(reinterpret_cast(argGetter)); JSHandle objHandle(thread, JSTaggedValue(reinterpret_cast(argReceiver))); return accessor->CallInternalGet(thread, objHandle).GetRawData(); @@ -92,7 +118,11 @@ uint64_t RuntimeTrampolines::AccessorGetter(uint64_t argThread, uint64_t argGett int32_t RuntimeTrampolines::FindElementWithCache(uint64_t argThread, uint64_t hClass, uint64_t key, int32_t num) { + uintptr_t *curFp = nullptr; auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); auto cls = reinterpret_cast(hClass); auto layoutInfo = LayoutInfo::Cast(cls->GetAttributes().GetTaggedObject()); return layoutInfo->FindElementWithCache(thread, cls, JSTaggedValue(key), num); @@ -103,4 +133,91 @@ uint32_t RuntimeTrampolines::StringGetHashCode(uint64_t ecmaString) auto string = reinterpret_cast(ecmaString); return string->GetHashcode(); } + +void RuntimeTrampolines::PrintHeapReginInfo(uint64_t argThread) +{ + auto thread = reinterpret_cast(argThread); + thread->GetEcmaVM()->GetHeap()->GetNewSpace()->EnumerateRegions([](Region *current) { + LOG_ECMA(INFO) << "semispace region: " << current << std::endl; + }); + thread->GetEcmaVM()->GetHeap()->GetOldSpace()->EnumerateRegions([](Region *current) { + LOG_ECMA(INFO) << "GetOldSpace region: " << current << std::endl; + }); + thread->GetEcmaVM()->GetHeap()->GetNonMovableSpace()->EnumerateRegions([](Region *current) { + LOG_ECMA(INFO) << "GetNonMovableSpace region: " << current << std::endl; + }); + thread->GetEcmaVM()->GetHeap()->GetMachineCodeSpace()->EnumerateRegions([](Region *current) { + LOG_ECMA(INFO) << "GetMachineCodeSpace region: " << current << std::endl; + }); +} + +TaggedArray* RuntimeTrampolines::GetTaggedArrayPtrTest(uint64_t argThread) +{ + uintptr_t *curFp = nullptr; + auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); + // this case static static JSHandle arr don't free in first call + // second call trigger gc. + // don't call EcmaHandleScope handleScope(thread); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + static int i = 0; + static JSHandle arr = factory->NewTaggedArray(2); + if (i == 0) { + arr->Set(thread, 0, JSTaggedValue(3)); // 3: first element + arr->Set(thread, 1, JSTaggedValue(4)); // 4: second element + } +#ifndef NDEBUG + PrintHeapReginInfo(argThread); +#endif + if (i != 0) { + thread->GetEcmaVM()->CollectGarbage(TriggerGCType::COMPRESS_FULL_GC); + } + LOG_ECMA(INFO) << " arr->GetData() " << std::hex << " " << arr->GetData(); + i++; + return *arr; +} +uint64_t RuntimeTrampolines::Execute(uint64_t argThread, uint64_t argFunc, + uint64_t thisArg, uint32_t argc, uint64_t argArgv) +{ + auto thread = reinterpret_cast(argThread); + auto func = reinterpret_cast(argFunc); + auto argv = reinterpret_cast(argArgv); + CallParams params; + params.callTarget = func; + params.newTarget = JSTaggedValue::VALUE_UNDEFINED; + params.thisArg = thisArg; + params.argc = argc; + params.argv = argv; + + return EcmaInterpreter::Execute(thread, params).GetRawData(); +} + +void RuntimeTrampolines::SetValueWithBarrier(uint64_t argThread, uint64_t argAddr, uint64_t argOffset, + uint64_t argValue) +{ + auto thread = reinterpret_cast(argThread); + auto addr = reinterpret_cast(argAddr); + auto offset = static_cast(argOffset); + auto value = static_cast(argValue); + + SET_VALUE_WITH_BARRIER(thread, addr, offset, value); +} + +double RuntimeTrampolines::FloatMod(double left, double right) +{ + return std::fmod(left, right); +} + +uint64_t RuntimeTrampolines::NewInternalString(uint64_t argThread, uint64_t argKey) +{ + uintptr_t *curFp = nullptr; + auto thread = reinterpret_cast(argThread); + GET_CURRETN_FP(curFp); + uintptr_t *prevFp = GET_PREV_FP(curFp); + CallRuntimeTrampolinesScope scope(thread, prevFp, curFp); + JSHandle keyHandle(thread, JSTaggedValue(reinterpret_cast(argKey))); + return JSTaggedValue(thread->GetEcmaVM()->GetFactory()->InternString(keyHandle)).GetRawData(); +} } // namespace panda::ecmascript diff --git a/ecmascript/runtime_trampolines.h b/ecmascript/runtime_trampolines.h index 678ea521eeab52a92c509428ab7068bee809a88e..c6396b2294db9868f643cd4b3b7e988d676fdc50 100644 --- a/ecmascript/runtime_trampolines.h +++ b/ecmascript/runtime_trampolines.h @@ -16,7 +16,9 @@ #ifndef ECMASCRIPT_RUNTIME_TRAMPOLINES_H #define ECMASCRIPT_RUNTIME_TRAMPOLINES_H #include "ecmascript/compiler/fast_stub_define.h" +#include "ecmascript/ecma_macros.h" #include "ecmascript/js_thread.h" +#include "ecmascript/interpreter/frame_handler.h" namespace panda::ecmascript { class RuntimeTrampolines { @@ -48,6 +50,42 @@ public: static uint32_t GetHash32(uint64_t key, uint64_t len); static int32_t FindElementWithCache(uint64_t argThread, uint64_t hClass, uint64_t key, int32_t num); static uint32_t StringGetHashCode(uint64_t ecmaString); + static TaggedArray* GetTaggedArrayPtrTest(uint64_t argThread); + static uint64_t Execute(uint64_t argThread, uint64_t argFunc, uint64_t thisArg, uint32_t argc, uint64_t argArgv); + static void SetValueWithBarrier(uint64_t argThread, uint64_t argAddr, uint64_t argOffset, uint64_t argValue); + static double FloatMod(double left, double right); + static uint64_t NewInternalString(uint64_t argThread, uint64_t argKey); + static void PrintHeapReginInfo(uint64_t argThread); +}; + +class CallRuntimeTrampolinesScope { +public: + CallRuntimeTrampolinesScope(JSThread *thread, uintptr_t *newFp, uintptr_t *pc) + :lastFp_(nullptr), + thread_(thread) + { + lastOptCallRuntimePc_ = thread->GetLastOptCallRuntimePc(); + thread->SetLastOptCallRuntimePc(pc); + JSTaggedType *cursp = const_cast(thread->GetCurrentSPFrame()); + lastFp_ = static_cast(static_cast(cursp)); + thread->SetLastIFrameSp(cursp); + JSTaggedType *newSp = static_cast(static_cast(newFp)); + thread_->SetCurrentSPFrame(newSp); + LOG_ECMA(INFO) << "Sp: " << newSp << " type:" << + static_cast(FrameHandler(newSp).GetFrameType()); + } + ~CallRuntimeTrampolinesScope() + { + JSTaggedType *oldSp = static_cast(static_cast(lastFp_)); + thread_->SetCurrentSPFrame(oldSp); + LOG_ECMA(INFO) << "Sp: " << oldSp << " type:" << + static_cast(FrameHandler(oldSp).GetFrameType()); + thread_->SetLastOptCallRuntimePc(lastOptCallRuntimePc_); + } +private: + uintptr_t *lastFp_; + JSThread *thread_; + uintptr_t *lastOptCallRuntimePc_; }; } // namespace panda::ecmascript -#endif \ No newline at end of file +#endif diff --git a/ecmascript/snapshot/tests/snapshot_test.cpp b/ecmascript/snapshot/tests/snapshot_test.cpp index 3131e0baac3e18970a95c7d8d0cdf9754a90d3dc..f28064c11435af7207046300ab8b7e6e14f6b49c 100644 --- a/ecmascript/snapshot/tests/snapshot_test.cpp +++ b/ecmascript/snapshot/tests/snapshot_test.cpp @@ -40,7 +40,7 @@ public: void SetUp() override { - RuntimeOptions options; + JSRuntimeOptions options; options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetBootIntrinsicSpaces({"ecmascript"}); diff --git a/ecmascript/stub_module.cpp b/ecmascript/stub_module.cpp index 62e7ce4417b1d528ca2b46693d9da764321de252..9449ac3c0aeeac1d3a9bab90a59ff9bbdc393aeb 100644 --- a/ecmascript/stub_module.cpp +++ b/ecmascript/stub_module.cpp @@ -15,6 +15,7 @@ #include "stub_module.h" #include "ecmascript/object_factory.h" +#include "ecmascript/compiler/llvm/llvm_stackmap_parser.h" namespace panda::ecmascript { void StubModule::Save(const std::string &filename) @@ -23,25 +24,73 @@ void StubModule::Save(const std::string &filename) std::ofstream modulefile(filename.c_str(), std::ofstream::binary); /* write stub entries offset */ modulefile.write(reinterpret_cast(fastStubEntries_.data()), - sizeof(uintptr_t) * kungfu::FAST_STUB_MAXCOUNT); - /* write code length & code buff */ + sizeof(uintptr_t) * (kungfu::FAST_STUB_MAXCOUNT)); int codeSize = code_->GetInstructionSizeInBytes().GetInt(); + /* write host code section start addr */ + modulefile.write(reinterpret_cast(&hostCodeSectionAddr_), sizeof(hostCodeSectionAddr_)); + /* write stackmap offset */ + int stackmapOffset = sizeof(uintptr_t) * (kungfu::FAST_STUB_MAXCOUNT) + 2*sizeof(int) + + codeSize; + modulefile.write(reinterpret_cast(&stackmapOffset), + sizeof(int)); + /* write code length & code buff */ modulefile.write(reinterpret_cast(&codeSize), sizeof(codeSize)); modulefile.write(reinterpret_cast(code_->GetDataOffsetAddress()), codeSize); + /* write stackmap buff */ + int stackmapSize = GetStackMapSize(); +#ifndef NDEBUG + LOG_ECMA(INFO) << "stackmap host addr:" << GetStackMapAddr() << " stackmapSize:" << stackmapSize << std::endl; +#endif + modulefile.write(reinterpret_cast(&stackmapSize), sizeof(stackmapSize)); + modulefile.write(reinterpret_cast(GetStackMapAddr()), stackmapSize); + + uint8_t *ptr = reinterpret_cast(GetStackMapAddr()); + kungfu::LLVMStackMapParser::GetInstance().CalculateStackMap(ptr); + modulefile.close(); } } void StubModule::Load(JSThread *thread, const std::string &filename) { +#ifndef NDEBUG + Logger::SetLevel(Logger::Level::INFO); +#endif + // now MachineCode is non movable, code and stackmap sperately is saved to MachineCode + // by calling NewMachineCodeObject. + // then MachineCode will support movable, code is saved to MachineCode and stackmap is saved + // to different heap which will be freed when stackmap is parsed by EcmaVM is started. std::ifstream modulefile(filename.c_str(), std::ofstream::binary); - modulefile.read(reinterpret_cast(fastStubEntries_.data()), sizeof(uintptr_t) * kungfu::FAST_STUB_MAXCOUNT); + modulefile.read(reinterpret_cast(fastStubEntries_.data()), + sizeof(uintptr_t) * (kungfu::FAST_STUB_MAXCOUNT)); + /* read host code section start addr */ + modulefile.read(reinterpret_cast(&hostCodeSectionAddr_), sizeof(hostCodeSectionAddr_)); + int stackmapOffset; + modulefile.read(reinterpret_cast(&stackmapOffset), sizeof(stackmapOffset)); int codeSize = 0; modulefile.read(reinterpret_cast(&codeSize), sizeof(codeSize)); auto factory = thread->GetEcmaVM()->GetFactory(); auto codeHandle = factory->NewMachineCodeObject(codeSize, nullptr); modulefile.read(reinterpret_cast(codeHandle->GetDataOffsetAddress()), codeSize); SetCode(*codeHandle); +#ifndef NDEBUG + LOG_ECMA(INFO) << "codeSection adress for device:" << std::hex << codeHandle->GetDataOffsetAddress() << + " codeSize:" << codeSize << std::endl; +#endif + SetDeviceCodeSectionAddr(codeHandle->GetDataOffsetAddress()); + /* read stackmap */ + + int stackmapSize; + modulefile.read(reinterpret_cast(&stackmapSize), sizeof(stackmapSize)); + SetStackMapSize(stackmapSize); + auto dataHandle = factory->NewMachineCodeObject(stackmapSize, nullptr); + modulefile.read(reinterpret_cast(dataHandle->GetDataOffsetAddress()), stackmapSize); + SetStackMapData(*dataHandle); +#ifndef NDEBUG + LOG_ECMA(INFO) << "stackmapSize adress for device:" << std::hex << dataHandle->GetDataOffsetAddress() + << " stackmapSize:"<< stackmapSize << std::endl; +#endif + SetStackMapAddr(reinterpret_cast(dataHandle->GetDataOffsetAddress())); modulefile.close(); } } // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/stub_module.h b/ecmascript/stub_module.h index a48b841ecef52bee581fb818581dc8587ab79801..5594be68b74f0802fa9ecfb20468937013bf2d72 100644 --- a/ecmascript/stub_module.h +++ b/ecmascript/stub_module.h @@ -22,10 +22,9 @@ #include "libpandabase/macros.h" namespace panda::ecmascript { -using Address = uintptr_t; class PUBLIC_API StubModule { public: - Address GetStubEntry(int index) + uintptr_t GetStubEntry(int index) { return code_->GetDataOffsetAddress() + fastStubEntries_[index]; } @@ -35,18 +34,63 @@ public: { code_ = code; } - void SetStubEntry(int index, Address offset) + void SetStackMapData(MachineCode *stackMapData) + { + stackMapData_ = stackMapData; + } + void SetStubEntry(int index, uintptr_t offset) { fastStubEntries_[index] = offset; } + void SetHostCodeSectionAddr(uintptr_t addr) + { + hostCodeSectionAddr_ = addr; + } + uintptr_t GetHostCodeSectionAddr() const + { + return hostCodeSectionAddr_; + } + void SetDeviceCodeSectionAddr(uintptr_t addr) + { + devicesCodeSectionAddr_ = addr; + } + uintptr_t GetDeviceCodeSectionAddr() const + { + return devicesCodeSectionAddr_; + } JSTaggedValue GetCode() { return JSTaggedValue(code_); } + JSTaggedValue GetStackMapData() const + { + return JSTaggedValue(stackMapData_); + } + void SetStackMapAddr(uintptr_t addr) + { + stackMapAddr_ = addr; + } + uintptr_t GetStackMapAddr() const + { + return stackMapAddr_; + } + void SetStackMapSize(int len) + { + stackMapSize_ = len; + } + int GetStackMapSize() const + { + return stackMapSize_; + } private: - std::array fastStubEntries_ {-1}; + std::array fastStubEntries_ {-1}; + uintptr_t hostCodeSectionAddr_ {0}; + uintptr_t devicesCodeSectionAddr_ {0}; MachineCode *code_ {nullptr}; + MachineCode *stackMapData_ {nullptr}; + uintptr_t stackMapAddr_ {0}; + int stackMapSize_ {0}; }; } // namespace panda::ecmascript #endif // ECMASCRIPT_STUB_MODULE_H \ No newline at end of file diff --git a/ecmascript/tests/BUILD.gn b/ecmascript/tests/BUILD.gn index f54a7db7eb53edc97b8bb69ee7f1f802ca7aab98..1db99fea73e77aabac4f96a6ff9983bc0881d894 100644 --- a/ecmascript/tests/BUILD.gn +++ b/ecmascript/tests/BUILD.gn @@ -98,6 +98,33 @@ host_unittest_action("DumpTest") { } } +host_unittest_action("EcmaModuleTest") { + module_out_path = module_output_path + + sources = [ + # test file + "ecma_module_test.cpp", + ] + + configs = [ + "//ark/js_runtime:ecma_test_config", + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_common_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + "$ark_root/libpandabase:libarkbase", + "//ark/js_runtime:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + if (!is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime" ] + } +} + host_unittest_action("EcmaStringTest") { module_out_path = module_output_path @@ -152,6 +179,33 @@ host_unittest_action("GlueRegsTest") { } } +host_unittest_action("JsArrayIteratorTest") { + module_out_path = module_output_path + + sources = [ + # test file + "js_array_iterator_test.cpp", + ] + + configs = [ + "//ark/js_runtime:ecma_test_config", + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_common_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + "$ark_root/libpandabase:libarkbase", + "//ark/js_runtime:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + if (!is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime" ] + } +} + host_unittest_action("JsArrayTest") { module_out_path = module_output_path @@ -179,6 +233,33 @@ host_unittest_action("JsArrayTest") { } } +host_unittest_action("JsDataViewTest") { + module_out_path = module_output_path + + sources = [ + # test file + "js_dataview_test.cpp", + ] + + configs = [ + "//ark/js_runtime:ecma_test_config", + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_common_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + "$ark_root/libpandabase:libarkbase", + "//ark/js_runtime:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + if (!is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime" ] + } +} + host_unittest_action("JsDateTest") { module_out_path = module_output_path @@ -448,6 +529,33 @@ host_unittest_action("JsProxyTest") { } } +host_unittest_action("JsSetIteratorTest") { + module_out_path = module_output_path + + sources = [ + # test file + "js_set_iterator_test.cpp", + ] + + configs = [ + "//ark/js_runtime:ecma_test_config", + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_common_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + "$ark_root/libpandabase:libarkbase", + "//ark/js_runtime:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + if (!is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime" ] + } +} + host_unittest_action("JsSetTest") { module_out_path = module_output_path @@ -475,6 +583,33 @@ host_unittest_action("JsSetTest") { } } +host_unittest_action("JsStringIteratorTest") { + module_out_path = module_output_path + + sources = [ + # test file + "js_string_iterator_test.cpp", + ] + + configs = [ + "//ark/js_runtime:ecma_test_config", + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_common_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + "$ark_root/libpandabase:libarkbase", + "//ark/js_runtime:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + if (!is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime" ] + } +} + host_unittest_action("JsSymbolTest") { module_out_path = module_output_path @@ -529,6 +664,33 @@ host_unittest_action("JsTaggedQueueTest") { } } +host_unittest_action("JsTypedArrayTest") { + module_out_path = module_output_path + + sources = [ + # test file + "js_typed_array_test.cpp", + ] + + configs = [ + "//ark/js_runtime:ecma_test_config", + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_common_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + "$ark_root/libpandabase:libarkbase", + "//ark/js_runtime:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + if (!is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime" ] + } +} + host_unittest_action("JsVerificationTest") { module_out_path = module_output_path @@ -583,6 +745,33 @@ host_unittest_action("HugeObjectTest") { } } +host_unittest_action("JsArgumentsTest") { + module_out_path = module_output_path + + sources = [ + # test file + "js_arguments_test.cpp", + ] + + configs = [ + "//ark/js_runtime:ecma_test_config", + "//ark/js_runtime:ark_jsruntime_public_config", # should add before + # arkruntime_public_config + "//ark/js_runtime:ark_jsruntime_config", + "$ark_root/runtime:arkruntime_public_config", + ] + + deps = [ + "$ark_root/libpandabase:libarkbase", + "//ark/js_runtime:libark_jsruntime_test", + sdk_libc_secshared_dep, + ] + + if (!is_standard_system) { + deps += [ "$ark_root/runtime:libarkruntime" ] + } +} + host_unittest_action("LexicalEnvTest") { module_out_path = module_output_path @@ -831,6 +1020,7 @@ host_unittest_action("GcTest") { sources = [ # test file + "concurrent_sweep_test.cpp", "gc_test.cpp", ] @@ -861,11 +1051,15 @@ group("unittest") { ":AssertScopeTest", ":BuiltinsTest", ":DumpTest", + ":EcmaModuleTest", ":EcmaStringTest", ":GcTest", ":GlueRegsTest", ":HugeObjectTest", + ":JsArgumentsTest", + ":JsArrayIteratorTest", ":JsArrayTest", + ":JsDataViewTest", ":JsDateTest", ":JsForinIteratorTest", ":JsFunctionTest", @@ -877,9 +1071,12 @@ group("unittest") { ":JsPromiseTest", ":JsProxyTest", ":JsSerializerTest", + ":JsSetIteratorTest", ":JsSetTest", + ":JsStringIteratorTest", ":JsSymbolTest", ":JsTaggedQueueTest", + ":JsTypedArrayTest", ":JsVerificationTest", ":LexicalEnvTest", ":LinkedHashTableTest", @@ -900,11 +1097,15 @@ group("host_unittest") { ":AssertScopeTestAction", ":BuiltinsTestAction", ":DumpTestAction", + ":EcmaModuleTestAction", ":EcmaStringTestAction", ":GcTestAction", ":GlueRegsTestAction", ":HugeObjectTestAction", + ":JsArgumentsTestAction", + ":JsArrayIteratorTestAction", ":JsArrayTestAction", + ":JsDataViewTestAction", ":JsDateTestAction", ":JsForinIteratorTestAction", ":JsFunctionTestAction", @@ -916,9 +1117,12 @@ group("host_unittest") { ":JsPromiseTestAction", ":JsProxyTestAction", ":JsSerializerTestAction", + ":JsSetIteratorTestAction", ":JsSetTestAction", + ":JsStringIteratorTestAction", ":JsSymbolTestAction", ":JsTaggedQueueTestAction", + ":JsTypedArrayTestAction", ":JsVerificationTestAction", ":LexicalEnvTestAction", ":LinkedHashTableTestAction", diff --git a/ecmascript/tests/concurrent_sweep_test.cpp b/ecmascript/tests/concurrent_sweep_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..6759428f34878ffb5e8e3043145ef54077f6bd4b --- /dev/null +++ b/ecmascript/tests/concurrent_sweep_test.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 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/tests/test_helper.h" + +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/js_handle.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class ConcurrentSweepTest : 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); + } + + PandaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread; +}; + +TEST_F(ConcurrentSweepTest, ConcurrentSweep) +{ + auto vm = EcmaVM::Cast(instance); + const uint8_t *utf8 = reinterpret_cast("test"); + JSHandle test1(thread, EcmaString::CreateFromUtf8(utf8, 4, vm, false)); + if (vm->IsInitialized()) { + vm->CollectGarbage(ecmascript::TriggerGCType::OLD_GC); + } + JSHandle test2(thread, EcmaString::CreateFromUtf8(utf8, 4, vm, false)); + ASSERT_EQ(test1->GetLength(), 4); + ASSERT_NE(test1.GetTaggedValue().GetHeapObject(), test2.GetTaggedValue().GetHeapObject()); +} +} // namespace panda::test diff --git a/ecmascript/tests/dump_test.cpp b/ecmascript/tests/dump_test.cpp index b7142c434353fb27693853ae5d8c74bd76a9500f..604f06b386e02f219527a2add9137cb51da3cba3 100644 --- a/ecmascript/tests/dump_test.cpp +++ b/ecmascript/tests/dump_test.cpp @@ -13,23 +13,72 @@ * limitations under the License. */ +#include "ecmascript/accessor_data.h" +#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/ecma_module.h" #include "ecmascript/ecma_vm.h" +#include "ecmascript/global_dictionary-inl.h" #include "ecmascript/global_env.h" +#include "ecmascript/hprof/heap_profiler.h" +#include "ecmascript/hprof/heap_profiler_interface.h" +#include "ecmascript/hprof/heap_snapshot.h" +#include "ecmascript/hprof/heap_snapshot_json_serializer.h" +#include "ecmascript/hprof/string_hashmap.h" +#include "ecmascript/ic/ic_handler.h" +#include "ecmascript/ic/proto_change_details.h" +#include "ecmascript/ic/property_box.h" +#include "ecmascript/jobs/micro_job_queue.h" +#include "ecmascript/jobs/pending_job.h" +#include "ecmascript/js_arguments.h" #include "ecmascript/js_array.h" +#include "ecmascript/js_array_iterator.h" +#include "ecmascript/js_arraybuffer.h" +#include "ecmascript/js_async_function.h" +#include "ecmascript/js_collator.h" +#include "ecmascript/js_dataview.h" #include "ecmascript/js_date.h" +#include "ecmascript/js_date_time_format.h" +#include "ecmascript/js_for_in_iterator.h" #include "ecmascript/js_function.h" +#include "ecmascript/js_function_extra_info.h" +#include "ecmascript/js_generator_object.h" +#include "ecmascript/js_global_object.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/js_intl.h" +#include "ecmascript/js_locale.h" #include "ecmascript/js_map.h" +#include "ecmascript/js_map_iterator.h" +#include "ecmascript/js_number_format.h" #include "ecmascript/js_object-inl.h" +#include "ecmascript/js_plural_rules.h" #include "ecmascript/js_primitive_ref.h" +#include "ecmascript/js_promise.h" +#include "ecmascript/js_realm.h" #include "ecmascript/js_regexp.h" +#include "ecmascript/js_relative_time_format.h" #include "ecmascript/js_set.h" +#include "ecmascript/js_set_iterator.h" +#include "ecmascript/js_string_iterator.h" +#include "ecmascript/js_tagged_number.h" #include "ecmascript/js_tagged_value-inl.h" #include "ecmascript/js_thread.h" +#include "ecmascript/js_typed_array.h" +#include "ecmascript/js_weak_container.h" +#include "ecmascript/layout_info-inl.h" +#include "ecmascript/lexical_env.h" #include "ecmascript/linked_hash_table-inl.h" +#include "ecmascript/mem/assert_scope-inl.h" +#include "ecmascript/mem/c_containers.h" +#include "ecmascript/mem/machine_code.h" #include "ecmascript/object_factory.h" +#include "ecmascript/tagged_array.h" +#include "ecmascript/tagged_dictionary.h" +#include "ecmascript/template_map.h" #include "ecmascript/tests/test_helper.h" +#include "ecmascript/transitions_dictionary.h" using namespace panda::ecmascript; +using namespace panda::ecmascript::base; namespace panda::test { class EcmaDumpTest : public testing::Test { @@ -77,4 +126,502 @@ HWTEST_F_L0(EcmaDumpTest, Dump) objFunc.Dump(jsThread); } #endif // #ifndef NDEBUG + +static JSHandle NewJSMap(JSThread *thread, ObjectFactory *factory, JSHandle proto) +{ + JSHandle mapClass = factory->NewEcmaDynClass(JSMap::SIZE, JSType::JS_MAP, proto); + JSHandle jsMap = JSHandle::Cast(factory->NewJSObject(mapClass)); + JSHandle linkedMap(thread, LinkedHashMap::Create(thread)); + jsMap->SetLinkedMap(thread, linkedMap); + return jsMap; +} + +static JSHandle NewJSSet(JSThread *thread, ObjectFactory *factory, JSHandle proto) +{ + JSHandle setClass = factory->NewEcmaDynClass(JSSet::SIZE, JSType::JS_SET, proto); + JSHandle jsSet = JSHandle::Cast(factory->NewJSObject(setClass)); + JSHandle linkedSet(thread, LinkedHashSet::Create(thread)); + jsSet->SetLinkedSet(thread, linkedSet); + return jsSet; +} + +static JSHandle NewJSObject(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv) +{ + JSFunction *jsFunc = globalEnv->GetObjectFunction().GetObject(); + JSHandle jsFunc1(thread, jsFunc); + JSHandle jsObj = factory->NewJSObjectByConstructor(JSHandle(jsFunc1), jsFunc1); + return jsObj; +} + +HWTEST_F_L0(EcmaDumpTest, HeapProfileDump) +{ + [[maybe_unused]] ecmascript::EcmaHandleScope scope(thread); + auto factory = thread->GetEcmaVM()->GetFactory(); + auto globalEnv = thread->GetEcmaVM()->GetGlobalEnv(); + auto globalConst = const_cast(thread->GlobalConstants()); + JSHandle proto = globalEnv->GetFunctionPrototype(); + std::vector> snapshotVector; + +#define DUMP_FOR_HANDLE(dumpHandle) \ + dumpHandle.GetTaggedValue().Dump(thread); \ + dumpHandle.GetTaggedValue().DumpForSnapshot(thread, snapshotVector); + +#define NEW_OBJECT_AND_DUMP(ClassName, TypeName) \ + JSHandle class##ClassName = \ + factory->NewEcmaDynClass(ClassName::SIZE, JSType::TypeName, proto); \ + JSHandle object##ClassName = factory->NewJSObject(class##ClassName); \ + object##ClassName.GetTaggedValue().Dump(thread); \ + object##ClassName.GetTaggedValue().DumpForSnapshot(thread, snapshotVector); + + for (JSType type = JSType::JS_OBJECT; type <= JSType::JS_TYPE_LAST; type = JSType(static_cast(type) + 1)) { + switch (type) { + case JSType::JS_ERROR: + case JSType::JS_EVAL_ERROR: + case JSType::JS_RANGE_ERROR: + case JSType::JS_TYPE_ERROR: + case JSType::JS_REFERENCE_ERROR: + case JSType::JS_URI_ERROR: + case JSType::JS_SYNTAX_ERROR: + case JSType::JS_OBJECT: { + CHECK_DUMP_FILEDS(ECMAObject::SIZE, JSObject::SIZE, 2) + JSHandle jsObj = NewJSObject(thread, factory, globalEnv); + DUMP_FOR_HANDLE(jsObj) + break; + } + case JSType::JS_REALM: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSRealm::SIZE, 2) + JSHandle jsRealm = factory->NewJSRealm(); + DUMP_FOR_HANDLE(jsRealm) + break; + } + case JSType::JS_FUNCTION_BASE: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSFunctionBase::SIZE, 1) + break; + } + case JSType::JS_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunctionBase::SIZE, JSFunction::SIZE, 7) + JSHandle jsFunc = globalEnv->GetFunctionFunction(); + DUMP_FOR_HANDLE(jsFunc) + break; + } + case JSType::JS_PROXY_REVOC_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSProxyRevocFunction::SIZE, 1) + JSHandle proxyRevocClass = + JSHandle::Cast(globalEnv->GetProxyRevocFunctionClass()); + JSHandle proxyRevocFunc = factory->NewJSObject(proxyRevocClass); + DUMP_FOR_HANDLE(proxyRevocFunc) + break; + } + case JSType::JS_PROMISE_REACTIONS_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSPromiseReactionsFunction::SIZE, 2) + JSHandle promiseReactClass = + JSHandle::Cast(globalEnv->GetPromiseReactionFunctionClass()); + JSHandle promiseReactFunc = factory->NewJSObject(promiseReactClass); + DUMP_FOR_HANDLE(promiseReactFunc) + break; + } + case JSType::JS_PROMISE_EXECUTOR_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSPromiseExecutorFunction::SIZE, 1) + JSHandle promiseExeClass = + JSHandle::Cast(globalEnv->GetPromiseExecutorFunctionClass()); + JSHandle promiseExeFunc = factory->NewJSObject(promiseExeClass); + DUMP_FOR_HANDLE(promiseExeFunc) + break; + } + case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSPromiseAllResolveElementFunction::SIZE, 5) + JSHandle promiseAllClass = + JSHandle::Cast(globalEnv->GetPromiseAllResolveElementFunctionClass()); + JSHandle promiseAllFunc = factory->NewJSObject(promiseAllClass); + DUMP_FOR_HANDLE(promiseAllFunc) + break; + } + case JSType::JS_GENERATOR_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSGeneratorFunction::SIZE, 0) + break; + } + case JSType::JS_ASYNC_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSAsyncFunction::SIZE, 0) + break; + } + case JSType::JS_INTL_BOUND_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSIntlBoundFunction::SIZE, 3) + JSHandle intlBoundFunc = factory->NewJSIntlBoundFunction(); + DUMP_FOR_HANDLE(intlBoundFunc) + break; + } + case JSType::JS_ASYNC_AWAIT_STATUS_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunction::SIZE, JSAsyncAwaitStatusFunction::SIZE, 1) + JSHandle asyncAwaitFunc = factory->NewJSAsyncAwaitStatusFunction(); + DUMP_FOR_HANDLE(asyncAwaitFunc) + break; + } + case JSType::JS_BOUND_FUNCTION: { + CHECK_DUMP_FILEDS(JSFunctionBase::SIZE, JSBoundFunction::SIZE, 3) + NEW_OBJECT_AND_DUMP(JSBoundFunction, JS_BOUND_FUNCTION) + break; + } + case JSType::JS_REG_EXP: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSRegExp::SIZE, 5) + NEW_OBJECT_AND_DUMP(JSRegExp, JS_REG_EXP) + break; + } + case JSType::JS_SET: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSSet::SIZE, 1) + JSHandle jsSet = NewJSSet(thread, factory, proto); + DUMP_FOR_HANDLE(jsSet) + break; + } + case JSType::JS_MAP: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSMap::SIZE, 1) + JSHandle jsMap = NewJSMap(thread, factory, proto); + DUMP_FOR_HANDLE(jsMap) + break; + } + case JSType::JS_WEAK_MAP: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSWeakMap::SIZE, 1) + JSHandle weakMapClass = factory->NewEcmaDynClass(JSWeakMap::SIZE, JSType::JS_WEAK_MAP, proto); + JSHandle jsWeakMap = JSHandle::Cast(factory->NewJSObject(weakMapClass)); + JSHandle weakLinkedMap(thread, LinkedHashMap::Create(thread)); + jsWeakMap->SetLinkedMap(thread, weakLinkedMap); + DUMP_FOR_HANDLE(jsWeakMap) + break; + } + case JSType::JS_WEAK_SET: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSWeakSet::SIZE, 1) + JSHandle weakSetClass = factory->NewEcmaDynClass(JSWeakSet::SIZE, JSType::JS_WEAK_SET, proto); + JSHandle jsWeakSet = JSHandle::Cast(factory->NewJSObject(weakSetClass)); + JSHandle weakLinkedSet(thread, LinkedHashSet::Create(thread)); + jsWeakSet->SetLinkedSet(thread, weakLinkedSet); + DUMP_FOR_HANDLE(jsWeakSet) + break; + } + case JSType::JS_DATE: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSDate::SIZE, 2) + JSHandle dateClass = factory->NewEcmaDynClass(JSDate::SIZE, JSType::JS_DATE, proto); + JSHandle date = JSHandle::Cast(factory->NewJSObject(dateClass)); + date->SetTimeValue(thread, JSTaggedValue(0.0)); + date->SetLocalOffset(thread, JSTaggedValue(0.0)); + DUMP_FOR_HANDLE(date) + break; + } + case JSType::JS_ITERATOR: + // JS Iterate is a tool class, so we don't need to check it. + break; + case JSType::JS_FORIN_ITERATOR: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSForInIterator::SIZE, 4) + JSHandle array(thread, factory->NewJSArray().GetTaggedValue()); + JSHandle forInIter = factory->NewJSForinIterator(array); + DUMP_FOR_HANDLE(forInIter) + break; + } + case JSType::JS_MAP_ITERATOR: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSMapIterator::SIZE, 3) + JSHandle jsMapIter = + factory->NewJSMapIterator(NewJSMap(thread, factory, proto), IterationKind::KEY); + DUMP_FOR_HANDLE(jsMapIter) + break; + } + case JSType::JS_SET_ITERATOR: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSSetIterator::SIZE, 3) + JSHandle jsSetIter = + factory->NewJSSetIterator(NewJSSet(thread, factory, proto), IterationKind::KEY); + DUMP_FOR_HANDLE(jsSetIter) + break; + } + case JSType::JS_ARRAY_ITERATOR: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSArrayIterator::SIZE, 3) + JSHandle arrayIter = + factory->NewJSArrayIterator(JSHandle::Cast(factory->NewJSArray()), IterationKind::KEY); + DUMP_FOR_HANDLE(arrayIter) + break; + } + case JSType::JS_STRING_ITERATOR: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSStringIterator::SIZE, 2) + JSHandle stringIter = globalEnv->GetStringIterator(); + DUMP_FOR_HANDLE(stringIter) + break; + } + case JSType::JS_INTL: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSIntl::SIZE, 1) + NEW_OBJECT_AND_DUMP(JSIntl, JS_INTL) + break; + } + case JSType::JS_LOCALE: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSLocale::SIZE, 1) + NEW_OBJECT_AND_DUMP(JSLocale, JS_LOCALE) + break; + } + case JSType::JS_DATE_TIME_FORMAT: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSDateTimeFormat::SIZE, 11) + NEW_OBJECT_AND_DUMP(JSDateTimeFormat, JS_DATE_TIME_FORMAT) + break; + } + case JSType::JS_RELATIVE_TIME_FORMAT: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSRelativeTimeFormat::SIZE, 7) + NEW_OBJECT_AND_DUMP(JSRelativeTimeFormat, JS_RELATIVE_TIME_FORMAT) + break; + } + case JSType::JS_NUMBER_FORMAT: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSNumberFormat::SIZE, 20) + NEW_OBJECT_AND_DUMP(JSNumberFormat, JS_NUMBER_FORMAT) + break; + } + case JSType::JS_COLLATOR: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSCollator::SIZE, 9) + NEW_OBJECT_AND_DUMP(JSCollator, JS_COLLATOR) + break; + } + case JSType::JS_PLURAL_RULES: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSPluralRules::SIZE, 11) + NEW_OBJECT_AND_DUMP(JSPluralRules, JS_PLURAL_RULES) + break; + } + case JSType::JS_ARRAY_BUFFER: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSArrayBuffer::SIZE, 3) + NEW_OBJECT_AND_DUMP(JSArrayBuffer, JS_ARRAY_BUFFER) + break; + } + case JSType::JS_PROMISE: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSPromise::SIZE, 5) + NEW_OBJECT_AND_DUMP(JSPromise, JS_PROMISE) + break; + } + case JSType::JS_DATA_VIEW: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSDataView::SIZE, 4) + NEW_OBJECT_AND_DUMP(JSDataView, JS_DATA_VIEW) + break; + } + case JSType::JS_ARGUMENTS: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSArguments::SIZE, 1) + NEW_OBJECT_AND_DUMP(JSArguments, JS_ARGUMENTS) + break; + } + case JSType::JS_GENERATOR_OBJECT: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSGeneratorObject::SIZE, 4) + NEW_OBJECT_AND_DUMP(JSGeneratorObject, JS_GENERATOR_OBJECT) + break; + } + case JSType::JS_ASYNC_FUNC_OBJECT: { + CHECK_DUMP_FILEDS(JSGeneratorObject::SIZE, JSAsyncFuncObject::SIZE, 1) + JSHandle asyncFuncObject = factory->NewJSAsyncFuncObject(); + DUMP_FOR_HANDLE(asyncFuncObject) + break; + } + case JSType::JS_ARRAY: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSArray::SIZE, 1) + JSHandle jsArray = factory->NewJSArray(); + DUMP_FOR_HANDLE(jsArray) + break; + } + case JSType::JS_TYPED_ARRAY: + case JSType::JS_INT8_ARRAY: + case JSType::JS_UINT8_ARRAY: + case JSType::JS_UINT8_CLAMPED_ARRAY: + case JSType::JS_INT16_ARRAY: + case JSType::JS_UINT16_ARRAY: + case JSType::JS_INT32_ARRAY: + case JSType::JS_UINT32_ARRAY: + case JSType::JS_FLOAT32_ARRAY: + case JSType::JS_FLOAT64_ARRAY: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSTypedArray::SIZE, 5) + NEW_OBJECT_AND_DUMP(JSTypedArray, JS_TYPED_ARRAY) + break; + } + case JSType::JS_PRIMITIVE_REF: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSPrimitiveRef::SIZE, 1) + NEW_OBJECT_AND_DUMP(JSPrimitiveRef, JS_PRIMITIVE_REF) + break; + } + case JSType::JS_GLOBAL_OBJECT: { + CHECK_DUMP_FILEDS(JSObject::SIZE, JSGlobalObject::SIZE, 0) + JSHandle globalObject = globalEnv->GetJSGlobalObject(); + DUMP_FOR_HANDLE(globalObject) + break; + } + case JSType::JS_PROXY: { + CHECK_DUMP_FILEDS(ECMAObject::SIZE, JSProxy::SIZE, 3) + JSHandle emptyObj(thread, NewJSObject(thread, factory, globalEnv).GetTaggedValue()); + JSHandle proxy = factory->NewJSProxy(emptyObj, emptyObj); + DUMP_FOR_HANDLE(proxy) + break; + } + case JSType::HCLASS: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), JSHClass::SIZE, 9) + JSHandle hclass = factory->NewEcmaDynClass(JSHClass::SIZE, JSType::HCLASS, proto); + DUMP_FOR_HANDLE(hclass) + break; + } + case JSType::STRING: { + DUMP_FOR_HANDLE(globalEnv->GetObjectFunction()) + break; + } + case JSType::TAGGED_ARRAY: { + JSHandle taggedArray = factory->NewTaggedArray(4); + DUMP_FOR_HANDLE(taggedArray) + break; + } + case JSType::TAGGED_DICTIONARY: { + JSHandle dict = factory->NewDictionaryArray(4); + DUMP_FOR_HANDLE(dict) + break; + } + case JSType::FREE_OBJECT_WITH_ONE_FIELD: + case JSType::FREE_OBJECT_WITH_NONE_FIELD: + case JSType::FREE_OBJECT_WITH_TWO_FIELD: + { + break; + } + case JSType::JS_NATIVE_POINTER: { + break; + } + case JSType::GLOBAL_ENV: { + DUMP_FOR_HANDLE(globalEnv) + break; + } + case JSType::ACCESSOR_DATA: + case JSType::INTERNAL_ACCESSOR: { + CHECK_DUMP_FILEDS(Record::SIZE, AccessorData::SIZE, 2) + JSHandle accessor = factory->NewAccessorData(); + DUMP_FOR_HANDLE(accessor) + break; + } + case JSType::SYMBOL: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), JSSymbol::SIZE, 3) + JSHandle symbol = factory->NewJSSymbol(); + DUMP_FOR_HANDLE(symbol) + break; + } + case JSType::JS_GENERATOR_CONTEXT: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), GeneratorContext::SIZE, 7) + JSHandle genContext = factory->NewGeneratorContext(); + DUMP_FOR_HANDLE(genContext) + break; + } + case JSType::PROTOTYPE_HANDLER: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), PrototypeHandler::SIZE, 3) + JSHandle protoHandler = factory->NewPrototypeHandler(); + DUMP_FOR_HANDLE(protoHandler) + break; + } + case JSType::TRANSITION_HANDLER: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), TransitionHandler::SIZE, 2) + JSHandle transitionHandler = factory->NewTransitionHandler(); + DUMP_FOR_HANDLE(transitionHandler) + break; + } + case JSType::PROPERTY_BOX: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), PropertyBox::SIZE, 1) + JSHandle PropertyBox = factory->NewPropertyBox(globalEnv->GetEmptyArray()); + DUMP_FOR_HANDLE(PropertyBox) + break; + } + case JSType::PROTO_CHANGE_MARKER: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ProtoChangeMarker::SIZE, 1) + JSHandle protoMaker = factory->NewProtoChangeMarker(); + DUMP_FOR_HANDLE(protoMaker) + break; + } + case JSType::PROTOTYPE_INFO: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), ProtoChangeDetails::SIZE, 2) + JSHandle protoDetails = factory->NewProtoChangeDetails(); + DUMP_FOR_HANDLE(protoDetails) + break; + } + case JSType::TEMPLATE_MAP: { + JSHandle templateMap = globalEnv->GetTemplateMap(); + DUMP_FOR_HANDLE(templateMap) + break; + } + case JSType::PROGRAM: { + CHECK_DUMP_FILEDS(ECMAObject::SIZE, Program::SIZE, 5) + JSHandle program = factory->NewProgram(); + DUMP_FOR_HANDLE(program) + break; + } + case JSType::LEXICAL_FUNCTION: { + CHECK_DUMP_FILEDS(ECMAObject::SIZE, LexicalFunction::SIZE, 5) + // unused + break; + } + case JSType::PROMISE_CAPABILITY: { + CHECK_DUMP_FILEDS(Record::SIZE, PromiseCapability::SIZE, 3) + JSHandle promiseCapa = factory->NewPromiseCapability(); + DUMP_FOR_HANDLE(promiseCapa) + break; + } + case JSType::PROMISE_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, PromiseRecord::SIZE, 1) + JSHandle promiseRecord = factory->NewPromiseRecord(); + DUMP_FOR_HANDLE(promiseRecord) + break; + } + case JSType::RESOLVING_FUNCTIONS_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, ResolvingFunctionsRecord::SIZE, 2) + JSHandle ResolvingFunc = factory->NewResolvingFunctionsRecord(); + DUMP_FOR_HANDLE(ResolvingFunc) + break; + } + case JSType::PROMISE_REACTIONS: { + CHECK_DUMP_FILEDS(Record::SIZE, PromiseReaction::SIZE, 3) + JSHandle promiseReact = factory->NewPromiseReaction(); + DUMP_FOR_HANDLE(promiseReact) + break; + } + case JSType::PROMISE_ITERATOR_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, PromiseIteratorRecord::SIZE, 2) + JSHandle emptyObj(thread, NewJSObject(thread, factory, globalEnv).GetTaggedValue()); + JSHandle promiseIter = factory->NewPromiseIteratorRecord(emptyObj, emptyObj); + DUMP_FOR_HANDLE(promiseIter) + break; + } + case JSType::MICRO_JOB_QUEUE: { + CHECK_DUMP_FILEDS(Record::SIZE, ecmascript::job::MicroJobQueue::SIZE, 2) + JSHandle microJob = factory->NewMicroJobQueue(); + DUMP_FOR_HANDLE(microJob) + break; + } + case JSType::PENDING_JOB: { + CHECK_DUMP_FILEDS(Record::SIZE, ecmascript::job::PendingJob::SIZE, 2) + JSHandle pendingClass(thread, + JSHClass::Cast(globalConst->GetPendingJobClass().GetTaggedObject())); + JSHandle pendingJob(thread, factory->NewDynObject(pendingClass)); + DUMP_FOR_HANDLE(pendingJob) + break; + } + case JSType::FUNCTION_EXTRA_INFO: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), JSFunctionExtraInfo::SIZE, 2) + JSHandle funcExtraClass(thread, + JSHClass::Cast(globalConst->GetFunctionExtraInfoClass().GetTaggedObject())); + JSHandle funcInfo(thread, factory->NewDynObject(funcExtraClass)); + DUMP_FOR_HANDLE(funcInfo) + break; + } + case JSType::COMPLETION_RECORD: { + CHECK_DUMP_FILEDS(Record::SIZE, CompletionRecord::SIZE, 2) + JSHandle comRecord = factory->NewCompletionRecord(0, globalEnv->GetEmptyArray()); + DUMP_FOR_HANDLE(comRecord) + break; + } + case JSType::MACHINE_CODE_OBJECT: { + CHECK_DUMP_FILEDS(TaggedObject::TaggedObjectSize(), MachineCode::DATA_OFFSET, 1) + JSHandle machineCode = factory->NewMachineCodeObject(16, nullptr); + DUMP_FOR_HANDLE(machineCode) + break; + } + case JSType::ECMA_MODULE: { + CHECK_DUMP_FILEDS(ECMAObject::SIZE, EcmaModule::SIZE, 1) + JSHandle ecmaModule = factory->NewEmptyEcmaModule(); + DUMP_FOR_HANDLE(ecmaModule) + break; + } + default: + LOG_ECMA_MEM(ERROR) << "JSType " << static_cast(type) << " cannot be dumped."; + UNREACHABLE(); + break; + } + } +#undef NEW_OBJECT_AND_DUMP +#undef DUMP_FOR_HANDLE +} } // namespace panda::test diff --git a/ecmascript/tests/ecma_module_test.cpp b/ecmascript/tests/ecma_module_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..c0c924d0a4c5c79392b0903bc0acf78aaa8141ce --- /dev/null +++ b/ecmascript/tests/ecma_module_test.cpp @@ -0,0 +1,548 @@ +/* + * Copyright (c) 2021 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/ecma_module.h" +#include "ecmascript/global_env.h" +#include "ecmascript/js_locale.h" +#include "ecmascript/tagged_dictionary.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class EcmaModuleTest : 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); + } + PandaVM *instance {nullptr}; + ecmascript::EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +EcmaModule *EcmaModuleCreate(JSThread *thread) +{ + ObjectFactory *objectFactory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleEcmaModule = objectFactory->NewEmptyEcmaModule(); + return *handleEcmaModule; +} + +/* + * Feature: EcmaModule + * Function: AddItem + * SubFunction: GetItem + * FunctionPoints: Add Item To EcmaModule + * CaseDescription: Add an item for a EcmaModule that has called "SetNameDictionary" function in the HWTEST_F_L0, and + * check its value through 'GetItem' function. + */ +HWTEST_F_L0(EcmaModuleTest, AddItem_001) +{ + int numOfElementsDict = 4; + CString cStrItemName = "key1"; + int intItemValue = 1; + JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); + JSHandle handleNameDict(thread, NameDictionary::Create(thread, numOfElementsDict)); + JSHandle handleTagValItemName( + thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName)); + JSHandle handleTagValItemValue(thread, JSTaggedValue(intItemValue)); + + handleEcmaModule->SetNameDictionary(thread, handleNameDict); // Call SetNameDictionary in HWTEST_F_L0 + EcmaModule::AddItem(thread, handleEcmaModule, handleTagValItemName, handleTagValItemValue); + EXPECT_EQ(handleEcmaModule->GetItem(thread, handleTagValItemName)->GetNumber(), intItemValue); +} + +/* + * Feature: EcmaModule + * Function: AddItem + * SubFunction: GetItem + * FunctionPoints: Add Item To EcmaModule + * CaseDescription: Add an item for a EcmaModule that has not called "SetNameDictionary" function in the HWTEST_F_L0, + * and check its value through 'GetItem' function. + */ +HWTEST_F_L0(EcmaModuleTest, AddItem_002) +{ + CString cStrItemName = "cStrItemName"; + int intItemValue = 1; + JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); + JSHandle handleTagValItemName( + thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName)); + JSHandle handleTagValItemValue(thread, JSTaggedValue(intItemValue)); + + // This EcmaModule calls 'SetNameDictionary' function through 'AddItem' function of "ecma_module.cpp". + EcmaModule::AddItem(thread, handleEcmaModule, handleTagValItemName, handleTagValItemValue); + EXPECT_EQ(handleEcmaModule->GetItem(thread, handleTagValItemName)->GetNumber(), intItemValue); +} + +/* + * Feature: EcmaModule + * Function: RemoveItem + * SubFunction: AddItem/GetItem + * FunctionPoints: Remove Item From EcmaModule + * CaseDescription: Add an item for an empty EcmaModule through 'AddItem' function, then remove the item from the + * EcmaModule through 'RemoveItem' function, finally check whether the item obtained from the + * EcmaModule through 'GetItem' function is undefined. + */ +HWTEST_F_L0(EcmaModuleTest, RemoveItem) +{ + ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); + + CString cStrItemName = "cStrItemName"; + int intItemValue = 1; + JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); + JSHandle handleTagValItemName(objFactory->NewFromCanBeCompressString(cStrItemName)); + JSHandle handleTagValItemValue(thread, JSTaggedValue(intItemValue)); + + EcmaModule::AddItem(thread, handleEcmaModule, handleTagValItemName, handleTagValItemValue); + EcmaModule::RemoveItem(thread, handleEcmaModule, handleTagValItemName); + EXPECT_TRUE(handleEcmaModule->GetItem(thread, handleTagValItemName)->IsUndefined()); +} + +/* + * Feature: EcmaModule + * Function: SetNameDictionary + * SubFunction: NameDictionary::Put/GetNameDictionary + * FunctionPoints: Set NameDictionary For EcmaModule + * CaseDescription: Create a source key, a source value, a source NameDictionary and a target EcmaModule, change the + * NameDictionary through 'NameDictionary::Put' function, set the changed source NameDictionary as + * this target EcmaModule's NameDictionary through 'SetNameDictionary' function, check whether the + * result returned through 'GetNameDictionary' function from the target EcmaModule are within + * expectations. + */ +HWTEST_F_L0(EcmaModuleTest, SetNameDictionary) +{ + ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); + + int numOfElementsDict = 4; + JSHandle handleNameDict(thread, NameDictionary::Create(thread, numOfElementsDict)); + JSHandle handleObjFunc = thread->GetEcmaVM()->GetGlobalEnv()->GetObjectFunction(); + CString keyArray1 = "hello1"; + JSHandle stringKey1 = objFactory->NewFromCanBeCompressString(keyArray1); + JSHandle key1(stringKey1); + JSHandle value1(objFactory + ->NewJSObjectByConstructor(JSHandle(handleObjFunc), handleObjFunc)); + JSHandle handleNameDictionaryFrom(thread, + NameDictionary::Put(thread, handleNameDict, key1, value1, PropertyAttributes::Default())); + JSHandle handleEcmaModule(thread, EcmaModuleCreate(thread)); + + handleEcmaModule->SetNameDictionary(thread, handleNameDictionaryFrom); + JSHandle handleNameDictionaryTo(thread, + NameDictionary::Cast(handleEcmaModule->GetNameDictionary().GetTaggedObject())); + EXPECT_EQ(handleNameDictionaryTo->EntriesCount(), 1); + int entry1 = handleNameDictionaryTo->FindEntry(key1.GetTaggedValue()); + EXPECT_TRUE(key1.GetTaggedValue() == handleNameDictionaryTo->GetKey(entry1)); + EXPECT_TRUE(value1.GetTaggedValue() == handleNameDictionaryTo->GetValue(entry1)); +} + +/* + * Feature: ModuleManager + * Function: AddModule + * SubFunction: AddItem/GetModule/GetItem + * FunctionPoints: Add EcmaModule To ModuleManager + * CaseDescription: Create 2 source EcmaModules that both add an item, create a ModuleManager that add the 2 source + * EcmaModule, check whether the items of EcmaModules obtained from the ModuleManager through + * 'GetModule' function and 'GetItem' function are within expectations. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleManager_AddModule) +{ + ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + + int numOfElementsDict1 = 4; + int numOfElementsDict2 = 4; + CString cStrItemName1 = "cStrItemName1"; + CString cStrItemName2 = "cStrItemName2"; + int intItemValue1 = 1; + int intItemValue2 = 2; + JSHandle handleNameDict1(thread, NameDictionary::Create(thread, numOfElementsDict1)); + JSHandle handleNameDict2(thread, NameDictionary::Create(thread, numOfElementsDict2)); + JSHandle handleItemName1( + thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName1)); + JSHandle handleItemName2( + thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(cStrItemName2)); + JSHandle handleItemValue1(thread, JSTaggedValue(intItemValue1)); + JSHandle handleItemValue2(thread, JSTaggedValue(intItemValue2)); + JSHandle handleEcmaModuleAddFrom1(thread, EcmaModuleCreate(thread)); + JSHandle handleEcmaModuleAddFrom2(thread, EcmaModuleCreate(thread)); + handleEcmaModuleAddFrom1->SetNameDictionary(thread, handleNameDict1); + handleEcmaModuleAddFrom2->SetNameDictionary(thread, handleNameDict2); + + EcmaModule::AddItem(thread, handleEcmaModuleAddFrom1, handleItemName1, handleItemValue1); + JSHandle handleTagValEcmaModuleAddFrom1(thread, handleEcmaModuleAddFrom1.GetTaggedValue()); + std::string stdStrNameEcmaModuleAdd1 = "NameEcmaModule1"; + JSHandle handleTagValNameEcmaModuleAdd1(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd1)); + EcmaModule::AddItem(thread, handleEcmaModuleAddFrom2, handleItemName2, handleItemValue2); + JSHandle handleTagValEcmaModuleAddFrom2(thread, handleEcmaModuleAddFrom2.GetTaggedValue()); + std::string stdStrNameEcmaModuleAdd2 = "NameEcmaModule2"; + JSHandle handleTagValNameEcmaModuleAdd2(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd2)); + + moduleManager->AddModule(handleTagValNameEcmaModuleAdd1, handleTagValEcmaModuleAddFrom1); + moduleManager->AddModule(handleTagValNameEcmaModuleAdd2, handleTagValEcmaModuleAddFrom2); + JSHandle handleTagValEcmaModuleGet1 = moduleManager->GetModule(thread, + handleTagValNameEcmaModuleAdd1); + JSHandle handleTagValEcmaModuleGet2 = moduleManager->GetModule(thread, + handleTagValNameEcmaModuleAdd2); + EXPECT_EQ(JSHandle::Cast(handleTagValEcmaModuleGet1)->GetItem(thread, handleItemName1)->GetNumber(), + intItemValue1); + EXPECT_EQ(JSHandle::Cast(handleTagValEcmaModuleGet2)->GetItem(thread, handleItemName2)->GetNumber(), + intItemValue2); +} + +/* + * Feature: ModuleManager + * Function: RemoveModule + * SubFunction: AddItem/GetModule/AddModule/GetItem + * FunctionPoints: Remove EcmaModule From ModuleManager + * CaseDescription: Create two source EcmaModules that add different items, create a ModuleManager that add the two + * source EcmaModules, check whether the properties of the EcmaModules obtained from the ModuleManager + * through 'GetModule' function are within expectations while removing EcmaModules from the + * ModuleManager through 'RemoveModule' function one by one. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleManager_RemoveModule) +{ + ObjectFactory* objFactory = thread->GetEcmaVM()->GetFactory(); + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + + std::string stdStrNameEcmaModuleAdd1 = "NameEcmaModule1"; + std::string stdStrNameEcmaModuleAdd2 = "NameEcmaModule2"; + int intItemValue1 = 1; + int intItemValue2 = 2; + int numOfElementsDict1 = 4; + int numOfElementsDict2 = 4; + JSHandle handleTagValNameEcmaModuleAdd1(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd1)); + JSHandle handleTagValNameEcmaModuleAdd2(objFactory->NewFromStdString(stdStrNameEcmaModuleAdd2)); + JSHandle handleTagValItemName1(objFactory->NewFromCanBeCompressString("name1")); + JSHandle handleTagValItemName2(objFactory->NewFromCanBeCompressString("name2")); + JSHandle handleTagValItemValue1(thread, JSTaggedValue(intItemValue1)); + JSHandle handleTagValItemValue2(thread, JSTaggedValue(intItemValue2)); + JSHandle handleEcmaModuleAddFrom1(thread, EcmaModuleCreate(thread)); + JSHandle handleEcmaModuleAddFrom2(thread, EcmaModuleCreate(thread)); + JSHandle handleNameDict1(thread, NameDictionary::Create(thread, numOfElementsDict1)); + JSHandle handleNameDict2(thread, NameDictionary::Create(thread, numOfElementsDict2)); + handleEcmaModuleAddFrom1->SetNameDictionary(thread, handleNameDict1); + handleEcmaModuleAddFrom2->SetNameDictionary(thread, handleNameDict2); + EcmaModule::AddItem(thread, handleEcmaModuleAddFrom1, handleTagValItemName1, handleTagValItemValue1); + EcmaModule::AddItem(thread, handleEcmaModuleAddFrom2, handleTagValItemName2, handleTagValItemValue2); + JSHandle handleTaggedValueEcmaModuleAddFrom1(thread, handleEcmaModuleAddFrom1.GetTaggedValue()); + JSHandle handleTaggedValueEcmaModuleAddFrom2(thread, handleEcmaModuleAddFrom2.GetTaggedValue()); + + moduleManager->AddModule(handleTagValNameEcmaModuleAdd1, handleTaggedValueEcmaModuleAddFrom1); + moduleManager->AddModule(handleTagValNameEcmaModuleAdd2, handleTaggedValueEcmaModuleAddFrom2); + EXPECT_EQ(JSHandle::Cast(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd1)) + ->GetItem(thread, handleTagValItemName1)->GetNumber(), intItemValue1); + EXPECT_EQ(JSHandle::Cast(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd2)) + ->GetItem(thread, handleTagValItemName2)->GetNumber(), intItemValue2); + + moduleManager->RemoveModule(handleTagValNameEcmaModuleAdd1); + EXPECT_TRUE(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd1)->IsUndefined()); + EXPECT_EQ(JSHandle::Cast(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd2)) + ->GetItem(thread, handleTagValItemName2)->GetNumber(), intItemValue2); + + moduleManager->RemoveModule(handleTagValNameEcmaModuleAdd2); + EXPECT_TRUE(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd1)->IsUndefined()); + EXPECT_TRUE(moduleManager->GetModule(thread, handleTagValNameEcmaModuleAdd2)->IsUndefined()); +} + +/* + * Feature: ModuleManager + * Function: SetCurrentExportModuleName + * SubFunction: GetCurrentExportModuleName + * FunctionPoints: Get Current ExportModuleName Of ModuleManager + * CaseDescription: Create a ModuleManager, check whether the ExportModuleName obtained from the ModuleManager through + * 'GetCurrentExportModuleName' function is within expectations while changing the Current + * ExportModuleName of the ModuleManager through 'SetCurrentExportModuleName' function. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleManager_SetCurrentExportModuleName) +{ + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + + std::string_view strViewNameEcmaModule1 = "NameEcmaModule1"; + std::string_view strViewNameEcmaModule2 = "NameEcmaModule2"; + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule1); + EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule1).c_str()); + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule2); + EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule2).c_str()); +} + +/* + * Feature: ModuleManager + * Function: GetPrevExportModuleName + * SubFunction: SetCurrentExportModuleName + * FunctionPoints: Get Previous ExportModuleName Of ModuleManager + * CaseDescription: Create a ModuleManager, check whether the previous ExportModuleName obtained from the ModuleManager + * through 'GetPrevExportModuleName' function is within expectations while changing the Current + * ExportModuleName of the ModuleManager through 'SetCurrentExportModuleName' function. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleManager_GetPrevExportModuleName) +{ + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + + std::string_view strViewNameEcmaModule1 = "NameEcmaModule1"; + std::string_view strViewNameEcmaModule2 = "NameEcmaModule2"; + std::string_view strViewNameEcmaModule3 = "NameEcmaModule3"; + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule1); + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule2); + EXPECT_STREQ(moduleManager->GetPrevExportModuleName().c_str(), CString(strViewNameEcmaModule1).c_str()); + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule3); + EXPECT_STREQ(moduleManager->GetPrevExportModuleName().c_str(), CString(strViewNameEcmaModule2).c_str()); +} + +/* + * Feature: ModuleManager + * Function: RestoreCurrentExportModuleName + * SubFunction: SetCurrentExportModuleName/GetCurrentExportModuleName + * FunctionPoints: Restore Current ExportModuleName Of ModuleManager + * CaseDescription: Create a ModuleManager, check whether the current ExportModuleName obtained from the ModuleManager + * through 'GetCurrentExportModuleName' function is within expectations while changing the Current + * ExportModuleName of the ModuleManager through 'SetCurrentExportModuleName' function and + * 'RestoreCurrentExportModuleName' function. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleManager_RestoreCurrentExportModuleName) +{ + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + + std::string_view strViewNameEcmaModule1 = "NameEcmaModule1"; + std::string_view strViewNameEcmaModule2 = "NameEcmaModule2"; + std::string_view strViewNameEcmaModule3 = "NameEcmaModule3"; + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule1); + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule2); + moduleManager->SetCurrentExportModuleName(strViewNameEcmaModule3); + EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule3).c_str()); + moduleManager->RestoreCurrentExportModuleName(); + EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule2).c_str()); + moduleManager->RestoreCurrentExportModuleName(); + EXPECT_STREQ(moduleManager->GetCurrentExportModuleName().c_str(), CString(strViewNameEcmaModule1).c_str()); +} + +/* + * Feature: ModuleManager + * Function: AddModuleItem + * SubFunction: SetCurrentExportModuleName/GetModule/GetModuleItem + * FunctionPoints: Add ModuleItem For Current EcmaModule Of ModuleManager + * CaseDescription: Create a ModuleManager, set the current EcmaModule for the ModuleManager through + * 'SetCurrentExportModuleName' function, add source ModuleItems for the current EcmaModule Of the + * ModuleManager, check whether the ModuleItems obtained through 'GetModuleItem' function from the + * ModuleManager are within expectations. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleManager_AddModuleItem) +{ + ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory(); + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + + int intItemValue11 = 11; + int intItemValue12 = 12; + int intItemValue21 = 21; + int intItemValue22 = 22; + JSHandle handleTagValItemName11(objFactory->NewFromCanBeCompressString("cStrItemName11")); + JSHandle handleTagValItemName12(objFactory->NewFromCanBeCompressString("cStrItemName12")); + JSHandle handleTagValItemName21(objFactory->NewFromCanBeCompressString("cStrItemName21")); + JSHandle handleTagValItemName22(objFactory->NewFromCanBeCompressString("cStrItemName22")); + JSHandle handleTagValItemValue11(thread, JSTaggedValue(intItemValue11)); + JSHandle handleTagValItemValue12(thread, JSTaggedValue(intItemValue12)); + JSHandle handleTagValItemValue21(thread, JSTaggedValue(intItemValue21)); + JSHandle handleTagValItemValue22(thread, JSTaggedValue(intItemValue22)); + JSHandle handleEcmaStrNameEcmaModule1 = objFactory->NewFromString("cStrNameEcmaModule1"); + JSHandle handleEcmaStrNameEcmaModule2 = objFactory->NewFromString("cStrNameEcmaModule2"); + std::string stdStrModuleFileName1 = JSLocale::ConvertToStdString(handleEcmaStrNameEcmaModule1); + std::string stdStrModuleFileName2 = JSLocale::ConvertToStdString(handleEcmaStrNameEcmaModule2); + JSHandle handleTagValEcmaModuleName1(handleEcmaStrNameEcmaModule1); + JSHandle handleTagValEcmaModuleName2(handleEcmaStrNameEcmaModule2); + + // Test when the module is created through 'NewEmptyEcmaModule' function called at HWTEST_F_L0. + JSHandle handleEcmaModule1(thread, EcmaModuleCreate(thread)); + JSHandle handleTagValEcmaModule1(thread, handleEcmaModule1.GetTaggedValue()); + moduleManager->AddModule(handleTagValEcmaModuleName1, handleTagValEcmaModule1); + moduleManager->SetCurrentExportModuleName(stdStrModuleFileName1); + moduleManager->AddModuleItem(thread, handleTagValItemName11, handleTagValItemValue11); + moduleManager->AddModuleItem(thread, handleTagValItemName12, handleTagValItemValue12); + + EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName11)->GetNumber(), + intItemValue11); + EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName12)->GetNumber(), + intItemValue12); + + // Test when the module is created through 'NewEmptyEcmaModule' function called at "ecma_module.cpp". + moduleManager->SetCurrentExportModuleName(stdStrModuleFileName2); + moduleManager->AddModuleItem(thread, handleTagValItemName21, handleTagValItemValue21); + moduleManager->AddModuleItem(thread, handleTagValItemName22, handleTagValItemValue22); + + JSHandle handleTagValEcmaModule2 = moduleManager->GetModule(thread, handleTagValEcmaModuleName2); + EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName11)->GetNumber(), + intItemValue11); + EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule1, handleTagValItemName12)->GetNumber(), + intItemValue12); + EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule2, handleTagValItemName21)->GetNumber(), + intItemValue21); + EXPECT_EQ(moduleManager->GetModuleItem(thread, handleTagValEcmaModule2, handleTagValItemName22)->GetNumber(), + intItemValue22); +} + +/* + * Feature: ModuleManager + * Function: CopyModule + * SubFunction: AddItem/SetCurrentExportModuleName/GetModule/GetModuleItem + * FunctionPoints: Copy EcmaModule To ModuleManager + * CaseDescription: Create two source EcmaModules and one target ModuleManager, prepare the two source EcmaModules + * through 'AddItem' function, check whether the the ModuleItems obtained through 'GetModuleItem' from + * the target ModuleManager are within expectations while changing the target ModuleManager through + * 'SetCurrentExportModuleName' function and 'CopyModule' function. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleManager_CopyModule) +{ + ObjectFactory *objFactory = thread->GetEcmaVM()->GetFactory(); + ModuleManager *moduleManager = thread->GetEcmaVM()->GetModuleManager(); + + int intItemValue11 = 11; + int intItemValue12 = 12; + int intItemValue21 = 21; + int intItemValue22 = 22; + std::string_view fileNameEcmaModuleCopyTo1 = "fileNameEcmaModuleCopyTo1"; + std::string_view fileNameEcmaModuleCopyTo2 = "fileNameEcmaModuleCopyTo2"; + JSHandle handleTagValItemName11(objFactory->NewFromCanBeCompressString("ItemName11")); + JSHandle handleTagValItemName12(objFactory->NewFromCanBeCompressString("ItemName12")); + JSHandle handleTagValItemName21(objFactory->NewFromCanBeCompressString("ItemName21")); + JSHandle handleTagValItemName22(objFactory->NewFromCanBeCompressString("ItemName22")); + JSHandle handleTagValItemValue11(thread, JSTaggedValue(intItemValue11)); + JSHandle handleTagValItemValue12(thread, JSTaggedValue(intItemValue12)); + JSHandle handleTagValItemValue21(thread, JSTaggedValue(intItemValue21)); + JSHandle handleTagValItemValue22(thread, JSTaggedValue(intItemValue22)); + JSHandle handleEcmaModuleCopyFrom1(thread, EcmaModuleCreate(thread)); + JSHandle handleEcmaModuleCopyFrom2(thread, EcmaModuleCreate(thread)); + JSHandle handleTagValEcmaModuleCopyFrom1(thread, handleEcmaModuleCopyFrom1.GetTaggedValue()); + JSHandle handleTagValEcmaModuleCopyFrom2(thread, handleEcmaModuleCopyFrom2.GetTaggedValue()); + EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom1, handleTagValItemName11, handleTagValItemValue11); + EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom1, handleTagValItemName12, handleTagValItemValue12); + EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom2, handleTagValItemName21, handleTagValItemValue21); + EcmaModule::AddItem(thread, handleEcmaModuleCopyFrom2, handleTagValItemName22, handleTagValItemValue22); + + moduleManager->SetCurrentExportModuleName(fileNameEcmaModuleCopyTo1); + moduleManager->CopyModule(thread, handleTagValEcmaModuleCopyFrom1); + JSHandle handleTagValEcmaModuleCopyTo1 = moduleManager->GetModule(thread, + JSHandle::Cast(objFactory->NewFromString(CString(fileNameEcmaModuleCopyTo1)))); + EXPECT_EQ(intItemValue11, + moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName11)->GetNumber()); + EXPECT_EQ(intItemValue12, + moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName12)->GetNumber()); + + moduleManager->SetCurrentExportModuleName(fileNameEcmaModuleCopyTo2); + moduleManager->CopyModule(thread, handleTagValEcmaModuleCopyFrom2); + JSHandle handleTagValEcmaModuleCopyTo2 = moduleManager->GetModule(thread, + JSHandle::Cast(objFactory->NewFromString(CString(fileNameEcmaModuleCopyTo2)))); + EXPECT_EQ(intItemValue11, + moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName11)->GetNumber()); + EXPECT_EQ(intItemValue12, + moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo1, handleTagValItemName12)->GetNumber()); + EXPECT_EQ(intItemValue21, + moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo2, handleTagValItemName21)->GetNumber()); + EXPECT_EQ(intItemValue22, + moduleManager->GetModuleItem(thread, handleTagValEcmaModuleCopyTo2, handleTagValItemName22)->GetNumber()); +} + +// ModuleStack +/* + * Feature: ModuleStack + * Function: PushModule + * SubFunction: GetTop + * FunctionPoints: Push EcmaModule By Name + * CaseDescription: Create a target ModuleStack, push a source EcmaModule name at the back of the name vector of the + * target ModuleStack, check whether the returned EcmaModule name obtained through 'GetTop' function + * from the target ModuleStack is the same with the source EcmaModule name. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleStack_PushModule) +{ + ModuleStack moduleStack; + + CString cStrPushNo1 = "cStrPushNo1"; + CString cStrPushNo2 = "cStrPushNo2"; + CString cStrPushNo3 = "cStrPushNo3"; + moduleStack.PushModule(cStrPushNo1); + EXPECT_STREQ(moduleStack.GetTop().c_str(), cStrPushNo1.c_str()); + moduleStack.PushModule(cStrPushNo2); + EXPECT_STREQ(moduleStack.GetTop().c_str(), cStrPushNo2.c_str()); + moduleStack.PushModule(cStrPushNo3); + EXPECT_STREQ(moduleStack.GetTop().c_str(), cStrPushNo3.c_str()); +} + +/* + * Feature: ModuleStack + * Function: PopModule + * SubFunction: PushModule/GetTop + * FunctionPoints: Pop EcmaModule At The Back + * CaseDescription: Create a target ModuleStack, push some source EcmaModule names at the back of the name vector of + * the target ModuleStack, check whether the returned EcmaModule name obtained through 'GetTop' + * function from the target ModuleStack now and the returned EcmaModule name obtained through 'GetTop' + * function from the target ModuleStack after the target ModuleStack calls 'PopModule' function are + * within expectations. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleStack_PopModule) +{ + ModuleStack moduleStack; + + CString cStrPushNo1 = "cStrPushNo1"; + CString cStrPushNo2 = "cStrPushNo2"; + CString cStrPushNo3 = "cStrPushNo3"; + moduleStack.PushModule(cStrPushNo1); + moduleStack.PushModule(cStrPushNo2); + moduleStack.PushModule(cStrPushNo3); + EXPECT_STREQ(moduleStack.GetTop().c_str(), cStrPushNo3.c_str()); + moduleStack.PopModule(); + EXPECT_STREQ(moduleStack.GetTop().c_str(), cStrPushNo2.c_str()); + moduleStack.PopModule(); + EXPECT_STREQ(moduleStack.GetTop().c_str(), cStrPushNo1.c_str()); + moduleStack.PopModule(); +} + +/* + * Feature: ModuleStack + * Function: GetPrevModule + * SubFunction: PushModule/GetTop/PopModule + * FunctionPoints: Get Previous Module + * CaseDescription: Create a target ModuleStack, push some source EcmaModule names at the back of the name vector of + * the target ModuleStack, check whether the returned EcmaModule name obtained through 'GetPrevModule' + * function from the target ModuleStack now and the returned EcmaModule name obtained through + * 'GetPrevModule' function from the target ModuleStack after the target ModuleStack calls 'PushModule' + * function or 'PopModule' function are within expectations. + */ +HWTEST_F_L0(EcmaModuleTest, ModuleStack_GetPrevModule) +{ + ModuleStack moduleStack; + + CString cStrPushNo1 = "cStrPushNo1"; + CString cStrPushNo2 = "cStrPushNo2"; + CString cStrPushNo3 = "cStrPushNo3"; + moduleStack.PushModule(cStrPushNo1); + moduleStack.PushModule(cStrPushNo2); + EXPECT_STREQ(moduleStack.GetPrevModule().c_str(), cStrPushNo1.c_str()); + moduleStack.PushModule(cStrPushNo3); + EXPECT_STREQ(moduleStack.GetPrevModule().c_str(), cStrPushNo2.c_str()); + moduleStack.PopModule(); + EXPECT_STREQ(moduleStack.GetPrevModule().c_str(), cStrPushNo1.c_str()); +} +} // namespace panda::ecmascript diff --git a/ecmascript/tests/ecma_string_test.cpp b/ecmascript/tests/ecma_string_test.cpp index 5a1a29ae3a98be877192e822caee700119db1505..1feedb777d9cb68d92e10aca779a9f5c993c7446 100644 --- a/ecmascript/tests/ecma_string_test.cpp +++ b/ecmascript/tests/ecma_string_test.cpp @@ -26,7 +26,7 @@ public: GTEST_LOG_(INFO) << "SetUpTestCase"; } - static void TesrDownTestCase() + static void TearDownTestCase() { GTEST_LOG_(INFO) << "TearDownCase"; } @@ -81,9 +81,9 @@ HWTEST_F_L0(EcmaStringTest, CreateEmptyString) EXPECT_FALSE(ecmaStrEmptyPtr->IsUtf16()); EcmaString::SetCompressedStringsEnabled(false); // Set compressedStringsEnabled false. - EcmaString *ecmaStrEmptyNotCompPtr = EcmaString::CreateEmptyString(ecmaVMPtr); - EXPECT_EQ(ecmaStrEmptyNotCompPtr->GetLength(), 0); - EXPECT_TRUE(ecmaStrEmptyNotCompPtr->IsUtf16()); + EcmaString *ecmaStrEmptyDisableCompPtr = EcmaString::CreateEmptyString(ecmaVMPtr); + EXPECT_EQ(ecmaStrEmptyDisableCompPtr->GetLength(), 0); + EXPECT_TRUE(ecmaStrEmptyDisableCompPtr->IsUtf16()); EcmaString::SetCompressedStringsEnabled(true); // Set compressedStringsEnabled true(default). } @@ -111,7 +111,8 @@ HWTEST_F_L0(EcmaStringTest, AllocStringObject) EXPECT_FALSE(ecmaStrAllocNotCompPtr->IsUtf8()); EXPECT_TRUE(ecmaStrAllocNotCompPtr->IsUtf16()); EcmaString::SetCompressedStringsEnabled(false); // Set compressedStringsEnabled false. - EXPECT_TRUE(ecmaStrAllocNotCompPtr->IsUtf16()); + EcmaString *ecmaStrAllocNotCompDisableCompPtr = EcmaString::AllocStringObject(sizeAllocNotComp, false, ecmaVMPtr); + EXPECT_TRUE(ecmaStrAllocNotCompDisableCompPtr->IsUtf16()); EcmaString::SetCompressedStringsEnabled(true); // Set compressedStringsEnabled true(default). } @@ -151,7 +152,9 @@ HWTEST_F_L0(EcmaStringTest, CreateFromUtf16) EXPECT_FALSE(ecmaStrU16NotCompPtr->IsUtf8()); EXPECT_TRUE(ecmaStrU16NotCompPtr->IsUtf16()); EcmaString::SetCompressedStringsEnabled(false); // Set compressedStringsEnabled false. - EXPECT_TRUE(ecmaStrU16NotCompPtr->IsUtf16()); + EcmaString *ecmaStrU16NotCompDisableCompPtr = EcmaString::CreateFromUtf16(&arrayU16NotComp[0], + lengthEcmaStrU16NotComp, ecmaVMPtr, false); + EXPECT_TRUE(ecmaStrU16NotCompDisableCompPtr->IsUtf16()); EcmaString::SetCompressedStringsEnabled(true); // Set compressedStringsEnabled true(default). } @@ -1244,7 +1247,9 @@ HWTEST_F_L0(EcmaStringTest, GetHashcode_003) EXPECT_EQ(ecmaStrU16NotCompPtr->GetHashcode(), static_cast(hashExpect)); EcmaString::SetCompressedStringsEnabled(false); // Set compressedStringsEnabled false. - EXPECT_EQ(ecmaStrU16NotCompPtr->GetHashcode(), static_cast(hashExpect)); + EcmaString *ecmaStrU16NotCompDisableCompPtr = EcmaString::CreateFromUtf16(&arrayU16NotComp[0], + lengthEcmaStrU16NotComp, ecmaVMPtr, false); + EXPECT_EQ(ecmaStrU16NotCompDisableCompPtr->GetHashcode(), static_cast(hashExpect)); EcmaString::SetCompressedStringsEnabled(true); // Set compressedStringsEnabled true(default). } @@ -1257,8 +1262,8 @@ HWTEST_F_L0(EcmaStringTest, GetHashcode_004) EXPECT_EQ(ecmaStrEmptyPtr->GetHashcode(), 0); EcmaString::SetCompressedStringsEnabled(false); // Set compressedStringsEnabled false. - EcmaString *ecmaStrNotCompEmptyPtr = EcmaString::CreateEmptyString(ecmaVMPtr); - EXPECT_EQ(ecmaStrNotCompEmptyPtr->GetHashcode(), 0); + EcmaString *ecmaStrEmptyDisableCompPtr = EcmaString::CreateEmptyString(ecmaVMPtr); + EXPECT_EQ(ecmaStrEmptyDisableCompPtr->GetHashcode(), 0); EcmaString::SetCompressedStringsEnabled(true); // Set compressedStringsEnabled true(default). } @@ -1274,7 +1279,8 @@ HWTEST_F_L0(EcmaStringTest, GetHashcode_005) EXPECT_EQ(ecmaStrAllocNotCompPtr->GetHashcode(), 0); EcmaString::SetCompressedStringsEnabled(false); // Set compressedStringsEnabled false. - EXPECT_EQ(ecmaStrAllocNotCompPtr->GetHashcode(), 0); + EcmaString *ecmaStrAllocNotCompDisableCompPtr = EcmaString::AllocStringObject(sizeAlloc, false, ecmaVMPtr); + EXPECT_EQ(ecmaStrAllocNotCompDisableCompPtr->GetHashcode(), 0); EcmaString::SetCompressedStringsEnabled(true); // Set compressedStringsEnabled true(default). } } // namespace panda::ecmascript diff --git a/ecmascript/tests/gc_test.cpp b/ecmascript/tests/gc_test.cpp index bece8eee7f97c335f28b1cf6f6f3c113141c20a8..3ba0b6fc4af667d145202ccedae0b7625c2001ee 100644 --- a/ecmascript/tests/gc_test.cpp +++ b/ecmascript/tests/gc_test.cpp @@ -38,7 +38,7 @@ public: void SetUp() override { - RuntimeOptions options; + JSRuntimeOptions options; options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetBootClassSpaces({"ecmascript"}); diff --git a/ecmascript/tests/js_arguments_test.cpp b/ecmascript/tests/js_arguments_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..5e5f06d8e6f47e4a74d13596d175810cb17b89e4 --- /dev/null +++ b/ecmascript/tests/js_arguments_test.cpp @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2021 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/js_arguments.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/js_handle.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class JsArgumentsTest : 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); + } + ecmascript::EcmaHandleScope *scope {nullptr}; + PandaVM *instance {nullptr}; + JSThread *thread {nullptr}; +}; + +static JSFunction *JSObjectTestCreate(JSThread *thread) +{ + EcmaVM *ecmaVM = thread->GetEcmaVM(); + JSHandle globalEnv = ecmaVM->GetGlobalEnv(); + return globalEnv->GetObjectFunction().GetObject(); +} + +HWTEST_F_L0(JsArgumentsTest, SetProperty) +{ + JSHandle argFunc(thread, JSObjectTestCreate(thread)); + JSHandle jsarg = + thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle(argFunc), argFunc); + JSHandle arg = thread->GetEcmaVM()->GetFactory()->NewJSArguments(); + + char array[] = "x"; + JSHandle key(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(array)); + JSHandle value(thread, JSTaggedValue(1)); + + // receive must be jsarg's conversion + JSHandle receiver = JSHandle::Cast(jsarg); + EXPECT_TRUE(JSArguments::SetProperty(thread, arg, key, value, receiver)); + EXPECT_EQ(JSObject::GetProperty(thread, JSHandle(jsarg), key).GetValue()->GetInt(), 1); + EXPECT_EQ(JSArguments::GetProperty(thread, jsarg, key).GetValue()->GetInt(), 1); + + JSHandle value2(thread, JSTaggedValue(2)); + EXPECT_TRUE(JSArguments::SetProperty(thread, arg, key, value2, receiver)); + EXPECT_EQ(JSObject::GetProperty(thread, JSHandle(jsarg), key).GetValue()->GetInt(), 2); + EXPECT_EQ(JSArguments::GetProperty(thread, jsarg, key).GetValue()->GetInt(), 2); +} + +HWTEST_F_L0(JsArgumentsTest, GetProperty) +{ + JSHandle argFunc(thread, JSObjectTestCreate(thread)); + JSHandle jsarg = + thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle(argFunc), argFunc); + JSHandle arg = thread->GetEcmaVM()->GetFactory()->NewJSArguments(); + + char array[] = "x"; + JSHandle key(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(array)); + JSHandle value(thread, JSTaggedValue(1)); + + JSHandle receiver = JSHandle::Cast(jsarg); + JSArguments::SetProperty(thread, arg, key, value, receiver); + EXPECT_EQ(JSObject::GetProperty(thread, JSHandle(jsarg), key).GetValue()->GetInt(), 1); + EXPECT_EQ(JSArguments::GetProperty(thread, JSHandle(jsarg), key, receiver).GetValue()->GetInt(), 1); + + JSHandle value2(thread, JSTaggedValue(2)); + JSArguments::SetProperty(thread, arg, key, value2, receiver); + EXPECT_EQ(JSArguments::GetProperty(thread, jsarg, key).GetValue()->GetInt(), 2); + EXPECT_EQ(JSObject::GetProperty(thread, JSHandle(jsarg), key).GetValue()->GetInt(), 2); +} + +HWTEST_F_L0(JsArgumentsTest, DeleteProperty) +{ + JSHandle argFunc(thread, JSObjectTestCreate(thread)); + JSHandle jsarg = + thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle(argFunc), argFunc); + JSHandle arg = thread->GetEcmaVM()->GetFactory()->NewJSArguments(); + + char array[] = "delete"; + JSHandle key(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString(array)); + JSHandle value(thread, JSTaggedValue(1)); + JSHandle receiver = JSHandle::Cast(jsarg); + JSArguments::SetProperty(thread, arg, key, value, receiver); + EXPECT_EQ(JSArguments::GetProperty(thread, jsarg, key).GetValue()->GetInt(), 1); + + // test delete + bool result = JSArguments::DeleteProperty(thread, JSHandle(jsarg), key); + EXPECT_TRUE(result); + EXPECT_TRUE(JSObject::GetProperty(thread, JSHandle(jsarg), key).GetValue()->IsUndefined()); +} + +HWTEST_F_L0(JsArgumentsTest, DefineOwnProperty) +{ + JSHandle argFunc(thread, JSObjectTestCreate(thread)); + JSHandle jsarg = + thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle(argFunc), argFunc); + JSHandle arg = thread->GetEcmaVM()->GetFactory()->NewJSArguments(); + + JSHandle key(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("x")); + JSHandle value1(thread, JSTaggedValue(1)); + JSHandle value2(thread, JSTaggedValue(2)); + JSHandle receiver = JSHandle::Cast(jsarg); + JSArguments::SetProperty(thread, arg, key, value2, receiver); + EXPECT_EQ(JSObject::GetProperty(thread, JSHandle(jsarg), key).GetValue()->GetInt(), 2); + + PropertyDescriptor Desc(thread); + // set value1 + Desc.SetValue(value1); + Desc.SetWritable(false); + EXPECT_TRUE(JSArguments::DefineOwnProperty(thread, JSHandle(jsarg), key, Desc)); + EXPECT_EQ(JSObject::GetProperty(thread, JSHandle(jsarg), key).GetValue()->GetInt(), 1); +} + +HWTEST_F_L0(JsArgumentsTest, GetOwnProperty) +{ + JSHandle argFunc(thread, JSObjectTestCreate(thread)); + JSHandle jsarg = + thread->GetEcmaVM()->GetFactory()->NewJSObjectByConstructor(JSHandle(argFunc), argFunc); + JSHandle arg = thread->GetEcmaVM()->GetFactory()->NewJSArguments(); + + JSHandle key(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("x")); + JSHandle value(thread, JSTaggedValue(1)); + JSHandle receiver = JSHandle::Cast(jsarg); + JSArguments::SetProperty(thread, arg, key, value, receiver); + + PropertyDescriptor Desc(thread); + JSHandle caller = thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("caller"); + // key is not caller + EXPECT_FALSE(JSTaggedValue::SameValue(key.GetTaggedValue(), caller.GetTaggedValue())); + EXPECT_TRUE(JSArguments::GetOwnProperty(thread, JSHandle(jsarg), key, Desc)); + EXPECT_EQ(Desc.GetValue()->GetInt(), 1); +} +} // namespace panda::test diff --git a/ecmascript/tests/js_array_iterator_test.cpp b/ecmascript/tests/js_array_iterator_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..74f768c69a6a6aaaf4d1b29aa6737fe89745bb43 --- /dev/null +++ b/ecmascript/tests/js_array_iterator_test.cpp @@ -0,0 +1,178 @@ +/* + * Copyright (c) 2021 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/global_env.h" +#include "ecmascript/js_array_iterator.h" +#include "ecmascript/js_array.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class JSArrayIteratorTest : 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); + } + PandaVM *instance {nullptr}; + ecmascript::EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +/* + * Feature: JSArrayIterator + * Function: SetIteratedArray + * SubFunction: GetIteratedArray + * FunctionPoints: Set Iterated Array + * CaseDescription: Call the "SetIteratedArray" function, check whether the result returned through "GetIteratedArray" + * function from the JSArrayIterator is within expectations. + */ +HWTEST_F_L0(JSArrayIteratorTest, SetIteratedArray) +{ + EcmaVM *ecmaVMPtr = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVMPtr->GetFactory(); + + uint32_t arrayFrom1[10] = {0, 6, 8, 99, 200, 1, -1, -199, 33, 100}; + uint32_t arrayFrom2[10] = {1111, 3211, 737, 0, 1267, 174, 2763, 832, 11, 93}; + int numArrayFrom1 = sizeof(arrayFrom1)/sizeof(arrayFrom1[0]); + int numArrayFrom2 = sizeof(arrayFrom2)/sizeof(arrayFrom2[0]); + JSHandle handleTaggedArrayFrom1(factory->NewTaggedArray(numArrayFrom1)); + JSHandle handleTaggedArrayFrom2(factory->NewTaggedArray(numArrayFrom2)); + for (int i = 0; i < numArrayFrom1; i++) { + handleTaggedArrayFrom1->Set(thread, i, JSTaggedValue(arrayFrom1[i])); + } + for (int i = 0; i < numArrayFrom2; i++) { + handleTaggedArrayFrom2->Set(thread, i, JSTaggedValue(arrayFrom2[i])); + } + JSHandle handleJSObjectTaggedArrayFrom1(JSArray::CreateArrayFromList(thread, handleTaggedArrayFrom1)); + JSHandle handleJSObjectTaggedArrayFrom2(JSArray::CreateArrayFromList(thread, handleTaggedArrayFrom2)); + + // Call "SetIteratedArray" function through "NewJSArrayIterator" function of "object_factory.cpp". + JSHandle handleJSArrayIter = factory->NewJSArrayIterator(handleJSObjectTaggedArrayFrom1, + IterationKind::KEY); + + JSHandle handleJSArrayTo1(thread, JSArray::Cast(handleJSArrayIter->GetIteratedArray().GetTaggedObject())); + EXPECT_EQ(handleJSArrayTo1->GetArrayLength(), numArrayFrom1); + for (int i = 0; i < numArrayFrom1; i++) { + EXPECT_EQ(JSArray::FastGetPropertyByValue(thread, JSHandle(handleJSArrayTo1), i)->GetNumber(), + arrayFrom1[i]); + } + + // Call "SetIteratedArray" function in this HWTEST_F_L0. + handleJSArrayIter->SetIteratedArray(thread, handleJSObjectTaggedArrayFrom2); + + JSHandle handleJSArrayTo2(thread, JSArray::Cast(handleJSArrayIter->GetIteratedArray().GetTaggedObject())); + EXPECT_EQ(handleJSArrayTo2->GetArrayLength(), numArrayFrom2); + for (int i = 0; i < numArrayFrom2; i++) { + EXPECT_EQ(JSArray::FastGetPropertyByValue(thread, JSHandle(handleJSArrayTo2), i)->GetNumber(), + arrayFrom2[i]); + } +} + +/* + * Feature: JSArrayIterator + * Function: SetNextIndex + * SubFunction: GetNextIndex + * FunctionPoints: Set Next Index + * CaseDescription: Call the "SetNextIndex" function, check whether the result returned through "GetNextIndex" function + * from the JSArrayIterator is within expectations. + */ +HWTEST_F_L0(JSArrayIteratorTest, SetNextIndex) +{ + EcmaVM *ecmaVMPtr = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVMPtr->GetFactory(); + + uint32_t array[10] = {0, 6, 8, 99, 200, 1, -1, -199, 33, 100}; + int numArray = sizeof(array)/sizeof(array[0]); + JSHandle handleTaggedArray(factory->NewTaggedArray(numArray)); + for (int i = 0; i < numArray; i++) { + handleTaggedArray->Set(thread, i, JSTaggedValue(array[i])); + } + JSHandle handleJSObjectTaggedArray(JSArray::CreateArrayFromList(thread, handleTaggedArray)); + + // Call "SetNextIndex" function through "NewJSArrayIterator" function of "object_factory.cpp". + JSHandle handleJSArrayIter = factory->NewJSArrayIterator(handleJSObjectTaggedArray, + IterationKind::KEY); + EXPECT_EQ(handleJSArrayIter->GetNextIndex().GetNumber(), 0); + + int testQuantity = 100; + for (int i = 1; i <= testQuantity; i++) { + JSHandle handleTagValNextIndex(thread, JSTaggedValue(i)); + + // Call "SetNextIndex" function in this HWTEST_F_L0. + handleJSArrayIter->SetNextIndex(thread, handleTagValNextIndex); + EXPECT_EQ(handleJSArrayIter->GetNextIndex().GetNumber(), i); + } +} + +/* + * Feature: JSArrayIterator + * Function: SetIterationKind + * SubFunction: GetIterationKind + * FunctionPoints: Set Iteration Kind + * CaseDescription: Call the "SetIterationKind" function, check whether the result returned through "GetIterationKind" + * function from the JSArrayIterator is within expectations. + */ +HWTEST_F_L0(JSArrayIteratorTest, SetIterationKind) +{ + EcmaVM *ecmaVMPtr = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVMPtr->GetFactory(); + + uint32_t array[10] = {0, 6, 8, 99, 200, 1, -1, -199, 33, 100}; + int numArray = sizeof(array)/sizeof(array[0]); + JSHandle handleTaggedArray(factory->NewTaggedArray(numArray)); + for (int i = 0; i < numArray; i++) { + handleTaggedArray->Set(thread, i, JSTaggedValue(array[i])); + } + JSHandle handleTagVal0(thread, JSTaggedValue(0)); + JSHandle handleTagVal1(thread, JSTaggedValue(1)); + JSHandle handleTagVal2(thread, JSTaggedValue(2)); + JSHandle handleJSObjectTaggedArray(JSArray::CreateArrayFromList(thread, handleTaggedArray)); + + // Call "SetIterationKind" function through "NewJSArrayIterator" function of "object_factory.cpp". + JSHandle handleJSArrayIter = factory->NewJSArrayIterator(handleJSObjectTaggedArray, + IterationKind::KEY); + EXPECT_EQ(handleJSArrayIter->GetIterationKind().GetNumber(), 0); + handleJSArrayIter = factory->NewJSArrayIterator(handleJSObjectTaggedArray, IterationKind::VALUE); + EXPECT_EQ(handleJSArrayIter->GetIterationKind().GetNumber(), 1); + handleJSArrayIter = factory->NewJSArrayIterator(handleJSObjectTaggedArray, IterationKind::KEY_AND_VALUE); + EXPECT_EQ(handleJSArrayIter->GetIterationKind().GetNumber(), 2); + + // Call "SetIterationKind" function in this HWTEST_F_L0. + handleJSArrayIter->SetIterationKind(thread, handleTagVal0); + EXPECT_EQ(handleJSArrayIter->GetIterationKind().GetNumber(), 0); + handleJSArrayIter->SetIterationKind(thread, handleTagVal1); + EXPECT_EQ(handleJSArrayIter->GetIterationKind().GetNumber(), 1); + handleJSArrayIter->SetIterationKind(thread, handleTagVal2); + EXPECT_EQ(handleJSArrayIter->GetIterationKind().GetNumber(), 2); +} +} // namespace panda::ecmascript diff --git a/ecmascript/tests/js_dataview_test.cpp b/ecmascript/tests/js_dataview_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..2c15663205ac8e5bdc0b4fd282a87b08371b4f11 --- /dev/null +++ b/ecmascript/tests/js_dataview_test.cpp @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2021 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/global_env.h" +#include "ecmascript/js_arraybuffer.h" +#include "ecmascript/js_dataview.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class JSDataViewTest : 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); + } + PandaVM *instance {nullptr}; + ecmascript::EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +/* + * Feature: JSDataView + * Function: GetElementSize + * SubFunction: N/A + * FunctionPoints: Get ElementSize + * CaseDescription: Check whether the returned value through "GetElementSize" function is within expectations. + */ +HWTEST_F_L0(JSDataViewTest, GetElementSize) +{ + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::INT8), 1); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::UINT8), 1); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::UINT8_CLAMPED), 1); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::INT16), 2); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::UINT16), 2); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::INT32), 4); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::UINT32), 4); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::FLOAT32), 4); + EXPECT_EQ(JSDataView::GetElementSize(DataViewType::FLOAT64), 8); +} + +/* + * Feature: JSDataView + * Function: SetDataView + * SubFunction: GetDataView + * FunctionPoints: Set DataView + * CaseDescription: Check whether the returned value through "GetDataView" function is within expectations after + * calling "SetDataView" function. + */ +HWTEST_F_L0(JSDataViewTest, SetDataView) +{ + EcmaVM *ecmaVMPtr = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVMPtr->GetFactory(); + JSHandle handleGlobalEnv = ecmaVMPtr->GetGlobalEnv(); + + int32_t lengthDataArrayBuf = 8; + int32_t offsetDataView = 4; + int32_t lengthDataView = 4; + JSHandle handleFuncArrayBuf(handleGlobalEnv->GetArrayBufferFunction()); + JSHandle handleTagValFuncArrayBuf(handleFuncArrayBuf); + JSHandle handleArrayBuf( + factory->NewJSObjectByConstructor(handleFuncArrayBuf, handleTagValFuncArrayBuf)); + handleArrayBuf->SetArrayBufferByteLength(thread, JSTaggedValue(lengthDataArrayBuf)); + + // Call "SetDataView" function through "NewJSDataView" function of "object_factory.cpp" + JSHandle handleDataView = factory->NewJSDataView(handleArrayBuf, offsetDataView, + lengthDataView); + EXPECT_TRUE(handleDataView->GetDataView().IsTrue()); + + // Call "SetDataView" function in this HWTEST_F_L0. + handleDataView->SetDataView(thread, JSTaggedValue::False()); + EXPECT_TRUE(handleDataView->GetDataView().IsFalse()); + handleDataView->SetDataView(thread, JSTaggedValue::True()); + EXPECT_TRUE(handleDataView->GetDataView().IsTrue()); +} + +/* + * Feature: JSDataView + * Function: SetViewedArrayBuffer + * SubFunction: GetViewedArrayBuffer + * FunctionPoints: Set ViewedArrayBuffer + * CaseDescription: Check whether the returned value through "GetViewedArrayBuffer" function is within expectations + * after calling "SetViewedArrayBuffer" function. + */ +HWTEST_F_L0(JSDataViewTest, SetViewedArrayBuffer) +{ + EcmaVM *ecmaVMPtr = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVMPtr->GetFactory(); + JSHandle handleFuncArrayBuf(ecmaVMPtr->GetGlobalEnv()->GetArrayBufferFunction()); + JSHandle handleTagValFuncArrayBuf(handleFuncArrayBuf); + + int32_t lengthDataArrayBuf1 = 8; + int32_t lengthDataArrayBuf2 = 16; + int32_t offsetDataView = 4; + int32_t lengthDataView = 4; + JSHandle handleArrayBuf1( + factory->NewJSObjectByConstructor(handleFuncArrayBuf, handleTagValFuncArrayBuf)); + JSHandle handleArrayBuf2( + factory->NewJSObjectByConstructor(handleFuncArrayBuf, handleTagValFuncArrayBuf)); + handleArrayBuf1->SetArrayBufferByteLength(thread, JSTaggedValue(lengthDataArrayBuf1)); + handleArrayBuf2->SetArrayBufferByteLength(thread, JSTaggedValue(lengthDataArrayBuf2)); + + // Call "SetViewedArrayBuffer" function through "NewJSDataView" function of "object_factory.cpp" + JSHandle handleDataView = factory->NewJSDataView(handleArrayBuf1, offsetDataView, + lengthDataView); + JSHandle handleTagValDataViewFrom1(thread, handleArrayBuf1.GetTaggedValue()); + JSHandle handleTagValDataViewTo1(thread, handleDataView->GetViewedArrayBuffer()); + EXPECT_TRUE(JSTaggedValue::Equal(thread, handleTagValDataViewFrom1, handleTagValDataViewTo1)); + + // Call "SetViewedArrayBuffer" function in this HWTEST_F_L0. + handleDataView->SetViewedArrayBuffer(thread, handleArrayBuf2.GetTaggedValue()); + JSHandle handleTagValDataViewFrom2(thread, handleArrayBuf2.GetTaggedValue()); + JSHandle handleTagValDataViewTo2(thread, handleDataView->GetViewedArrayBuffer()); + EXPECT_TRUE(JSTaggedValue::Equal(thread, handleTagValDataViewFrom2, handleTagValDataViewTo2)); + EXPECT_FALSE(JSTaggedValue::Equal(thread, handleTagValDataViewFrom1, handleTagValDataViewFrom2)); +} + +/* + * Feature: JSDataView + * Function: SetByteLength + * SubFunction: GetByteLength + * FunctionPoints: Set ByteLength + * CaseDescription: Check whether the returned value through "GetByteLength" function is within expectations after + * calling "SetByteLength" function. + */ +HWTEST_F_L0(JSDataViewTest, SetByteLength) +{ + EcmaVM *ecmaVMPtr = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVMPtr->GetFactory(); + JSHandle handleFuncArrayBuf(ecmaVMPtr->GetGlobalEnv()->GetArrayBufferFunction()); + JSHandle handleTagValFuncArrayBuf(handleFuncArrayBuf); + + int32_t lengthDataArrayBuf = 8; + int32_t offsetDataView = 4; + int32_t lengthDataView1 = 4; + int32_t lengthDataView2 = 2; + JSHandle handleTagValLengthDataView2(thread, JSTaggedValue(lengthDataView2)); + JSHandle handleArrayBuf( + factory->NewJSObjectByConstructor(handleFuncArrayBuf, handleTagValFuncArrayBuf)); + handleArrayBuf->SetArrayBufferByteLength(thread, JSTaggedValue(lengthDataArrayBuf)); + + // Call "SetByteLength" function through "NewJSDataView" function of "object_factory.cpp" + JSHandle handleDataView = factory->NewJSDataView(handleArrayBuf, offsetDataView, + lengthDataView1); + EXPECT_EQ(handleDataView->GetByteLength().GetNumber(), lengthDataView1); + + // Call "SetByteLength" function in this HWTEST_F_L0. + handleDataView->SetByteLength(thread, handleTagValLengthDataView2); + EXPECT_EQ(handleDataView->GetByteLength().GetNumber(), lengthDataView2); +} + +/* + * Feature: JSDataView + * Function: SetByteOffset + * SubFunction: GetByteOffset + * FunctionPoints: Set ByteOffset + * CaseDescription: Check whether the returned value through "GetByteOffset" function is within expectations after + * calling "SetByteOffset" function. + */ +HWTEST_F_L0(JSDataViewTest, SetByteOffset) +{ + EcmaVM *ecmaVMPtr = thread->GetEcmaVM(); + ObjectFactory *factory = ecmaVMPtr->GetFactory(); + JSHandle handleFuncArrayBuf1(ecmaVMPtr->GetGlobalEnv()->GetArrayBufferFunction()); + JSHandle handleTagValFuncArrayBuf1(handleFuncArrayBuf1); + + int32_t lengthDataArrayBuf = 8; + int32_t offsetDataView1 = 4; + int32_t offsetDataView2 = 6; + int32_t lengthDataView = 2; + JSHandle handleTagValOffsetDataView2(thread, JSTaggedValue(offsetDataView2)); + JSHandle handleArrayBuf( + factory->NewJSObjectByConstructor(handleFuncArrayBuf1, handleTagValFuncArrayBuf1)); + handleArrayBuf->SetArrayBufferByteLength(thread, JSTaggedValue(lengthDataArrayBuf)); + + // Call "SetByteOffset" function through "NewJSDataView" function of "object_factory.cpp" + JSHandle handleDataView = factory->NewJSDataView(handleArrayBuf, offsetDataView1, + lengthDataView); + EXPECT_EQ(handleDataView->GetByteOffset().GetNumber(), offsetDataView1); + + // Call "SetByteOffset" function in this HWTEST_F_L0. + handleDataView->SetByteOffset(thread, handleTagValOffsetDataView2); + EXPECT_EQ(handleDataView->GetByteOffset().GetNumber(), offsetDataView2); +} +} // namespace panda::ecmascript diff --git a/ecmascript/tests/js_object_test.cpp b/ecmascript/tests/js_object_test.cpp index e004cb4da561362eefd63258770dca0a30398055..69a9ee19bb7898fc7dfa7b9a66ef080ae08ed7da 100644 --- a/ecmascript/tests/js_object_test.cpp +++ b/ecmascript/tests/js_object_test.cpp @@ -1304,7 +1304,7 @@ HWTEST_F_L0(JSObjectTest, NativePointerField) obj->SetNativePointerFieldCount(1); char array[] = "Hello World!"; - obj->SetNativePointerField(0, array); + obj->SetNativePointerField(0, array, nullptr, nullptr); int32_t count = obj->GetNativePointerFieldCount(); EXPECT_TRUE(count == 1); void *pointer = obj->GetNativePointerField(0); diff --git a/ecmascript/tests/js_serializer_test.cpp b/ecmascript/tests/js_serializer_test.cpp index e40c6341dc852fd8d3710bf3d694eb73ba790f20..5a0d702ef6cfaf2f45c53fdd0cc5fc793096da97 100644 --- a/ecmascript/tests/js_serializer_test.cpp +++ b/ecmascript/tests/js_serializer_test.cpp @@ -41,7 +41,7 @@ public: JSDeserializerTest() : ecmaVm(nullptr), scope(nullptr), thread(nullptr) {} void Init() { - RuntimeOptions options; + JSRuntimeOptions options; options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetBootIntrinsicSpaces({"ecmascript"}); diff --git a/ecmascript/tests/js_set_iterator_test.cpp b/ecmascript/tests/js_set_iterator_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..594060fa337b73d94feaee8d760ed2a43a796cd4 --- /dev/null +++ b/ecmascript/tests/js_set_iterator_test.cpp @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2021 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/js_set_iterator.h" +#include "ecmascript/js_set.h" +#include "ecmascript/global_env.h" +#include "ecmascript/linked_hash_table-inl.h" +#include "ecmascript/object_factory.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class JSSetIteratorTest : 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); + } + ecmascript::EcmaHandleScope *scope {nullptr}; + PandaVM *instance {nullptr}; + JSThread *thread {nullptr}; +}; + +JSSet *CreateSet(JSThread *thread) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + + JSHandle constructor = env->GetBuiltinsSetFunction(); + JSHandle set = + JSHandle::Cast(factory->NewJSObjectByConstructor(JSHandle(constructor), constructor)); + LinkedHashSet *hashSet = LinkedHashSet::Cast(LinkedHashSet::Create(thread).GetTaggedObject()); + set->SetLinkedSet(thread, JSTaggedValue(hashSet)); + return JSSet::Cast(set.GetTaggedValue().GetTaggedObject()); +} + +/* + * Feature: JSSetIterator + * Function: CreateSetIterator + * SubFunction: GetIterationKind,GetNextIndex + * FunctionPoints: Create SetIterator + * CaseDescription: Check whether the returned value through "CreateSetIterator" function is within expectations. + */ +HWTEST_F_L0(JSSetIteratorTest, CreateSetIterator) +{ + JSHandle jsSet(thread, CreateSet(thread)); + EXPECT_TRUE(*jsSet != nullptr); + + JSHandle setIteratorValue1 = + JSSetIterator::CreateSetIterator(thread, JSHandle(jsSet), IterationKind::KEY); + + EXPECT_EQ(setIteratorValue1->IsJSSetIterator(), true); + JSHandle setIterator1(setIteratorValue1); + EXPECT_EQ(JSTaggedValue::SameValue(setIterator1->GetIteratedSet(), jsSet->GetLinkedSet()), true); + EXPECT_EQ(setIterator1->GetNextIndex().GetInt(), 0); + + JSTaggedValue iterationKind1 = setIterator1->GetIterationKind(); + EXPECT_EQ(JSTaggedValue::SameValue(iterationKind1, JSTaggedValue(static_cast(IterationKind::KEY))), true); + + JSHandle setIteratorValue2 = + JSSetIterator::CreateSetIterator(thread, JSHandle(jsSet), IterationKind::VALUE); + + EXPECT_EQ(setIteratorValue2->IsJSSetIterator(), true); + JSHandle setIterator2(setIteratorValue2); + EXPECT_EQ(JSTaggedValue::SameValue(setIterator2->GetIteratedSet(), jsSet->GetLinkedSet()), true); + EXPECT_EQ(setIterator2->GetNextIndex().GetInt(), 0); + + JSTaggedValue iterationKind2 = setIterator2->GetIterationKind(); + EXPECT_EQ(JSTaggedValue::SameValue(iterationKind2, JSTaggedValue(static_cast(IterationKind::VALUE))), true); +} + +/* + * Feature: JSSetIterator + * Function: next + * SubFunction: IteratorValue + * FunctionPoints: get the next value in setiterator + * CaseDescription: Check whether the return value obtained by the function is the next value in the array element. + */ +HWTEST_F_L0(JSSetIteratorTest, Next) +{ + JSHandle jsSet(thread, CreateSet(thread)); + EXPECT_TRUE(*jsSet != nullptr); + + for (int i = 0; i < 3; i++) { + JSHandle key(thread, JSTaggedValue(i)); + JSSet::Add(thread, jsSet, key); + } + + // set IterationKind(key or value) + JSHandle setIteratorValue = + JSSetIterator::CreateSetIterator(thread, JSHandle(jsSet), IterationKind::KEY); + JSHandle setIterator(setIteratorValue); + + auto ecmaRuntimeCallInfo = TestHelper::CreateEcmaRuntimeCallInfo(thread, JSTaggedValue::Undefined(), 6); + ecmaRuntimeCallInfo->SetFunction(JSTaggedValue::Undefined()); + ecmaRuntimeCallInfo->SetThis(setIteratorValue.GetTaggedValue()); + ecmaRuntimeCallInfo->SetCallArg(0, JSTaggedValue::Undefined()); + [[maybe_unused]] auto prev = TestHelper::SetupFrame(thread, ecmaRuntimeCallInfo.get()); + + JSTaggedValue result1 = JSSetIterator::Next(ecmaRuntimeCallInfo.get()); + EXPECT_EQ(setIterator->GetNextIndex().GetInt(), 1); + JSHandle resultObj1(thread, result1); + EXPECT_EQ(0, JSIterator::IteratorValue(thread, resultObj1)->GetInt()); + + JSTaggedValue result2 = JSSetIterator::Next(ecmaRuntimeCallInfo.get()); + EXPECT_EQ(setIterator->GetNextIndex().GetInt(), 2); + JSHandle resultObj2(thread, result2); + EXPECT_EQ(1, JSIterator::IteratorValue(thread, resultObj2)->GetInt()); + + JSTaggedValue result3 = JSSetIterator::Next(ecmaRuntimeCallInfo.get()); + EXPECT_EQ(setIterator->GetNextIndex().GetInt(), 3); + JSHandle resultObj3(thread, result3); + EXPECT_EQ(2, JSIterator::IteratorValue(thread, resultObj3)->GetInt()); + + JSTaggedValue result4 = JSSetIterator::Next(ecmaRuntimeCallInfo.get()); + JSHandle resultObj4(thread, result4); + EXPECT_EQ(JSIterator::IteratorValue(thread, resultObj4).GetTaggedValue(), JSTaggedValue::Undefined()); + + TestHelper::TearDownFrame(thread, prev); +} +} // namespace panda::test \ No newline at end of file diff --git a/ecmascript/tests/js_string_iterator_test.cpp b/ecmascript/tests/js_string_iterator_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..831038fa6e01664f374b4d50aa0a8163e483f89d --- /dev/null +++ b/ecmascript/tests/js_string_iterator_test.cpp @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2021 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/js_string_iterator.h" +#include "ecmascript/ecma_string.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class JSStringIteratorTest : 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); + } + PandaVM *instance {nullptr}; + ecmascript::EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; +}; + +/* + * Feature: JSStringIterator + * Function: CreateStringIterator + * SubFunction: IsStringIterator + * FunctionPoints: Create String Iterator + * CaseDescription: Call the "CreateStringIterator" function, check whether the result tagged value returned by + * "IsStringIterator" function from the JSArrayIterator is within expectations. + */ +HWTEST_F_L0(JSStringIteratorTest, CreateStringIterator) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + + char array1[] = "x"; + JSHandle iteratorString1 = factory->NewFromCanBeCompressString(array1); + EXPECT_TRUE(JSStringIterator::CreateStringIterator(thread, iteratorString1).GetTaggedValue().IsStringIterator()); + + char array2[] = "1"; + JSHandle iteratorString2 = factory->NewFromCanBeCompressString(array2); + EXPECT_TRUE(JSStringIterator::CreateStringIterator(thread, iteratorString2).GetTaggedValue().IsStringIterator()); +} + +/* + * Feature: JSStringIterator + * Function: SetIteratedString + * SubFunction: GetIteratedString + * FunctionPoints: Set Iterated String + * CaseDescription: Call the "SetIteratedString" function, check whether the result returned through "GetIteratedString" + * function from the JSArrayIterator is within expectations. + */ +HWTEST_F_L0(JSStringIteratorTest, SetIteratedString) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + char array1[] = "12345"; + + JSHandle iteratorString1 = factory->NewFromCanBeCompressString(array1); + JSTaggedValue iteratorStringValue1 = iteratorString1.GetTaggedValue(); + JSHandle stringIterator1 = JSStringIterator::CreateStringIterator(thread, iteratorString1); + + JSTaggedValue handString1 = stringIterator1->GetIteratedString(); + JSHandle resultHandleString1(thread, reinterpret_cast(handString1.GetRawData())); + EXPECT_EQ(resultHandleString1->Compare(reinterpret_cast(iteratorStringValue1.GetRawData())), 5); + + char array2[] = "abcd"; + JSHandle iteratorString2 = factory->NewFromCanBeCompressString(array2); + JSTaggedValue iteratorStringValue2 = iteratorString2.GetTaggedValue(); + JSHandle stringIterator2 = JSStringIterator::CreateStringIterator(thread, iteratorString2); + + JSTaggedValue handString2 = stringIterator2->GetIteratedString(); + JSHandle resultHandleString2(thread, reinterpret_cast(handString2.GetRawData())); + EXPECT_EQ(resultHandleString2->Compare(reinterpret_cast(iteratorStringValue2.GetRawData())), 4); +} + +/* + * Feature: JSStringIterator + * Function: SetStringIteratorNextIndex + * SubFunction: GetStringIteratorNextIndex + * FunctionPoints: Set String Iterator Next Index + * CaseDescription: Call the "SetStringIteratorNextIndex" function, check whether the result returned through + * "GetStringIteratorNextIndex" function from the JSArrayIterator is within expectations. + */ +HWTEST_F_L0(JSStringIteratorTest, SetStringIteratorNextIndex) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + char array1[] = "12345"; + uint32_t arrayLength1 = sizeof(array1) - 1; + + JSHandle iteratorString1 = factory->NewFromCanBeCompressString(array1); + JSHandle stringIterator1 = JSStringIterator::CreateStringIterator(thread, iteratorString1); + EXPECT_EQ(stringIterator1->GetStringIteratorNextIndex().GetInt(), 0); + + for (int i = 1; i <= arrayLength1; i++) { + JSHandle handleTagStringIteratorNextIndex1(thread, JSTaggedValue(i)); + stringIterator1->SetStringIteratorNextIndex(thread, handleTagStringIteratorNextIndex1); + EXPECT_EQ(stringIterator1->GetStringIteratorNextIndex().GetNumber(), i); + } + + char array2[] = "abcde"; + uint32_t arrayLength2 = sizeof(array2) - 1; + + JSHandle iteratorString2 = factory->NewFromCanBeCompressString(array2); + JSHandle stringIterator2 = JSStringIterator::CreateStringIterator(thread, iteratorString2); + EXPECT_EQ(stringIterator2->GetStringIteratorNextIndex().GetInt(), 0); + + for (int i = 1; i <= arrayLength2; i++) { + JSHandle handleTagStringIteratorNextIndex2(thread, JSTaggedValue(i)); + stringIterator2->SetStringIteratorNextIndex(thread, handleTagStringIteratorNextIndex2); + EXPECT_EQ(stringIterator2->GetStringIteratorNextIndex().GetNumber(), i); + } +} +} // namespace panda::ecmascript \ No newline at end of file diff --git a/ecmascript/tests/js_typed_array_test.cpp b/ecmascript/tests/js_typed_array_test.cpp new file mode 100644 index 0000000000000000000000000000000000000000..0d287d765cf56e4330a7c6a43c9bf73c6ede55e0 --- /dev/null +++ b/ecmascript/tests/js_typed_array_test.cpp @@ -0,0 +1,1332 @@ +/* + * Copyright (c) 2021 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/typed_array_helper-inl.h" +#include "ecmascript/tests/test_helper.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class JSTypedArrayTest : 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); + } + PandaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread {nullptr}; + + const CVector cVecJSType { + JSType::JS_INT8_ARRAY, JSType::JS_UINT8_ARRAY, JSType::JS_UINT8_CLAMPED_ARRAY, + JSType::JS_INT16_ARRAY, JSType::JS_UINT16_ARRAY, + JSType::JS_INT32_ARRAY, JSType::JS_UINT32_ARRAY, + JSType::JS_FLOAT32_ARRAY, JSType::JS_FLOAT64_ARRAY}; + + // CVector pushed with JSTaggedValue made from compatible input value for the JSType + const CVector cVecHandleTagValValueForTypedArray { + // Use "(S)(...)" cast to make v in "JSTaggedValue(T v) : coretypes::TaggedValue(v) {}" compatible with S + JSTaggedValue((int8_t)(-111)), JSTaggedValue((uint8_t)(222)), JSTaggedValue((uint8_t)(222)), + JSTaggedValue((int16_t)(-31111)), JSTaggedValue((uint16_t)(61111)), + // int32 : -2147483648->2147483647, uint32 : 0->4294967295 + JSTaggedValue((int32_t)(2111111111)), JSTaggedValue((uint32_t)(4111111111)), + JSTaggedValue((float)(4321.1234)), JSTaggedValue((double)(987654321.123456789))}; +}; + +JSHandle CreateNumberTypedArray(JSThread *thread, JSType jsType) +{ + JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + + JSHandle handleTagValFunc = env->GetInt8ArrayFunction(); + switch (jsType) { + case JSType::JS_INT8_ARRAY: + break; + case JSType::JS_UINT8_ARRAY: + handleTagValFunc = env->GetUint8ArrayFunction(); + break; + case JSType::JS_UINT8_CLAMPED_ARRAY: + handleTagValFunc = env->GetUint8ClampedArrayFunction(); + break; + case JSType::JS_INT16_ARRAY: + handleTagValFunc = env->GetInt16ArrayFunction(); + break; + case JSType::JS_UINT16_ARRAY: + handleTagValFunc = env->GetUint16ArrayFunction(); + break; + case JSType::JS_INT32_ARRAY: + handleTagValFunc = env->GetInt32ArrayFunction(); + break; + case JSType::JS_UINT32_ARRAY: + handleTagValFunc = env->GetUint32ArrayFunction(); + break; + case JSType::JS_FLOAT32_ARRAY: + handleTagValFunc = env->GetFloat32ArrayFunction(); + break; + case JSType::JS_FLOAT64_ARRAY: + handleTagValFunc = env->GetFloat64ArrayFunction(); + break; + default: + ASSERT_PRINT(false, "the second argument is a wrong JSType for CreateNumberTypedArray function"); + break; + } + + return JSHandle::Cast( + factory->NewJSObjectByConstructor(JSHandle::Cast(handleTagValFunc), handleTagValFunc)); +} + +/* + * Feature: JSTypedArray + * Function: ToPropKey + * SubFunction: EcmaString::GetCString + * FunctionPoints: TaggedType Signs To EcmaString Signs + * CaseDescription: Check whether the EcmaStrings transformed through calling ToPropKey function from TaggedTypes are + * within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, ToPropKey_001) +{ + JSHandle handleUndefined(thread, JSTaggedValue::Undefined()); + JSHandle handleHole(thread, JSTaggedValue::Hole()); + JSHandle hnadleTagValEcmaStrPropKeyTo1 = JSTypedArray::ToPropKey(thread, handleUndefined); + JSHandle hnadleTagValEcmaStrPropKeyTo2 = JSTypedArray::ToPropKey(thread, handleHole); + JSHandle handleEcmaStrPropKeyTo1 = JSHandle::Cast(hnadleTagValEcmaStrPropKeyTo1); + JSHandle handleEcmaStrPropKeyTo2 = JSHandle::Cast(hnadleTagValEcmaStrPropKeyTo2); + EXPECT_NE(0, sizeof(handleUndefined)); + EXPECT_NE(0, sizeof(handleHole)); + std::unique_ptr uniCharArrTo1(handleEcmaStrPropKeyTo1->GetCString()); + std::unique_ptr uniCharArrTo2(handleEcmaStrPropKeyTo2->GetCString()); + EXPECT_EQ(uniCharArrTo1[0], 'u'); + EXPECT_EQ(uniCharArrTo1[1], 'n'); + EXPECT_EQ(uniCharArrTo1[2], 'd'); + EXPECT_EQ(uniCharArrTo1[3], 'e'); + EXPECT_EQ(uniCharArrTo1[4], 'f'); + EXPECT_EQ(uniCharArrTo1[5], 'i'); + EXPECT_EQ(uniCharArrTo1[6], 'n'); + EXPECT_EQ(uniCharArrTo1[7], 'e'); + EXPECT_EQ(uniCharArrTo1[8], 'd'); + EXPECT_EQ(uniCharArrTo1[9], 0); // "undefined" + EXPECT_EQ(uniCharArrTo2[0], 0); // "" +} + +/* + * Feature: JSTypedArray + * Function: ToPropKey + * SubFunction: EcmaString::GetCString + * FunctionPoints: Number Signs To EcmaString Signs + * CaseDescription: Check whether the EcmaStrings transformed through calling ToPropKey function from Numbers are + * within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, ToPropKey_002) +{ + JSHandle handleTagVal1(thread, JSTaggedValue(0)); + JSHandle handleTagVal2(thread, JSTaggedValue(-1)); + JSHandle handleTagVal3(thread, JSTaggedValue(1.789)); + JSHandle handleTagVal4(thread, JSTaggedValue(-789.1)); + JSHandle hnadleTagValEcmaStrPropKeyTo1 = JSTypedArray::ToPropKey(thread, handleTagVal1); + JSHandle hnadleTagValEcmaStrPropKeyTo2 = JSTypedArray::ToPropKey(thread, handleTagVal2); + JSHandle hnadleTagValEcmaStrPropKeyTo3 = JSTypedArray::ToPropKey(thread, handleTagVal3); + JSHandle hnadleTagValEcmaStrPropKeyTo4 = JSTypedArray::ToPropKey(thread, handleTagVal4); + JSHandle handleEcmaStrPropKeyTo1 = JSHandle::Cast(hnadleTagValEcmaStrPropKeyTo1); + JSHandle handleEcmaStrPropKeyTo2 = JSHandle::Cast(hnadleTagValEcmaStrPropKeyTo2); + JSHandle handleEcmaStrPropKeyTo3 = JSHandle::Cast(hnadleTagValEcmaStrPropKeyTo3); + JSHandle handleEcmaStrPropKeyTo4 = JSHandle::Cast(hnadleTagValEcmaStrPropKeyTo4); + std::unique_ptr uniCharArrTo1(handleEcmaStrPropKeyTo1->GetCString()); + std::unique_ptr uniCharArrTo2(handleEcmaStrPropKeyTo2->GetCString()); + std::unique_ptr uniCharArrTo3(handleEcmaStrPropKeyTo3->GetCString()); + std::unique_ptr uniCharArrTo4(handleEcmaStrPropKeyTo4->GetCString()); + EXPECT_EQ(uniCharArrTo1[0], '0'); + EXPECT_EQ(uniCharArrTo1[1], 0); // "0" + EXPECT_EQ(uniCharArrTo2[0], '-'); + EXPECT_EQ(uniCharArrTo2[1], '1'); + EXPECT_EQ(uniCharArrTo2[2], 0); // "-1" + EXPECT_EQ(uniCharArrTo3[0], '1'); + EXPECT_EQ(uniCharArrTo3[1], '.'); + EXPECT_EQ(uniCharArrTo3[2], '7'); + EXPECT_EQ(uniCharArrTo3[3], '8'); + EXPECT_EQ(uniCharArrTo3[4], '9'); + EXPECT_EQ(uniCharArrTo3[5], 0); // "1.789" + EXPECT_EQ(uniCharArrTo4[0], '-'); + EXPECT_EQ(uniCharArrTo4[1], '7'); + EXPECT_EQ(uniCharArrTo4[2], '8'); + EXPECT_EQ(uniCharArrTo4[3], '9'); + EXPECT_EQ(uniCharArrTo4[4], '.'); + EXPECT_EQ(uniCharArrTo4[5], '1'); + EXPECT_EQ(uniCharArrTo4[6], 0); // "-789.1" +} + +/* + * Feature: JSTypedArray + * Function: CreateJSTypedArray(GlobalEnv::GetInt8ArrayFunction.../ObjectFactory::NewJSObjectByConstructor) + * SubFunction: JSTaggedValue::IsTypedArray/IsJSInt8Array... + * FunctionPoints: Create JSTypedArray(JSInt8Array...) + * CaseDescription: Check whether the bools returned through calling IsTypedArray/IsInt8Array... functions from the + * JSTypedArrays created through calling NewJSObjectByConstructor function are within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, TypedArrayCreate) +{ + JSHandle handleInt8Array = CreateNumberTypedArray(thread, JSType::JS_INT8_ARRAY); + JSHandle handleTagValInt8Array = JSHandle::Cast(handleInt8Array); + EXPECT_TRUE(handleTagValInt8Array->IsJSInt8Array() && handleTagValInt8Array->IsTypedArray()); + + JSHandle handleUint8Array = CreateNumberTypedArray(thread, JSType::JS_UINT8_ARRAY); + JSHandle handleTagValUint8Array = JSHandle::Cast(handleUint8Array); + EXPECT_TRUE(handleTagValUint8Array->IsJSUint8Array() && handleTagValUint8Array->IsTypedArray()); + + JSHandle handleUint8ClampedArray = CreateNumberTypedArray(thread, JSType::JS_UINT8_CLAMPED_ARRAY); + JSHandle handleTagValUint8ClampedArray = JSHandle::Cast(handleUint8ClampedArray); + EXPECT_TRUE(handleTagValUint8ClampedArray->IsJSUint8ClampedArray() && + handleTagValUint8ClampedArray->IsTypedArray()); + + JSHandle handleInt16Array = CreateNumberTypedArray(thread, JSType::JS_INT16_ARRAY); + JSHandle handleTagValInt16Array = JSHandle::Cast(handleInt16Array); + EXPECT_TRUE(handleTagValInt16Array->IsJSInt16Array() && handleTagValInt16Array->IsTypedArray()); + + JSHandle handleUint16Array = CreateNumberTypedArray(thread, JSType::JS_UINT16_ARRAY); + JSHandle handleTagValUint16Array = JSHandle::Cast(handleUint16Array); + EXPECT_TRUE(handleTagValUint16Array->IsJSUint16Array() && handleTagValUint16Array->IsTypedArray()); + + JSHandle handleInt32Array = CreateNumberTypedArray(thread, JSType::JS_INT32_ARRAY); + JSHandle handleTagValInt32Array = JSHandle::Cast(handleInt32Array); + EXPECT_TRUE(handleTagValInt32Array->IsJSInt32Array() && handleTagValInt32Array->IsTypedArray()); + + JSHandle handleUint32Array = CreateNumberTypedArray(thread, JSType::JS_UINT32_ARRAY); + JSHandle handleTagValUint32Array = JSHandle::Cast(handleUint32Array); + EXPECT_TRUE(handleTagValUint32Array->IsJSUint32Array() && handleTagValUint32Array->IsTypedArray()); + + JSHandle handleFloat32Array = CreateNumberTypedArray(thread, JSType::JS_FLOAT32_ARRAY); + JSHandle handleTagValFloat32Array = JSHandle::Cast(handleFloat32Array); + EXPECT_TRUE(handleTagValFloat32Array->IsJSFloat32Array() && handleTagValFloat32Array->IsTypedArray()); + + JSHandle handleFloat64Array = CreateNumberTypedArray(thread, JSType::JS_FLOAT64_ARRAY); + JSHandle handleTagValFloat64Array = JSHandle::Cast(handleFloat64Array); + EXPECT_TRUE(handleTagValFloat64Array->IsJSFloat64Array() && handleTagValFloat64Array->IsTypedArray()); +} + +/* + * Feature: JSTypedArray + * Function: SetViewedArrayBuffer + * SubFunction: GetViewedArrayBuffer/ObjectFactory::NewJSArrayBuffer + * FunctionPoints: Set ViewedArrayBuffer + * CaseDescription: Check whether the JSArrayBuffer returned through calling GetViewedArrayBuffer function from the + * JSTypedArray changed through calling SetViewedArrayBuffer function is within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, SetViewedArrayBuffer) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleArrayBufferFrom = factory->NewJSArrayBuffer(10); + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast(handleArrayBufferFrom); + + for (int i = 0; i < cVecJSType.size(); i++) { + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(i)); + + EXPECT_EQ(handleTypedArray->GetViewedArrayBuffer(), JSTaggedValue::Undefined()); + handleTypedArray->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + EXPECT_EQ(handleTypedArray->GetViewedArrayBuffer(), handleTagValArrayBufferFrom.GetTaggedValue()); + } +} + +/* + * Feature: JSTypedArray + * Function: SetTypedArrayName + * SubFunction: GetTypedArrayName + * FunctionPoints: Set TypedArrayName + * CaseDescription: Check whether the JSTaggedValue returned through calling GetTypedArrayName function from the + * JSTypedArray changed through calling SetTypedArrayName function is within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, SetTypedArrayName) +{ + CString cStrName = "cStrName"; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleEcmaStrNameFrom = factory->NewFromString(cStrName); + JSHandle handleTagValEcmaStrNameFrom = JSHandle::Cast(handleEcmaStrNameFrom); + + for (int i = 0; i < cVecJSType.size(); i++) { + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(i)); + + EXPECT_EQ(handleTypedArray->GetTypedArrayName(), JSTaggedValue::Undefined()); + handleTypedArray->SetTypedArrayName(thread, handleTagValEcmaStrNameFrom); + EXPECT_EQ(handleTypedArray->GetTypedArrayName(), handleTagValEcmaStrNameFrom.GetTaggedValue()); + } +} + +/* + * Feature: JSTypedArray + * Function: SetByteLength + * SubFunction: GetByteLength + * FunctionPoints: Set ByteLength + * CaseDescription: Check whether the Number returned through calling GetByteLength function from the JSTypedArray + * changed through calling SetByteLength function is within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, SetByteLength) +{ + uint32_t u32ByteLength = 2; + JSHandle handleTagValByteLengthFrom(thread, JSTaggedValue(u32ByteLength)); + + for (int i = 0; i < cVecJSType.size(); i++) { + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(i)); + + EXPECT_EQ(handleTypedArray->GetByteLength(), JSTaggedValue(0)); + handleTypedArray->SetByteLength(thread, handleTagValByteLengthFrom); + EXPECT_EQ(handleTypedArray->GetByteLength(), handleTagValByteLengthFrom.GetTaggedValue()); + } +} + +/* + * Feature: JSTypedArray + * Function: SetByteOffset + * SubFunction: GetByteOffset + * FunctionPoints: Set ByteOffset + * CaseDescription: Check whether the Number returned through calling GetByteOffset function from the JSTypedArray + * changed through calling SetByteOffset function is within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, SetByteOffset) +{ + uint32_t u32ByteOffset = 2; + JSHandle handleTagValByteOffsetFrom(thread, JSTaggedValue(u32ByteOffset)); + + for (int i = 0; i < cVecJSType.size(); i++) { + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(i)); + + EXPECT_EQ(handleTypedArray->GetByteOffset(), JSTaggedValue(0)); + handleTypedArray->SetByteOffset(thread, handleTagValByteOffsetFrom); + EXPECT_EQ(handleTypedArray->GetByteOffset(), handleTagValByteOffsetFrom.GetTaggedValue()); + } +} + +/* + * Feature: JSTypedArray + * Function: SetArrayLength + * SubFunction: GetArrayLength + * FunctionPoints: Set ArrayLength + * CaseDescription: Check whether the Number returned through calling GetArrayLength function from the JSTypedArray + * changed through calling SetArrayLength function is within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, SetArrayLength) +{ + uint32_t u32ArrayLength = 2; + JSHandle handleTagValArrayLengthFrom(thread, JSTaggedValue(u32ArrayLength)); + + for (int i = 0; i < cVecJSType.size(); i++) { + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(i)); + + EXPECT_EQ(handleTypedArray->GetArrayLength(), JSTaggedValue(0)); + handleTypedArray->SetArrayLength(thread, handleTagValArrayLengthFrom); + EXPECT_EQ(handleTypedArray->GetArrayLength(), handleTagValArrayLengthFrom.GetTaggedValue()); + } +} + +/* + * Feature: JSTypedArray + * Function: IntegerIndexedElementSet + * SubFunction: IntegerIndexedElementGet + * FunctionPoints: Set Element At Integer Index(JSTaggedValue) Of JSTypedArray + * CaseDescription: Check whether the OperationResults returned through calling IntegerIndexedElementGet function from + * the JSTypedArray changed through calling IntegerIndexedElementSet function are within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Int8Array_001) +{ + uint32_t numElementsInt8Array = 256; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleInt8Array = CreateNumberTypedArray(thread, JSType::JS_INT8_ARRAY); + JSHandle handleTagValInt8Array = JSHandle::Cast(handleInt8Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleInt8Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsInt8Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleInt8Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleInt8Array->SetArrayLength(thread, JSTaggedValue(numElementsInt8Array)); + + CVector cVecOpResult = {}; + for (int32_t i = 0; i < numElementsInt8Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt8Array, JSTaggedValue(i), + JSHandle(thread, JSTaggedValue(std::numeric_limits::min() + i)))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (int32_t i = 0; i < numElementsInt8Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), std::numeric_limits::min() + i); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(numElementsInt8Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt8Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt8Array, + JSTaggedValue(numElementsInt8Array), JSHandle(thread, JSTaggedValue(0)))); +} + +// Nonstandard input value for Int8Array +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Int8Array_002) +{ + uint32_t numElementsInt8Array = 16; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleInt8Array = CreateNumberTypedArray(thread, JSType::JS_INT8_ARRAY); + JSHandle handleTagValInt8Array = JSHandle::Cast(handleInt8Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleInt8Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsInt8Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleInt8Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleInt8Array->SetArrayLength(thread, JSTaggedValue(numElementsInt8Array)); + + int64_t value1 = -129; // to int8 : 127 + int64_t value2 = 128; // to int8 : -128 + double value3 = 13.4; // to int8 : 13 + double value4 = 13.6; // to int8 : 13 + JSHandle handleTagValValueSet1(thread, JSTaggedValue(value1)); + JSHandle handleTagValValueSet2(thread, JSTaggedValue(value2)); + JSHandle handleTagValValueSet3(thread, JSTaggedValue(value3)); + JSHandle handleTagValValueSet4(thread, JSTaggedValue(value4)); + + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt8Array, JSTaggedValue(0), + handleTagValValueSet1)); + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt8Array, JSTaggedValue(0), + handleTagValValueSet2)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt8Array, JSTaggedValue(0), + handleTagValValueSet3)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt8Array, JSTaggedValue(0), + handleTagValValueSet4)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt8Array, + JSTaggedValue(0)); + + EXPECT_NE(value1, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value2, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value3, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value4, opResult4.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(127, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(-128, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult4.GetValue().GetTaggedValue().GetNumber()); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint8Array_001) +{ + uint32_t numElementsUint8Array = 256; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint8Array = CreateNumberTypedArray(thread, JSType::JS_UINT8_ARRAY); + JSHandle handleTagValUint8Array = JSHandle::Cast(handleUint8Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint8Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint8Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint8Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint8Array->SetArrayLength(thread, JSTaggedValue(numElementsUint8Array)); + + CVector cVecOpResult = {}; + for (uint32_t i = 0; i < numElementsUint8Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8Array, JSTaggedValue(i), + JSHandle(thread, JSTaggedValue(std::numeric_limits::min() + i)))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (uint32_t i = 0; i < numElementsUint8Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), std::numeric_limits::min() + i); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(numElementsUint8Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8Array, + JSTaggedValue(numElementsUint8Array), JSHandle(thread, JSTaggedValue(0)))); +} + +// Nonstandard input value for Uint8Array +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint8Array_002) +{ + uint32_t numElementsUint8Array = 16; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint8Array = CreateNumberTypedArray(thread, JSType::JS_UINT8_ARRAY); + JSHandle handleTagValUint8Array = JSHandle::Cast(handleUint8Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint8Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint8Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint8Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint8Array->SetArrayLength(thread, JSTaggedValue(numElementsUint8Array)); + + int64_t value1 = -1; // to uint8 : 255 + int64_t value2 = 256; // to uint8 : 0 + double value3 = 13.4; // to uint8 : 13 + double value4 = 13.6; // to uint8 : 13 + JSHandle handleTagValValueSet1(thread, JSTaggedValue(value1)); + JSHandle handleTagValValueSet2(thread, JSTaggedValue(value2)); + JSHandle handleTagValValueSet3(thread, JSTaggedValue(value3)); + JSHandle handleTagValValueSet4(thread, JSTaggedValue(value4)); + + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8Array, JSTaggedValue(0), + handleTagValValueSet1)); + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8Array, JSTaggedValue(0), + handleTagValValueSet2)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8Array, JSTaggedValue(0), + handleTagValValueSet3)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8Array, JSTaggedValue(0), + handleTagValValueSet4)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8Array, + JSTaggedValue(0)); + + EXPECT_NE(value1, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value2, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value3, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value4, opResult4.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(255, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(0, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult4.GetValue().GetTaggedValue().GetNumber()); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint8ClampedArray_001) +{ + uint32_t numElementsUint8ClampedArray = 256; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint8ClampedArray = CreateNumberTypedArray(thread, JSType::JS_UINT8_CLAMPED_ARRAY); + JSHandle handleTagValUint8ClampedArray = JSHandle::Cast(handleUint8ClampedArray); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint8ClampedArray)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint8ClampedArray; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint8ClampedArray->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint8ClampedArray->SetArrayLength(thread, JSTaggedValue(numElementsUint8ClampedArray)); + + CVector cVecOpResult = {}; + for (uint32_t i = 0; i < numElementsUint8ClampedArray; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8ClampedArray, JSTaggedValue(i), + JSHandle(thread, JSTaggedValue(std::numeric_limits::min() + i)))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (uint32_t i = 0; i < numElementsUint8ClampedArray; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), std::numeric_limits::min() + i); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(numElementsUint8ClampedArray)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8ClampedArray, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(numElementsUint8ClampedArray), JSHandle(thread, JSTaggedValue(0)))); +} + +// Nonstandard input value for Uint8ClampedArray +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint8ClampedArray_002) +{ + uint32_t numElementsUint8ClampedArray = 16; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint8ClampedArray = CreateNumberTypedArray(thread, JSType::JS_UINT8_CLAMPED_ARRAY); + JSHandle handleTagValUint8ClampedArray = JSHandle::Cast(handleUint8ClampedArray); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint8ClampedArray)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint8ClampedArray; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint8ClampedArray->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint8ClampedArray->SetArrayLength(thread, JSTaggedValue(numElementsUint8ClampedArray)); + + int64_t value1 = -1; // to uint8_clamped : 0 + int64_t value2 = 256; // to uint8_clamped : 255 + double value3 = 13.4; // to uint8_clamped : 13 + double value4 = 13.6; // to uint8_clamped : 14 + JSHandle handleTagValValueSet1(thread, JSTaggedValue(value1)); + JSHandle handleTagValValueSet2(thread, JSTaggedValue(value2)); + JSHandle handleTagValValueSet3(thread, JSTaggedValue(value3)); + JSHandle handleTagValValueSet4(thread, JSTaggedValue(value4)); + + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8ClampedArray, JSTaggedValue(0), + handleTagValValueSet1)); + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8ClampedArray, JSTaggedValue(0), + handleTagValValueSet2)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8ClampedArray, JSTaggedValue(0), + handleTagValValueSet3)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint8ClampedArray, JSTaggedValue(0), + handleTagValValueSet4)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint8ClampedArray, + JSTaggedValue(0)); + + EXPECT_NE(value1, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value2, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value3, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value4, opResult4.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(0, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(255, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(14, opResult4.GetValue().GetTaggedValue().GetNumber()); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Int16Array_001) +{ + uint32_t numElementsInt16Array = 100; + int16_t scaleForInt16ValueSet = 100; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleInt16Array = CreateNumberTypedArray(thread, JSType::JS_INT16_ARRAY); + JSHandle handleTagValInt16Array = JSHandle::Cast(handleInt16Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleInt16Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsInt16Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleInt16Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleInt16Array->SetArrayLength(thread, JSTaggedValue(numElementsInt16Array)); + + CVector cVecOpResult = {}; + for (int32_t i = 0; i < numElementsInt16Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt16Array, JSTaggedValue(i), + JSHandle(thread, + JSTaggedValue(std::numeric_limits::min() + i * scaleForInt16ValueSet)))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (int32_t i = 0; i < numElementsInt16Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), + std::numeric_limits::min() + i * scaleForInt16ValueSet); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(numElementsInt16Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt16Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt16Array, + JSTaggedValue(numElementsInt16Array), JSHandle(thread, JSTaggedValue(0)))); +} + +// Nonstandard input value for Int16Array +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Int16Array_002) +{ + uint32_t numElementsInt16Array = 16; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleInt16Array = CreateNumberTypedArray(thread, JSType::JS_INT16_ARRAY); + JSHandle handleTagValInt16Array = JSHandle::Cast(handleInt16Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleInt16Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsInt16Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleInt16Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleInt16Array->SetArrayLength(thread, JSTaggedValue(numElementsInt16Array)); + + int64_t value1 = -32769; // to int16 : 32767 + int64_t value2 = 32768; // to int16 : -32768 + double value3 = 13.4; // to int16 : 13 + double value4 = 13.6; // to int16 : 13 + JSHandle handleTagValValueSet1(thread, JSTaggedValue(value1)); + JSHandle handleTagValValueSet2(thread, JSTaggedValue(value2)); + JSHandle handleTagValValueSet3(thread, JSTaggedValue(value3)); + JSHandle handleTagValValueSet4(thread, JSTaggedValue(value4)); + + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt16Array, JSTaggedValue(0), + handleTagValValueSet1)); + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt16Array, JSTaggedValue(0), + handleTagValValueSet2)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt16Array, JSTaggedValue(0), + handleTagValValueSet3)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt16Array, JSTaggedValue(0), + handleTagValValueSet4)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt16Array, + JSTaggedValue(0)); + + EXPECT_NE(value1, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value2, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value3, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value4, opResult4.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(32767, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(-32768, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult4.GetValue().GetTaggedValue().GetNumber()); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint16Array_001) +{ + uint32_t numElementsUint16Array = 100; + uint32_t scaleForUint16ValueSet = 100; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint16Array = CreateNumberTypedArray(thread, JSType::JS_UINT16_ARRAY); + JSHandle handleTagValUint16Array = JSHandle::Cast(handleUint16Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint16Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint16Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint16Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint16Array->SetArrayLength(thread, JSTaggedValue(numElementsUint16Array)); + + CVector cVecOpResult = {}; + for (uint32_t i = 0; i < numElementsUint16Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint16Array, JSTaggedValue(i), + JSHandle(thread, + JSTaggedValue(std::numeric_limits::min() + i * scaleForUint16ValueSet)))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (uint32_t i = 0; i < numElementsUint16Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), + std::numeric_limits::min() + i * scaleForUint16ValueSet); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(numElementsUint16Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint16Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint16Array, + JSTaggedValue(numElementsUint16Array), JSHandle(thread, JSTaggedValue(0)))); +} + +// Nonstandard input value for Uint16Array +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint16Array_002) +{ + uint32_t numElementsUint16Array = 16; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint16Array = CreateNumberTypedArray(thread, JSType::JS_UINT16_ARRAY); + JSHandle handleTagValUint16Array = JSHandle::Cast(handleUint16Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint16Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint16Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint16Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint16Array->SetArrayLength(thread, JSTaggedValue(numElementsUint16Array)); + + int64_t value1 = -1; // to uint16 : 65535 + int64_t value2 = 65536; // to uint16 : 0 + double value3 = 13.4; // to uint16 : 13 + double value4 = 13.6; // to uint16 : 13 + JSHandle handleTagValValueSet1(thread, JSTaggedValue(value1)); + JSHandle handleTagValValueSet2(thread, JSTaggedValue(value2)); + JSHandle handleTagValValueSet3(thread, JSTaggedValue(value3)); + JSHandle handleTagValValueSet4(thread, JSTaggedValue(value4)); + + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint16Array, JSTaggedValue(0), + handleTagValValueSet1)); + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint16Array, JSTaggedValue(0), + handleTagValValueSet2)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint16Array, JSTaggedValue(0), + handleTagValValueSet3)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint16Array, JSTaggedValue(0), + handleTagValValueSet4)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint16Array, + JSTaggedValue(0)); + + EXPECT_NE(value1, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value2, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value3, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value4, opResult4.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(65535, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(0, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult4.GetValue().GetTaggedValue().GetNumber()); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Int32Array_001) +{ + uint32_t numElementsInt32Array = 100; + int32_t scaleForInt32ValueSet = 100000; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleInt32Array = CreateNumberTypedArray(thread, JSType::JS_INT32_ARRAY); + JSHandle handleTagValInt32Array = JSHandle::Cast(handleInt32Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleInt32Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsInt32Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleInt32Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleInt32Array->SetArrayLength(thread, JSTaggedValue(numElementsInt32Array)); + + CVector cVecOpResult = {}; + for (int32_t i = 0; i < numElementsInt32Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt32Array, JSTaggedValue(i), + JSHandle(thread, + JSTaggedValue(std::numeric_limits::min() + i * scaleForInt32ValueSet)))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (int32_t i = 0; i < numElementsInt32Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), + std::numeric_limits::min() + i * scaleForInt32ValueSet); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(numElementsInt32Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt32Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt32Array, + JSTaggedValue(numElementsInt32Array), JSHandle(thread, JSTaggedValue(0)))); +} + +// Nonstandard input value for Int32Array +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Int32Array_002) +{ + uint32_t numElementsInt32Array = 16; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleInt32Array = CreateNumberTypedArray(thread, JSType::JS_INT32_ARRAY); + JSHandle handleTagValInt32Array = JSHandle::Cast(handleInt32Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleInt32Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsInt32Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleInt32Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleInt32Array->SetArrayLength(thread, JSTaggedValue(numElementsInt32Array)); + + int64_t value1 = -2147483649; // to int32 : 2147483647 + int64_t value2 = 2147483648; // to int32 : -2147483648 + double value3 = 13.4; // to int32 : 13 + double value4 = 13.6; // to int32 : 13 + JSHandle handleTagValValueSet1(thread, JSTaggedValue(value1)); + JSHandle handleTagValValueSet2(thread, JSTaggedValue(value2)); + JSHandle handleTagValValueSet3(thread, JSTaggedValue(value3)); + JSHandle handleTagValValueSet4(thread, JSTaggedValue(value4)); + + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt32Array, JSTaggedValue(0), + handleTagValValueSet1)); + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt32Array, JSTaggedValue(0), + handleTagValValueSet2)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt32Array, JSTaggedValue(0), + handleTagValValueSet3)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValInt32Array, JSTaggedValue(0), + handleTagValValueSet4)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValInt32Array, + JSTaggedValue(0)); + + EXPECT_NE(value1, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value2, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value3, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value4, opResult4.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(2147483647, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(-2147483648, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult4.GetValue().GetTaggedValue().GetNumber()); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint32Array_001) +{ + uint32_t numElementsUint32Array = 100; + uint32_t scaleForUint32ValueSet = 100000; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint32Array = CreateNumberTypedArray(thread, JSType::JS_UINT32_ARRAY); + JSHandle handleTagValUint32Array = JSHandle::Cast(handleUint32Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint32Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint32Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint32Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint32Array->SetArrayLength(thread, JSTaggedValue(numElementsUint32Array)); + + CVector cVecOpResult = {}; + for (uint32_t i = 0; i < numElementsUint32Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint32Array, JSTaggedValue(i), + JSHandle(thread, + JSTaggedValue(std::numeric_limits::min() + i * scaleForUint32ValueSet)))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (uint32_t i = 0; i < numElementsUint32Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), + std::numeric_limits::min() + i * scaleForUint32ValueSet); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(numElementsUint32Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint32Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint32Array, + JSTaggedValue(numElementsUint32Array), JSHandle(thread, JSTaggedValue(0)))); +} + +// Nonstandard input value for Uint32Array +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Uint32Array_002) +{ + int32_t numElementsUint32Array = 16; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleUint32Array = CreateNumberTypedArray(thread, JSType::JS_UINT32_ARRAY); + JSHandle handleTagValUint32Array = JSHandle::Cast(handleUint32Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleUint32Array)); + int32_t byteLengthViewdArrayBuffer = sizeElement * numElementsUint32Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleUint32Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleUint32Array->SetArrayLength(thread, JSTaggedValue(numElementsUint32Array)); + + int64_t value1 = -1; // to uint32 : 4294967295 + int64_t value2 = 4294967296; // to uint32 : 0 + double value3 = 13.4; // to uint32 : 13 + double value4 = 13.6; // to uint32 : 13 + JSHandle handleTagValValueSet1(thread, JSTaggedValue(value1)); + JSHandle handleTagValValueSet2(thread, JSTaggedValue(value2)); + JSHandle handleTagValValueSet3(thread, JSTaggedValue(value3)); + JSHandle handleTagValValueSet4(thread, JSTaggedValue(value4)); + + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint32Array, JSTaggedValue(0), + handleTagValValueSet1)); + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint32Array, JSTaggedValue(0), + handleTagValValueSet2)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint32Array, JSTaggedValue(0), + handleTagValValueSet3)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(0)); + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValUint32Array, JSTaggedValue(0), + handleTagValValueSet4)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValUint32Array, + JSTaggedValue(0)); + + EXPECT_NE(value1, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value2, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value3, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_NE(value4, opResult4.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(4294967295, opResult1.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(0, opResult2.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult3.GetValue().GetTaggedValue().GetNumber()); + EXPECT_EQ(13, opResult4.GetValue().GetTaggedValue().GetNumber()); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Float32Array) +{ + uint32_t numElementsFloat32Array = 100; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleFloat32Array = CreateNumberTypedArray(thread, JSType::JS_FLOAT32_ARRAY); + JSHandle handleTagValFloat32Array = JSHandle::Cast(handleFloat32Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleFloat32Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsFloat32Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleFloat32Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleFloat32Array->SetArrayLength(thread, JSTaggedValue(numElementsFloat32Array)); + + CVector cVecOpResult = {}; + float floatMaxValue = std::numeric_limits::max(); + for (uint32_t i = 0; i < numElementsFloat32Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValFloat32Array, JSTaggedValue(i), + JSHandle(thread, + JSTaggedValue(floatMaxValue - (i * (floatMaxValue / numElementsFloat32Array)))))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat32Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (uint32_t i = 0; i < numElementsFloat32Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), + floatMaxValue - (i * (floatMaxValue / numElementsFloat32Array))); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat32Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat32Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat32Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat32Array, + JSTaggedValue(numElementsFloat32Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValFloat32Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValFloat32Array, + JSTaggedValue(numElementsFloat32Array), JSHandle(thread, JSTaggedValue(0)))); +} + +HWTEST_F_L0(JSTypedArrayTest, IntegerIndexedElementSet_Float64Array) +{ + uint32_t numElementsFloat64Array = 100; + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + JSHandle handleFloat64Array = CreateNumberTypedArray(thread, JSType::JS_FLOAT64_ARRAY); + JSHandle handleTagValFloat64Array = JSHandle::Cast(handleFloat64Array); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleFloat64Array)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsFloat64Array; + JSHandle handleTagValArrayBufferFrom = JSHandle::Cast( + factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleFloat64Array->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleFloat64Array->SetArrayLength(thread, JSTaggedValue(numElementsFloat64Array)); + + CVector cVecOpResult = {}; + double doubleMaxValue = std::numeric_limits::max(); + for (uint32_t i = 0; i < numElementsFloat64Array; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValFloat64Array, JSTaggedValue(i), + JSHandle(thread, JSTaggedValue( + doubleMaxValue - (i * (doubleMaxValue / numElementsFloat64Array)))))); + OperationResult opResult = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat64Array, + JSTaggedValue(i)); + cVecOpResult.push_back(opResult); + } + for (uint32_t i = 0; i < numElementsFloat64Array; i++) { + EXPECT_EQ(cVecOpResult.at(i).GetValue().GetTaggedValue().GetNumber(), + doubleMaxValue - (i * (doubleMaxValue / numElementsFloat64Array))); + } + cVecOpResult.clear(); + + OperationResult opResult1 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat64Array, + JSTaggedValue(-1)); + OperationResult opResult2 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat64Array, + JSTaggedValue(-0.0)); + OperationResult opResult3 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat64Array, + JSTaggedValue(1.1)); + OperationResult opResult4 = JSTypedArray::IntegerIndexedElementGet(thread, handleTagValFloat64Array, + JSTaggedValue(numElementsFloat64Array)); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult3.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult4.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValFloat64Array, JSTaggedValue(-1), + JSHandle(thread, JSTaggedValue(0)))); + EXPECT_FALSE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValFloat64Array, + JSTaggedValue(numElementsFloat64Array), JSHandle(thread, JSTaggedValue(0)))); +} + +/* + * Feature: JSTypedArray + * Function: FastElementGet + * SubFunction: IntegerIndexedElementSet + * FunctionPoints: Get Element At Index(uint32_t) Of JSTypedArray + * CaseDescription: Check whether the OperationResults returned through calling FastElementGet function from the + * JSTypedArray changed through calling IntegerIndexedElementSet function are within expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, FastElementGet_TypedArray) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + + for (uint32_t j = 0; j < cVecJSType.size(); j++) { + uint32_t numElementsTypedArray = 10; + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(j)); + JSHandle handleTagValTypedArray = JSHandle::Cast(handleTypedArray); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleTypedArray)); + uint32_t byteLengthViewdArrayBuffer = sizeElement * numElementsTypedArray; + JSHandle handleTagValArrayBufferFrom = + JSHandle::Cast(factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleTypedArray->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleTypedArray->SetArrayLength(thread, JSTaggedValue(numElementsTypedArray)); + + JSHandle handleTagValValueSet(thread, JSTaggedValue(cVecHandleTagValValueForTypedArray.at(j))); + for (uint32_t i = 0; i < numElementsTypedArray; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValTypedArray, JSTaggedValue(i), + handleTagValValueSet)); + } + for (uint32_t i = 0; i < numElementsTypedArray; i++) { + OperationResult opResult = JSTypedArray::FastElementGet(thread, handleTagValTypedArray, i); + EXPECT_EQ(opResult.GetValue().GetTaggedValue().GetNumber(), + handleTagValValueSet.GetTaggedValue().GetNumber()); + } + + OperationResult opResult1 = JSTypedArray::FastElementGet(thread, handleTagValTypedArray, -1); + OperationResult opResult2 = JSTypedArray::FastElementGet(thread, handleTagValTypedArray, + numElementsTypedArray); + EXPECT_EQ(opResult1.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + EXPECT_EQ(opResult2.GetValue().GetTaggedValue(), JSTaggedValue::Undefined()); + } +} + +/* + * Feature: JSTypedArray + * Function: DefineOwnProperty + * SubFunction: GetOwnProperty/HasProperty + * PropertyDescriptor::HasWritable/HasEnumerable/HasConfigurable/IsWritable/IsEnumerable/IsConfigurable + * FunctionPoints: Define Own Property For Element At Index(JSTaggedValue) Of JSTypedArray + * CaseDescription: Call DefineOwnProperty function with a JSTypedArray, a index(JSTaggedValue) and a source + * PropertyDescriptor, check whether the bool returned through calling HasProperty function with the + * JSTypedArray and the index(JSTaggedValue) is within expectations, check whether the target + * PropertyDescriptor changed through GetOwnProperty function is with expectations. + */ +HWTEST_F_L0(JSTypedArrayTest, DefineOwnProperty_TypedArray) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + + for (int j = 0; j < cVecJSType.size(); j++) { + int32_t numElementsTypedArray = 10; + JSHandle handleTagValValueDef(thread, cVecHandleTagValValueForTypedArray.at(j)); + PropertyDescriptor descFrom1(thread, handleTagValValueDef, true, true, true); + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(j)); + JSHandle handleTagValTypedArray = JSHandle::Cast(handleTypedArray); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleTypedArray)); + int32_t byteLengthViewdArrayBuffer = sizeElement * numElementsTypedArray; + JSHandle handleTagValArrayBufferFrom = + JSHandle::Cast(factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleTypedArray->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleTypedArray->SetArrayLength(thread, JSTaggedValue(numElementsTypedArray)); + + for (uint32_t i = 0; i < numElementsTypedArray; i++) { + JSHandle handleTagValKey(thread, JSTaggedValue(i)); + EXPECT_FALSE(JSTypedArray::HasProperty(thread, handleTagValTypedArray, handleTagValKey)); + EXPECT_TRUE(JSTypedArray::DefineOwnProperty(thread, handleTagValTypedArray, handleTagValKey, descFrom1)); + EXPECT_TRUE(JSTypedArray::HasProperty(thread, handleTagValTypedArray, handleTagValKey)); + EXPECT_TRUE(JSTaggedValue::StrictEqual(thread, handleTagValValueDef, + JSTypedArray::GetProperty(thread, handleTagValTypedArray, handleTagValKey).GetValue())); + + PropertyDescriptor descTo1(thread); + EXPECT_FALSE(descTo1.HasWritable() || descTo1.HasEnumerable() || descTo1.HasConfigurable()); + EXPECT_TRUE(JSTypedArray::GetOwnProperty(thread, handleTagValTypedArray, handleTagValKey, descTo1)); + EXPECT_TRUE(descTo1.HasWritable() && descTo1.HasEnumerable() && descTo1.HasConfigurable()); + EXPECT_TRUE(descTo1.IsWritable() && descTo1.IsEnumerable() && descTo1.IsConfigurable()); + EXPECT_TRUE(JSTaggedValue::StrictEqual(thread, descTo1.GetValue(), handleTagValValueDef)); + } + } +} + +/* + * Feature: JSTypedArray + * Function: SetProperty + * SubFunction: GetProperty/HasProperty + * FunctionPoints: Set Property For Element At Index(JSTaggedValue) Of JSTypedArray + * CaseDescription: Call SetProperty function with a JSTypedArray, a index(JSTaggedValue) and a source + * value(JSTaggedValue), check whether the bool returned through calling HasProperty function with the + * JSTypedArray and the index(JSTaggedValue) is within expectations, check whether the + * value(JSTaggedValue) of the OperationResult returned through calling GetProperty function with the + * JSTypedArray and the index(JSTaggedValue) is the same with the source value(JSTaggedValue). + */ +HWTEST_F_L0(JSTypedArrayTest, SetProperty_TypedArray) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + + for (int j = 0; j < cVecJSType.size(); j++) { + int32_t numElementsTypedArray = 10; + JSHandle handleTagValValueSet(thread, cVecHandleTagValValueForTypedArray.at(j)); + JSHandle handleTypedArray = CreateNumberTypedArray(thread, cVecJSType.at(j)); + JSHandle handleTagValTypedArray = JSHandle::Cast(handleTypedArray); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleTypedArray)); + int32_t byteLengthViewdArrayBuffer = sizeElement * numElementsTypedArray; + JSHandle handleTagValArrayBufferFrom = + JSHandle::Cast(factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + handleTypedArray->SetViewedArrayBuffer(thread, handleTagValArrayBufferFrom); + handleTypedArray->SetArrayLength(thread, JSTaggedValue(numElementsTypedArray)); + + for (uint32_t i = 0; i < numElementsTypedArray; i++) { + JSHandle handleTagValKey(thread, JSTaggedValue(i)); + EXPECT_FALSE(JSTypedArray::HasProperty(thread, handleTagValTypedArray, handleTagValKey)); + EXPECT_TRUE(JSTypedArray::SetProperty(thread, handleTagValTypedArray, handleTagValKey, + handleTagValValueSet)); + EXPECT_TRUE(JSTypedArray::HasProperty(thread, handleTagValTypedArray, handleTagValKey)); + EXPECT_TRUE(JSTaggedValue::StrictEqual(thread, handleTagValValueSet, + JSTypedArray::GetProperty(thread, handleTagValTypedArray, handleTagValKey).GetValue())); + } + } +} + +/* + * Feature: JSTypedArray + * Function: FastCopyElementToArray + * SubFunction: IntegerIndexedElementSet/TaggedArray::Get + * FunctionPoints: Copy All Elements Of JSTypedArray To TaggedArray Fast + * CaseDescription: Create a source JSTypedArray and a target TaggedArray, init the elements of the source JSTypedArray + * with a certain value(JSTaggedValue) through calling IntegerIndexedElementSet function. Call + * FastCopyElementToArray function with the source JSTypedArray and the target TaggedArray. Check + * whether the values(JSTaggedValue) returned through Get(TaggedArray) function are the same with the + * certain value(JSTaggedValue). + */ +HWTEST_F_L0(JSTypedArrayTest, FastCopyElementToArray_TypedArray) +{ + ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + + for (int j = 0; j < cVecJSType.size(); j++) { + int32_t numElementsTypedArray = 10; + JSHandle handleTagValValueSet(thread, cVecHandleTagValValueForTypedArray.at(j)); + JSHandle handleTypedArrayFrom = + CreateNumberTypedArray(thread, cVecJSType.at(j)); + JSHandle handleTagValTypedArrayFrom = JSHandle::Cast(handleTypedArrayFrom); + + uint32_t sizeElement = ecmascript::base::TypedArrayHelper::GetElementSize( + JSHandle::Cast(handleTypedArrayFrom)); + int32_t byteLengthViewdArrayBuffer = sizeElement * numElementsTypedArray; + JSHandle handleTagValArrayBuffer = + JSHandle::Cast(factory->NewJSArrayBuffer(byteLengthViewdArrayBuffer)); + JSHandle handleTagArrTo = factory->NewTaggedArray(byteLengthViewdArrayBuffer); + handleTypedArrayFrom->SetViewedArrayBuffer(thread, handleTagValArrayBuffer); + handleTypedArrayFrom->SetArrayLength(thread, JSTaggedValue(numElementsTypedArray)); + + for (uint32_t i = 0; i < numElementsTypedArray; i++) { + EXPECT_TRUE(JSTypedArray::IntegerIndexedElementSet(thread, handleTagValTypedArrayFrom, JSTaggedValue(i), + handleTagValValueSet)); + } + EXPECT_TRUE(JSTypedArray::FastCopyElementToArray(thread, handleTagValTypedArrayFrom, handleTagArrTo)); + for (uint32_t i = 0; i < numElementsTypedArray; i++) { + EXPECT_EQ(handleTagArrTo->Get(i), handleTagValValueSet.GetTaggedValue()); + } + } +} +} // namespace panda::test diff --git a/ecmascript/tests/name_dictionary_test.cpp b/ecmascript/tests/name_dictionary_test.cpp index cd8dbe8e7b8242936e3858546059c8e91edc0825..24b29cec2058dac8e3e5a3ea210facb308c1970e 100644 --- a/ecmascript/tests/name_dictionary_test.cpp +++ b/ecmascript/tests/name_dictionary_test.cpp @@ -78,7 +78,7 @@ HWTEST_F_L0(NameDictionaryTest, addKeyAndValue) int numOfElement = 64; JSHandle dictJShandle(thread, NameDictionary::Create(thread, numOfElement)); EXPECT_TRUE(*dictJShandle != nullptr); - JSHandle dictHandle(dictJShandle); + JSMutableHandle dictHandle(dictJShandle); JSHandle objFun = GetGlobalEnv(thread)->GetObjectFunction(); // create key and values @@ -103,7 +103,8 @@ HWTEST_F_L0(NameDictionaryTest, addKeyAndValue) PropertyAttributes metaData2; // test insert() - JSHandle dict(thread, NameDictionary::PutIfAbsent(thread, dictHandle, key1, value1, metaData1)); + NameDictionary *dict = NameDictionary::PutIfAbsent(thread, dictHandle, key1, value1, metaData1); + dictHandle.Update(JSTaggedValue(dict)); EXPECT_EQ(dict->EntriesCount(), 1); // test find() and lookup() @@ -111,10 +112,10 @@ HWTEST_F_L0(NameDictionaryTest, addKeyAndValue) EXPECT_EQ(key1.GetTaggedValue(), JSTaggedValue(dict->GetKey(entry1).GetRawData())); EXPECT_EQ(value1.GetTaggedValue(), JSTaggedValue(dict->GetValue(entry1).GetRawData())); - JSHandle dict2(thread, dict->PutIfAbsent(thread, dictHandle, key2, value2, metaData2)); + JSHandle dict2(thread, NameDictionary::PutIfAbsent(thread, dictHandle, key2, value2, metaData2)); EXPECT_EQ(dict2->EntriesCount(), 2); // test remove() - dict->Remove(thread, dictHandle, entry1); + dict = NameDictionary::Remove(thread, dictHandle, entry1); EXPECT_EQ(-1, dict->FindEntry(key1.GetTaggedValue())); EXPECT_EQ(dict->EntriesCount(), 1); } @@ -172,7 +173,8 @@ HWTEST_F_L0(NameDictionaryTest, ShrinkCapacity) PropertyAttributes metaData; // test insert() - dictHandle.Update(JSTaggedValue(NameDictionary::PutIfAbsent(thread, dictHandle, key, value, metaData))); + NameDictionary *newDict = NameDictionary::PutIfAbsent(thread, dictHandle, key, value, metaData); + dictHandle.Update(JSTaggedValue(newDict)); } keyArray[5] = '2'; @@ -183,7 +185,8 @@ HWTEST_F_L0(NameDictionaryTest, ShrinkCapacity) int entry = dictHandle->FindEntry(arrayHandle.GetTaggedValue()); EXPECT_NE(entry, -1); - dictHandle.Update(JSTaggedValue(NameDictionary::Remove(thread, dictHandle, entry))); + NameDictionary *newDict1 = NameDictionary::Remove(thread, dictHandle, entry); + dictHandle.Update(JSTaggedValue(newDict1)); EXPECT_EQ(dictHandle->EntriesCount(), 9); EXPECT_EQ(dictHandle->Size(), 16); } diff --git a/ecmascript/tests/test_helper.h b/ecmascript/tests/test_helper.h index 4a5a202f9e68100756d2e562ddf55cec6a6bdd4c..645a40c6863e275a356be174766c9b52c73c4a52 100644 --- a/ecmascript/tests/test_helper.h +++ b/ecmascript/tests/test_helper.h @@ -33,6 +33,7 @@ using panda::ecmascript::JSTaggedType; using panda::ecmascript::JSTaggedValue; using panda::ecmascript::JSThread; using panda::ecmascript::NUM_MANDATORY_JSFUNC_ARGS; +using ecmascript::JSRuntimeOptions; // Add for hmf tests platform, define to TEST_F or TEST_P when running gtest in gitlab #define HWTEST_F_L0(testsuit, testcase) HWTEST_F(testsuit, testcase, testing::ext::TestSize.Level0) @@ -64,7 +65,8 @@ public: JSTaggedType *newSp = sp - frameSize; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) FrameState *state = reinterpret_cast(newSp) - 1; - state->prev = sp; + state->base.frameType = static_cast(ecmascript::FrameType::INTERPRETER_FRAME); + state->base.prev = sp; state->pc = nullptr; state->sp = newSp; state->method = thread->GetEcmaVM()->GetMethodForNativeFunction(nullptr); @@ -80,7 +82,7 @@ public: // If you want to call once create, you can refer to BuiltinsMathTest for detail. static void CreateEcmaVMWithScope(PandaVM *&instance, JSThread *&thread, EcmaHandleScope *&scope) { - RuntimeOptions options; + JSRuntimeOptions options; options.SetShouldLoadBootPandaFiles(false); options.SetShouldInitializeIntrinsics(false); options.SetBootClassSpaces({"ecmascript"}); diff --git a/ecmascript/tooling/BUILD.gn b/ecmascript/tooling/BUILD.gn index e789c1b0862ccfb30eb4d57192e01c60490b29c3..170f72c5316d50c741e4b2d2750f24137d85a8a5 100644 --- a/ecmascript/tooling/BUILD.gn +++ b/ecmascript/tooling/BUILD.gn @@ -47,7 +47,7 @@ source_set("libark_ecma_debugger_static") { deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", - "$ark_root/runtime:arkruntime_gen_intrinsics_intrinsics_h", + "$ark_root/runtime:arkruntime_header_deps", ] cflags_cc = [ "-fvisibility=hidden" ] @@ -84,9 +84,7 @@ source_set("libark_ecma_debugger_test_static") { deps = [ "$ark_root/libpandabase:libarkbase", "$ark_root/libpandafile:libarkfile", - "$ark_root/runtime:arkruntime_gen_intrinsics_intrinsics_h", - "$ark_root/runtime:libarkruntime_options_gen_h", - "$ark_root/verification/gen:verification_verifier_messages_h", + "$ark_root/runtime:arkruntime_header_deps", ] } diff --git a/ecmascript/tooling/agent/js_backend.cpp b/ecmascript/tooling/agent/js_backend.cpp index 6172d2ae76ec2dd19e44961b1a0f4cd8c08f11a2..f7dd532c87ed547ffbd2f639dd03dfe0855b819e 100644 --- a/ecmascript/tooling/agent/js_backend.cpp +++ b/ecmascript/tooling/agent/js_backend.cpp @@ -32,14 +32,14 @@ JSBackend::JSBackend(FrontEnd *frontend) : frontend_(frontend) ecmaVm_ = static_cast(frontend)->GetEcmaVM(); hooks_ = std::make_unique(this); - debugger_ = DebuggerApi::CreateJSDebugger(Runtime::GetCurrent(), ecmaVm_); + debugger_ = DebuggerApi::CreateJSDebugger(ecmaVm_); DebuggerApi::RegisterHooks(debugger_, hooks_.get()); } JSBackend::JSBackend(const EcmaVM *vm) : ecmaVm_(vm) { // For testcases - debugger_ = DebuggerApi::CreateJSDebugger(Runtime::GetCurrent(), ecmaVm_); + debugger_ = DebuggerApi::CreateJSDebugger(ecmaVm_); } JSBackend::~JSBackend() @@ -458,7 +458,7 @@ PtJSExtractor *JSBackend::GetExtractor(const CString &url) bool JSBackend::GenerateCallFrames(CVector> *callFrames) { int32_t callFrameId = 0; - auto walkerFunc = [this, &callFrameId, &callFrames](const EcmaFrameHandler *frameHandler) -> StackState { + auto walkerFunc = [this, &callFrameId, &callFrames](const InterpretedFrameHandler *frameHandler) -> StackState { JSMethod *method = DebuggerApi::GetMethod(frameHandler); if (method->IsNative()) { LOG(INFO, DEBUGGER) << "GenerateCallFrames: Skip CFrame and Native method"; @@ -478,7 +478,8 @@ bool JSBackend::GenerateCallFrames(CVector> *callFram return DebuggerApi::StackWalker(ecmaVm_, walkerFunc); } -bool JSBackend::GenerateCallFrame(CallFrame *callFrame, const EcmaFrameHandler *frameHandler, int32_t callFrameId) +bool JSBackend::GenerateCallFrame(CallFrame *callFrame, + const InterpretedFrameHandler *frameHandler, int32_t callFrameId) { JSMethod *method = DebuggerApi::GetMethod(frameHandler); auto *pf = method->GetPandaFile(); @@ -528,7 +529,7 @@ bool JSBackend::GenerateCallFrame(CallFrame *callFrame, const EcmaFrameHandler * return true; } -std::unique_ptr JSBackend::GetLocalScopeChain(const EcmaFrameHandler *frameHandler, +std::unique_ptr JSBackend::GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, std::unique_ptr *thisObj) { auto localScope = std::make_unique(); diff --git a/ecmascript/tooling/agent/js_backend.h b/ecmascript/tooling/agent/js_backend.h index 44060029ca835479dd2eb009273dbbff4f06a132..2cdff1cff7eca9a058015047dc70b8433039042f 100644 --- a/ecmascript/tooling/agent/js_backend.h +++ b/ecmascript/tooling/agent/js_backend.h @@ -109,8 +109,8 @@ private: PtJSExtractor *GetExtractor(const panda_file::File *file); PtJSExtractor *GetExtractor(const CString &url); bool GenerateCallFrames(CVector> *callFrames); - bool GenerateCallFrame(CallFrame *callFrame, const EcmaFrameHandler *frameHandler, int32_t frameId); - std::unique_ptr GetLocalScopeChain(const EcmaFrameHandler *frameHandler, + bool GenerateCallFrame(CallFrame *callFrame, const InterpretedFrameHandler *frameHandler, int32_t frameId); + std::unique_ptr GetLocalScopeChain(const InterpretedFrameHandler *frameHandler, std::unique_ptr *thisObj); std::unique_ptr GetGlobalScopeChain(); std::optional SetValue(int32_t regIndex, std::unique_ptr *result, const CString &varValue); diff --git a/ecmascript/tooling/agent/js_pt_hooks.cpp b/ecmascript/tooling/agent/js_pt_hooks.cpp index a80170980bea0ad7246a02e724d2ed44cd4dbf60..52ea080ea077c294cf982dd561a1056ac0f5fc7f 100644 --- a/ecmascript/tooling/agent/js_pt_hooks.cpp +++ b/ecmascript/tooling/agent/js_pt_hooks.cpp @@ -19,10 +19,6 @@ namespace panda::tooling::ecmascript { void JSPtHooks::Breakpoint([[maybe_unused]] PtThread thread, const PtLocation &location) { - if (thread.GetId() != ManagedThread::NON_INITIALIZED_THREAD_ID) { - // Skip none-js thread - return; - } LOG(DEBUG, DEBUGGER) << "JSPtHooks: Breakpoint => " << location.GetMethodId() << ": " << location.GetBytecodeOffset(); @@ -38,13 +34,9 @@ void JSPtHooks::Paused(PauseReason reason) backend_->NotifyPaused({}, reason); } -void JSPtHooks::Exception(PtThread thread, [[maybe_unused]] const PtLocation &location, +void JSPtHooks::Exception([[maybe_unused]] PtThread thread, [[maybe_unused]] const PtLocation &location, [[maybe_unused]] PtObject exceptionObject, [[maybe_unused]] const PtLocation &catchLocation) { - if (thread.GetId() != ManagedThread::NON_INITIALIZED_THREAD_ID) { - // Skip none-js thread - return; - } LOG(DEBUG, DEBUGGER) << "JSPtHooks: Exception"; [[maybe_unused]] LocalScope scope(backend_->ecmaVm_); @@ -58,12 +50,8 @@ void JSPtHooks::Exception(PtThread thread, [[maybe_unused]] const PtLocation &lo } } -void JSPtHooks::SingleStep(PtThread thread, const PtLocation &location) +void JSPtHooks::SingleStep([[maybe_unused]] PtThread thread, const PtLocation &location) { - if (thread.GetId() != ManagedThread::NON_INITIALIZED_THREAD_ID) { - // Skip none-js thread - return; - } LOG(DEBUG, DEBUGGER) << "JSPtHooks: SingleStep => " << location.GetBytecodeOffset(); [[maybe_unused]] LocalScope scope(backend_->ecmaVm_); diff --git a/ecmascript/tooling/interface/debugger_api.cpp b/ecmascript/tooling/interface/debugger_api.cpp index 93ae8e71d082b8c09737ea64f8b6e87fe6b03ade..683bd3f91f3b09deac97badf94873d9583821ca1 100644 --- a/ecmascript/tooling/interface/debugger_api.cpp +++ b/ecmascript/tooling/interface/debugger_api.cpp @@ -49,12 +49,12 @@ CString DebuggerApi::ConvertToString(const std::string &str) return panda::ecmascript::ConvertToString(str); } -// EcmaFrameHandler +// InterpretedFrameHandler uint32_t DebuggerApi::GetStackDepth(const EcmaVM *ecmaVm) { uint32_t count = 0; - EcmaFrameHandler frameHandler(ecmaVm->GetJSThread()); - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + InterpretedFrameHandler frameHandler(ecmaVm->GetJSThread()); + for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { if (frameHandler.IsBreakFrame()) { continue; } @@ -63,10 +63,10 @@ uint32_t DebuggerApi::GetStackDepth(const EcmaVM *ecmaVm) return count; } -bool DebuggerApi::StackWalker(const EcmaVM *ecmaVm, std::function func) +bool DebuggerApi::StackWalker(const EcmaVM *ecmaVm, std::function func) { - EcmaFrameHandler frameHandler(ecmaVm->GetJSThread()); - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + InterpretedFrameHandler frameHandler(ecmaVm->GetJSThread()); + for (; frameHandler.HasFrame(); frameHandler.PrevInterpretedFrame()) { if (frameHandler.IsBreakFrame()) { continue; } @@ -84,37 +84,38 @@ bool DebuggerApi::StackWalker(const EcmaVM *ecmaVm, std::functionGetJSThread()).GetBytecodeOffset(); + return InterpretedFrameHandler(ecmaVm->GetJSThread()).GetBytecodeOffset(); } JSMethod *DebuggerApi::GetMethod(const EcmaVM *ecmaVm) { - return EcmaFrameHandler(ecmaVm->GetJSThread()).GetMethod(); + return InterpretedFrameHandler(ecmaVm->GetJSThread()).GetMethod(); } Local DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm, size_t index) { - auto value = EcmaFrameHandler(ecmaVm->GetJSThread()).GetVRegValue(index); + auto value = InterpretedFrameHandler(ecmaVm->GetJSThread()).GetVRegValue(index); JSHandle handledValue(ecmaVm->GetJSThread(), value); return JSNApiHelper::ToLocal(handledValue); } void DebuggerApi::SetVRegValue(const EcmaVM *ecmaVm, size_t index, Local value) { - return EcmaFrameHandler(ecmaVm->GetJSThread()).SetVRegValue(index, JSNApiHelper::ToJSTaggedValue(*value)); + return InterpretedFrameHandler(ecmaVm->GetJSThread()).SetVRegValue(index, JSNApiHelper::ToJSTaggedValue(*value)); } -uint32_t DebuggerApi::GetBytecodeOffset(const EcmaFrameHandler *frameHandler) +uint32_t DebuggerApi::GetBytecodeOffset(const InterpretedFrameHandler *frameHandler) { return frameHandler->GetBytecodeOffset(); } -JSMethod *DebuggerApi::GetMethod(const EcmaFrameHandler *frameHandler) +JSMethod *DebuggerApi::GetMethod(const InterpretedFrameHandler *frameHandler) { return frameHandler->GetMethod(); } -Local DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm, const EcmaFrameHandler *frameHandler, size_t index) +Local DebuggerApi::GetVRegValue(const EcmaVM *ecmaVm, + const InterpretedFrameHandler *frameHandler, size_t index) { auto value = frameHandler->GetVRegValue(index); JSHandle handledValue(ecmaVm->GetJSThread(), value); @@ -161,9 +162,9 @@ double DebuggerApi::StringToDouble(const uint8_t *start, const uint8_t *end, uin } // JSDebugger -JSDebugger *DebuggerApi::CreateJSDebugger(Runtime *runtime, const EcmaVM *ecmaVm) +JSDebugger *DebuggerApi::CreateJSDebugger(const EcmaVM *ecmaVm) { - return new JSDebugger(runtime, ecmaVm); + return new JSDebugger(ecmaVm); } void DebuggerApi::DestroyJSDebugger(JSDebugger *debugger) diff --git a/ecmascript/tooling/interface/debugger_api.h b/ecmascript/tooling/interface/debugger_api.h index fa9458c8922b55ca5137d28872637ea4dcfa8e75..4c94ee3c40bfd86b8c6c2803a29ef7672b3c1948 100644 --- a/ecmascript/tooling/interface/debugger_api.h +++ b/ecmascript/tooling/interface/debugger_api.h @@ -32,7 +32,7 @@ class JSDebugger; } // tooling::ecmascript namespace ecmascript { -class EcmaFrameHandler; +class InterpretedFrameHandler; class EcmaVM; class JSMethod; class JSThread; @@ -41,7 +41,7 @@ class JSThread; namespace panda::tooling::ecmascript { using panda::ecmascript::CString; -using panda::ecmascript::EcmaFrameHandler; +using panda::ecmascript::InterpretedFrameHandler; using panda::ecmascript::EcmaVM; using panda::ecmascript::JSMethod; using panda::ecmascript::JSThread; @@ -59,16 +59,17 @@ public: static CString ToCString(int32_t number); static CString ConvertToString(const std::string &str); - // EcmaFrameHandler + // InterpretedFrameHandler static uint32_t GetStackDepth(const EcmaVM *ecmaVm); - static bool StackWalker(const EcmaVM *ecmaVm, std::function func); + static bool StackWalker(const EcmaVM *ecmaVm, std::function func); static uint32_t GetBytecodeOffset(const EcmaVM *ecmaVm); static JSMethod *GetMethod(const EcmaVM *ecmaVm); static Local GetVRegValue(const EcmaVM *ecmaVm, size_t index); static void SetVRegValue(const EcmaVM *ecmaVm, size_t index, Local value); - static uint32_t GetBytecodeOffset(const EcmaFrameHandler *frameHandler); - static JSMethod *GetMethod(const EcmaFrameHandler *frameHandler); - static Local GetVRegValue(const EcmaVM *ecmaVm, const EcmaFrameHandler *frameHandler, size_t index); + static uint32_t GetBytecodeOffset(const InterpretedFrameHandler *frameHandler); + static JSMethod *GetMethod(const InterpretedFrameHandler *frameHandler); + static Local GetVRegValue(const EcmaVM *ecmaVm, + const InterpretedFrameHandler *frameHandler, size_t index); // JSThread static Local GetException(const EcmaVM *ecmaVm); @@ -82,7 +83,7 @@ public: static double StringToDouble(const uint8_t *start, const uint8_t *end, uint8_t radix); // JSDebugger - static JSDebugger *CreateJSDebugger(Runtime *runtime, const EcmaVM *ecmaVm); + static JSDebugger *CreateJSDebugger(const EcmaVM *ecmaVm); static void DestroyJSDebugger(JSDebugger *debugger); static std::optional RegisterHooks(JSDebugger *debugger, PtHooks *hooks); static std::optional SetBreakpoint(JSDebugger *debugger, const PtLocation &location); diff --git a/ecmascript/tooling/interface/js_debugger.cpp b/ecmascript/tooling/interface/js_debugger.cpp index 893707fa2af02d4b06afc3870af66944eb64db6b..e3fecc1ad822c02eb14c3bc76979f7baacae8eba 100644 --- a/ecmascript/tooling/interface/js_debugger.cpp +++ b/ecmascript/tooling/interface/js_debugger.cpp @@ -73,8 +73,7 @@ void JSDebugger::BytecodePcChanged(ManagedThread *thread, Method *method, uint32 HandleBreakpoint(JSThread::Cast(thread), JSMethod::Cast(method), bcOffset); } -bool JSDebugger::HandleBreakpoint([[maybe_unused]] const JSThread *thread, const JSMethod *method, - uint32_t bcOffset) +bool JSDebugger::HandleBreakpoint(const JSThread *thread, const JSMethod *method, uint32_t bcOffset) { if (!FindBreakpoint(method, bcOffset)) { return false; @@ -83,7 +82,7 @@ bool JSDebugger::HandleBreakpoint([[maybe_unused]] const JSThread *thread, const auto *pf = method->GetPandaFile(); PtLocation location {pf->GetFilename().c_str(), method->GetFileId(), bcOffset}; if (hooks_ != nullptr) { - hooks_->Breakpoint(PtThread(ManagedThread::NON_INITIALIZED_THREAD_ID), location); + hooks_->Breakpoint(PtThread(thread->GetId()), location); } return true; @@ -99,7 +98,7 @@ void JSDebugger::HandleExceptionThrowEvent(const JSThread *thread, const JSMetho PtLocation throwLocation {pf->GetFilename().c_str(), method->GetFileId(), bcOffset}; if (hooks_ != nullptr) { - hooks_->Exception(PtThread(ManagedThread::NON_INITIALIZED_THREAD_ID), throwLocation, PtObject(), throwLocation); + hooks_->Exception(PtThread(thread->GetId()), throwLocation, PtObject(), throwLocation); } } diff --git a/ecmascript/tooling/interface/js_debugger.h b/ecmascript/tooling/interface/js_debugger.h index 416ab5cee8d394ee76ad3cd1eeb938a4996e89d2..f0b4de9d7e5bebb6ab0d36c35411df13c8acd782 100644 --- a/ecmascript/tooling/interface/js_debugger.h +++ b/ecmascript/tooling/interface/js_debugger.h @@ -27,23 +27,15 @@ using panda::ecmascript::CUnorderedSet; class JSDebugger : public DebugInterface, RuntimeListener { public: - JSDebugger(const Runtime *runtime, const EcmaVM *vm) : runtime_(runtime), ecmaVm_(vm) + JSDebugger(const EcmaVM *vm) : ecmaVm_(vm) { - auto notificationMgr = runtime_->GetNotificationManager(); - // set EcmaVM rendezvous - notificationMgr->SetRendezvous(ecmaVm_->GetRendezvous()); + auto notificationMgr = ecmaVm_->GetNotificationManager(); notificationMgr->AddListener(this, JSDEBUG_EVENT_MASK); - // set PandaVM rendezvous - notificationMgr->SetRendezvous(runtime_->GetPandaVM()->GetRendezvous()); } ~JSDebugger() override { - auto notificationMgr = runtime_->GetNotificationManager(); - // set EcmaVM rendezvous - notificationMgr->SetRendezvous(ecmaVm_->GetRendezvous()); + auto notificationMgr = ecmaVm_->GetNotificationManager(); notificationMgr->RemoveListener(this, JSDEBUG_EVENT_MASK); - // set PandaVM rendezvous - notificationMgr->SetRendezvous(runtime_->GetPandaVM()->GetRendezvous()); } std::optional RegisterHooks(PtHooks *hooks) override @@ -234,7 +226,6 @@ private: void HandleExceptionThrowEvent(const JSThread *thread, const JSMethod *method, uint32_t bcOffset); bool HandleStep(const JSThread *thread, const JSMethod *method, uint32_t bcOffset); - const Runtime *runtime_; const EcmaVM *ecmaVm_; PtHooks *hooks_ {nullptr}; diff --git a/ecmascript/tooling/pt_js_extractor.cpp b/ecmascript/tooling/pt_js_extractor.cpp index 7498f82b05b302ae6a890c9d41d687bcffd23956..fe9e50f4eee3f86f617397fbd79c82c7c280f933 100644 --- a/ecmascript/tooling/pt_js_extractor.cpp +++ b/ecmascript/tooling/pt_js_extractor.cpp @@ -17,7 +17,7 @@ #include "ecmascript/tooling/pt_js_extractor.h" namespace panda::tooling::ecmascript { -using panda::ecmascript::EcmaFrameHandler; +using panda::ecmascript::InterpretedFrameHandler; using panda::ecmascript::JSTaggedType; uint32_t PtJSExtractor::SingleStepper::GetStackDepth() const { diff --git a/ecmascript/tooling/test/debugger_commands_test.cpp b/ecmascript/tooling/test/debugger_commands_test.cpp index d2d9c537db2bf384be2aed5513e5d634c8224c3c..cc9c1bf1d764a0724fac394cca9a0ac572061d61 100644 --- a/ecmascript/tooling/test/debugger_commands_test.cpp +++ b/ecmascript/tooling/test/debugger_commands_test.cpp @@ -62,7 +62,7 @@ protected: HWTEST_F_L0(DebuggerCommandsTest, CreateDebuggerTest) { - std::unique_ptr debugger = std::make_unique(Runtime::GetCurrent(), ecmaVm); + std::unique_ptr debugger = std::make_unique(ecmaVm); ASSERT_NE(debugger, nullptr); } } // namespace panda::test \ No newline at end of file diff --git a/ecmascript/weak_vector-inl.h b/ecmascript/weak_vector-inl.h index 9f27e48850ce5a4f490b5f49c78e8f9b45ce1006..d17c66aa7edd7b7aa3f1a7bad295e0c26cdc3660 100644 --- a/ecmascript/weak_vector-inl.h +++ b/ecmascript/weak_vector-inl.h @@ -49,7 +49,7 @@ JSTaggedValue WeakVector::Get(array_size_t index) const void WeakVector::Set(const JSThread *thread, array_size_t index, JSTaggedValue value) { ASSERT(index < GetCapacity()); - return TaggedArray::Set(thread, VectorToArrayIndex(index), value); + TaggedArray::Set(thread, VectorToArrayIndex(index), value); } void WeakVector::SetEnd(const JSThread *thread, array_size_t end) diff --git a/js_runtime_config.gni b/js_runtime_config.gni index ea4700b46133793ad282302c26840b97d036cd91..df2bc82f828d837f3d4575a506b70661e5bb2f26 100644 --- a/js_runtime_config.gni +++ b/js_runtime_config.gni @@ -14,7 +14,57 @@ ark_root = "//ark/runtime_core" js_root = "//ark/js_runtime" compile_llvm_online = false +run_with_asan = false +enable_stub_aot = false +asan_lib_path = "/usr/lib/llvm-10/lib/clang/10.0.0/lib/linux" # For OpenHarmony build, always link with the static lib: sdk_libc_secshared_dep = "//utils/native/base:utilsecurec" sdk_libc_secshared_config = "//utils/native/base:utils_config" + +# Generate file for a template and YAML data provided. +# +# Mandatory arguments: +# data_file -- YAML data full name +# template_file -- template full name +# output_file -- output file full name +# requires -- a list of scripts that provide data-querying API for templates +# extra_dependencies -- a list of files that should be considered as dependencies, must be lable +template("ark_gen_file") { + assert(defined(invoker.data_file), "data_file is required!") + assert(defined(invoker.template_file), "template_file is required!") + assert(defined(invoker.output_file), "output_file is required!") + + requires = "" + if (defined(invoker.requires)) { + requires = string_join(",", rebase_path(invoker.requires, root_build_dir)) + } + + extra_dependencies = [] + if (defined(invoker.extra_dependencies)) { + extra_dependencies += invoker.extra_dependencies + } + + action("$target_name") { + script = "$ark_root/isa/gen.rb" + + # rerun action when data file or template file update + inputs = [ + invoker.template_file, + invoker.data_file, + ] + outputs = [ invoker.output_file ] + args = [ + "--template", + rebase_path(invoker.template_file, root_build_dir), + "--data", + rebase_path(invoker.data_file, root_build_dir), + "--require", + requires, + "--output", + rebase_path(outputs[0]), + ] + + deps = extra_dependencies + } +} diff --git a/llvm.patch b/llvm.patch new file mode 100644 index 0000000000000000000000000000000000000000..86f6381f71c9dd8ed094552e90a2e56d3a7ab7b2 --- /dev/null +++ b/llvm.patch @@ -0,0 +1,121 @@ +diff --git a/llvm/CMakeLists.txt b/llvm/CMakeLists.txt +index 0e85afa82c7..f56219422d2 100644 +--- a/llvm/CMakeLists.txt ++++ b/llvm/CMakeLists.txt +@@ -507,6 +507,12 @@ option(LLVM_BUILD_EXAMPLES + "Build the LLVM example programs. If OFF, just generate build targets." OFF) + option(LLVM_INCLUDE_EXAMPLES "Generate build targets for the LLVM examples" ON) + ++option(BUILD_ARK_GC_SUPPORT ++ "ARK support GC. If ON, support GC." OFF) ++if(BUILD_ARK_GC_SUPPORT) ++ add_definitions(-DARK_GC_SUPPORT) ++endif(ARK_SUPPORT_GC) ++ + if(LLVM_BUILD_EXAMPLES) + add_definitions(-DBUILD_EXAMPLES) + endif(LLVM_BUILD_EXAMPLES) +diff --git a/llvm/lib/Target/X86/X86FrameLowering.cpp b/llvm/lib/Target/X86/X86FrameLowering.cpp +index 1da20371caf..875184f32b2 100644 +--- a/llvm/lib/Target/X86/X86FrameLowering.cpp ++++ b/llvm/lib/Target/X86/X86FrameLowering.cpp +@@ -31,6 +31,7 @@ + #include "llvm/Support/Debug.h" + #include "llvm/Target/TargetOptions.h" + #include ++#include + + using namespace llvm; + +@@ -1169,6 +1170,29 @@ void X86FrameLowering::emitPrologue(MachineFunction &MF, + MFI.setOffsetAdjustment(-StackSize); + } + ++#ifdef ARK_GC_SUPPORT ++ // push marker ++ if (MF.getFunction().hasFnAttribute("js-stub-call")) ++ { ++ int64_t marker = 0x0; ++ MF.getFunction() ++ .getFnAttribute("js-stub-call") ++ .getValueAsString() ++ .getAsInteger(10, marker);//marker 1 break frame ++ std::cout << __LINE__ << " marker:" << std::dec << marker << std::endl; ++ ++ BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64i32)) ++ .addImm(marker) ++ .setMIFlag(MachineInstr::FrameSetup); ++ /*reserve thread.fp */ ++ if (marker == 1) { ++ BuildMI(MBB, MBBI, DL, TII.get(X86::PUSH64i32)) ++ .addImm(marker) ++ .setMIFlag(MachineInstr::FrameSetup); ++ } ++ } ++#endif ++ + // For EH funclets, only allocate enough space for outgoing calls. Save the + // NumBytes value that we would've used for the parent frame. + unsigned ParentFrameNumBytes = NumBytes; +@@ -1635,6 +1659,27 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, + uint64_t SEHStackAllocAmt = NumBytes; + + if (HasFP) { ++#ifdef ARK_GC_SUPPORT ++ if (MF.getFunction().hasFnAttribute("js-stub-call")) ++ { ++ int64_t marker = 0x0; ++ MF.getFunction() ++ .getFnAttribute("js-stub-call") ++ .getValueAsString() ++ .getAsInteger(10, marker);//marker 1 break frame ++ ++ // pop marker ++ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), ++ MachineFramePtr) ++ .setMIFlag(MachineInstr::FrameDestroy); ++ if (marker == 1) { ++ // pop thread.fp ++ BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), ++ MachineFramePtr) ++ .setMIFlag(MachineInstr::FrameDestroy); ++ } ++ } ++#endif + // Pop EBP. + BuildMI(MBB, MBBI, DL, TII.get(Is64Bit ? X86::POP64r : X86::POP32r), + MachineFramePtr) +@@ -1993,8 +2038,33 @@ bool X86FrameLowering::assignCalleeSavedSpillSlots( + + if (hasFP(MF)) { + // emitPrologue always spills frame register the first thing. ++#ifdef ARK_GC_SUPPORT ++ if (MF.getFunction().hasFnAttribute("js-stub-call")) { ++ int64_t marker = 0x0; ++ MF.getFunction() ++ .getFnAttribute("js-stub-call") ++ .getValueAsString() ++ .getAsInteger(10, marker);//marker 1 break frame ++ if (marker == 1) { ++ SpillSlotOffset -= 3 * SlotSize; // add type and thread.fp ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ CalleeSavedFrameSize += 16; ++ } else { ++ SpillSlotOffset -= 2 * SlotSize; // add type ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ CalleeSavedFrameSize += 8; ++ } ++ } else { ++ SpillSlotOffset -= SlotSize; // add type and thread.fp ++ MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++ } ++#else + SpillSlotOffset -= SlotSize; + MFI.CreateFixedSpillStackObject(SlotSize, SpillSlotOffset); ++#endif + + // Since emitPrologue and emitEpilogue will handle spilling and restoring of + // the frame register, we can delete it from CSI list and not have to worry diff --git a/test/copy_resource.py b/test/copy_resource.py index b6b3a10cd18d1b2c669cb36a867bc7b16d0e2755..dfaa369555be9dbca4e80ed15f5e9f86a2e7f697 100755 --- a/test/copy_resource.py +++ b/test/copy_resource.py @@ -35,21 +35,20 @@ def parse_args(): return args -def copy_xml(args): - """copy resource xml to test direction.""" +def copy_res(args): + """copy resources to test direction.""" src_xml_file = os.path.join(args.src_path, args.src_xml) - dst_xml_file = os.path.join(args.dst_path, args.src_xml) if not os.path.isfile(src_xml_file): print(args.src_xml + " not exist.") return - if not os.path.exists(args.dst_path): - os.makedirs(args.dst_path) + if os.path.exists(args.dst_path): + shutil.rmtree(args.dst_path) - shutil.copyfile(src_xml_file, dst_xml_file) + shutil.copytree(args.src_path, args.dst_path) if __name__ == '__main__': input_args = parse_args() - copy_xml(input_args) + copy_res(input_args) diff --git a/test/moduletest/BUILD.gn b/test/moduletest/BUILD.gn index a2fe10f7623e8fccfc405eff1ae4ff4994276ff8..ea18c4b160f49f262fe98dac3c5ff422f8684622 100644 --- a/test/moduletest/BUILD.gn +++ b/test/moduletest/BUILD.gn @@ -24,8 +24,7 @@ group("ark_js_moduletest") { "globalrecord:globalrecordAction", "helloworld:helloworldAction", "lexicalenv:lexicalenvAction", - - # "module:moduleAction", + "module:moduleAction", "multiargs:multiargsAction", "newobjdynrange:newobjdynrangeAction", "promise:promiseAction", diff --git a/test/moduletest/helloworld/BUILD.gn b/test/moduletest/helloworld/BUILD.gn index 1f9c33ffa37a7ff67e29ea4b154ae6de22e26e67..1c00da7d4dd8ae998fb9632e48d3c72824747e29 100644 --- a/test/moduletest/helloworld/BUILD.gn +++ b/test/moduletest/helloworld/BUILD.gn @@ -13,6 +13,21 @@ import("//ark/js_runtime/test/test_helper.gni") -host_moduletest_action("helloworld") { +host_moduletest_action("second_module") { + deps = [] +} + +host_moduletest_action("third_module") { deps = [] } + +host_moduletest_action("helloworld") { + extra_modules = [ + "second_module", + "third_module", + ] + deps = [ + ":gen_second_module_abc", + ":gen_third_module_abc", + ] +} diff --git a/test/moduletest/helloworld/expect_output.txt b/test/moduletest/helloworld/expect_output.txt index d53f276158d8a037f602c28faac1bad1c36ea646..59b7042f6009e8ee2a4c573f907e1249d74c311b 100644 --- a/test/moduletest/helloworld/expect_output.txt +++ b/test/moduletest/helloworld/expect_output.txt @@ -12,3 +12,5 @@ # limitations under the License. hello world ! +second_module got: I'm helloworld! +third_module got: I'm second_module! diff --git a/test/moduletest/helloworld/helloworld.js b/test/moduletest/helloworld/helloworld.js index b41a5e95bf3dd92278d5d80fa115d745a0684843..a08f2c600f629ea831df32f55d09cf1b9ccd6525 100644 --- a/test/moduletest/helloworld/helloworld.js +++ b/test/moduletest/helloworld/helloworld.js @@ -13,4 +13,5 @@ * limitations under the License. */ +var helloworld = "I'm helloworld!" print("hello world !") \ No newline at end of file diff --git a/test/moduletest/helloworld/second_module.js b/test/moduletest/helloworld/second_module.js new file mode 100644 index 0000000000000000000000000000000000000000..0f42b9ab1568604c890e3b25f464ca03cd0aa3e5 --- /dev/null +++ b/test/moduletest/helloworld/second_module.js @@ -0,0 +1,17 @@ +/* + * Copyright (c) 2021 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. + */ + +var second_module = "I'm second_module!" +print("second_module got: " + helloworld) \ No newline at end of file diff --git a/test/moduletest/helloworld/third_module.js b/test/moduletest/helloworld/third_module.js new file mode 100644 index 0000000000000000000000000000000000000000..e1952b40bc60e9aade4fd5a3db7f27398846ce54 --- /dev/null +++ b/test/moduletest/helloworld/third_module.js @@ -0,0 +1,16 @@ +/* + * Copyright (c) 2021 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. + */ + +print("third_module got: " + second_module) \ No newline at end of file diff --git a/test/moduletest/module/BUILD.gn b/test/moduletest/module/BUILD.gn index fbf4dea604bd2bf0419d0fdd4efad43e1f033682..5e9c5ddd6310c7fc9a3f7980f8572f3384c0881d 100644 --- a/test/moduletest/module/BUILD.gn +++ b/test/moduletest/module/BUILD.gn @@ -15,10 +15,12 @@ import("//ark/js_runtime/test/test_helper.gni") host_moduletest_action("B") { deps = [] + is_module = true } host_moduletest_action("C") { deps = [] + is_module = true } host_moduletest_action("module") { @@ -26,4 +28,5 @@ host_moduletest_action("module") { ":gen_B_abc", ":gen_C_abc", ] + is_module = true } diff --git a/test/test_helper.gni b/test/test_helper.gni index 4cc7e2300e5a007228604dd23dd13a7b43819bd7..498344cc688ec6d6e6be0d09900a648ed34e99fc 100644 --- a/test/test_helper.gni +++ b/test/test_helper.gni @@ -38,6 +38,7 @@ template("host_unittest_action") { _host_test_target_ = ":${_target_name_}(${host_toolchain})" _root_out_dir_ = get_label_info(_host_test_target_, "root_out_dir") + deps = [ _host_test_target_ ] script = "//ark/js_runtime/test/run_ark_executable.py" @@ -50,7 +51,8 @@ template("host_unittest_action") { "0", "--env-path", rebase_path(_root_out_dir_) + "/ark/ark:" + rebase_path(_root_out_dir_) + - "/test/test:" + rebase_path(_root_out_dir_) + "/global/${icu_path}:" + + "/ark/ark_js_runtime:" + rebase_path(_root_out_dir_) + "/test/test:" + + rebase_path(_root_out_dir_) + "/global/${icu_path}:" + rebase_path("//prebuilts/clang/ohos/linux-x86_64/llvm/lib/"), ] @@ -64,6 +66,10 @@ template("host_unittest_action") { template("host_moduletest_action") { _target_name_ = "${target_name}" _deps_ = invoker.deps + _is_module_ = false + if (defined(invoker.is_module) && invoker.is_module) { + _is_module_ = true + } _test_js_path_ = "./${_target_name_}.js" _test_abc_path_ = "$target_out_dir/${_target_name_}.abc" @@ -75,6 +81,9 @@ template("host_moduletest_action") { src_js = rebase_path(_test_js_path_) dst_file = rebase_path(_test_abc_path_) extra_args = [ "--debug" ] + if (_is_module_) { + extra_args += [ "--module" ] + } in_puts = [ _test_js_path_, @@ -83,6 +92,17 @@ template("host_moduletest_action") { out_puts = [ _test_abc_path_ ] } + _extra_modules_ = [] + if (defined(invoker.extra_modules)) { + foreach(module, invoker.extra_modules) { + _extra_modules_ += [ "$target_out_dir/${module}.abc" ] + } + } + _test_abc_paths_ = rebase_path(_test_abc_path_) + foreach(extra_module, _extra_modules_) { + _test_abc_paths_ += ":" + rebase_path(extra_module) + } + action("${_target_name_}Action") { testonly = true @@ -93,6 +113,7 @@ template("host_moduletest_action") { ":gen_${_target_name_}_abc", _host_jsvm_target_, ] + deps += _deps_ script = "//ark/js_runtime/test/run_ark_executable.py" @@ -100,7 +121,7 @@ template("host_moduletest_action") { "--script-file", rebase_path(_root_out_dir_) + "/ark/ark_js_runtime/ark_js_vm", "--script-args", - rebase_path(_test_abc_path_), + _test_abc_paths_, "--expect-file", rebase_path(_test_expect_path_), "--env-path", @@ -111,6 +132,7 @@ template("host_moduletest_action") { ] inputs = [ _test_abc_path_ ] + inputs += _extra_modules_ outputs = [ "$target_out_dir/${_target_name_}/" ] }