From c60fee9ed08dcf6c78f04cb98691ba079eef5286 Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Wed, 19 Oct 2022 19:08:25 +0300 Subject: [PATCH 1/4] Cleanup unused runtime features Signed-off-by: Vsevolod Pukhov --- runtime/ecma_vm.cpp | 4 - runtime/ecma_vm.h | 5 - runtime/frames.h | 232 ------------------- runtime/interpreter/fast_runtime_stub-inl.h | 28 --- runtime/interpreter/interpreter.h | 1 - runtime/js_runtime_options.h | 89 +------ runtime/js_thread.cpp | 27 --- runtime/js_thread.h | 70 +----- tests/runtime/common/huge_object_test.cpp | 1 - tests/runtime/common/js_object_test.cpp | 2 - tests/runtime/common/js_serializer_test.cpp | 3 - tests/runtime/common/object_factory_test.cpp | 2 - 12 files changed, 2 insertions(+), 462 deletions(-) delete mode 100644 runtime/frames.h diff --git a/runtime/ecma_vm.cpp b/runtime/ecma_vm.cpp index ba6fee4b7..1f31c8162 100644 --- a/runtime/ecma_vm.cpp +++ b/runtime/ecma_vm.cpp @@ -256,10 +256,6 @@ bool EcmaVM::Initialize() globalEnvHandle->SetEmptyTaggedQueue(thread_, factory_->NewTaggedQueue(0)); globalEnvHandle->SetTemplateMap(thread_, TemplateMap::Create(thread_)); globalEnvHandle->SetRegisterSymbols(GetJSThread(), SymbolTable::Create(GetJSThread())); -#ifdef ECMASCRIPT_ENABLE_STUB_AOT - std::string module_file = options_.GetStubModuleFile(); - thread_->LoadFastStubModule(module_file.c_str()); -#endif SetupRegExpResultCache(); micro_job_queue_ = factory_->NewMicroJobQueue().GetTaggedValue(); diff --git a/runtime/ecma_vm.h b/runtime/ecma_vm.h index 3b3da59ff..8f0c92754 100644 --- a/runtime/ecma_vm.h +++ b/runtime/ecma_vm.h @@ -404,11 +404,6 @@ public: return native_methods_; } - void SetEnableForceGC(bool enable) - { - options_.SetEnableForceGC(enable); - } - void SetData(void *data) { data_ = data; diff --git a/runtime/frames.h b/runtime/frames.h deleted file mode 100644 index 9ec736d29..000000000 --- a/runtime/frames.h +++ /dev/null @@ -1,232 +0,0 @@ -/* - * Copyright (c) 2021-2022 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -// in aot project, three Frame: Interpreter Frame、Runtime Frame、Optimized Frame. Optimized Frame -// call Runtime function, generate OptLeaveFrame Frame(gc related context (patchid、sp、fp) is saved to frame) -// then return Optimized thread.sp restore orignal sp. - -// Frame Layout -// Interpreter Frame(alias **iframe** ) Layout as follow: -// ``` -// +----------------------------------+-------------------+ -// | argv[n-1] | ^ -// |----------------------------------| | -// | ...... | | -// |----------------------------------| | -// | thisArg [maybe not exist] | | -// |----------------------------------| | -// | new_target [maybe not exist] | | -// |----------------------------------| | -// | callTarget [deleted] | | -// |----------------------------------| | -// | ...... | | -// |----------------------------------| | -// | Vregs [not exist in native] | | -// +----------------------------------+--------+ interpreter frame -// | base.frameType | ^ | -// |----------------------------------| | | -// | base.prev(pre stack pointer) | | | -// |----------------------------------| | | -// | numActualArgs [deleted] | | | -// |----------------------------------| | | -// | env | | | -// |----------------------------------| | | -// | acc | | | -// |----------------------------------|InterpretedFrame | -// | profileTypeInfo | | | -// |----------------------------------| | | -// | constantpool | | | -// |----------------------------------| | | -// | method [changed to function] | | | -// |----------------------------------| | | -// | 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. - -// For Example: -// ``` -// call call -// foo -----------------> bar -----------------------> rtfunc -// (interpret frame) (OptLeaveFrame) (Runtime Frame) -// ``` - -// Frame Layout as follow: -// ``` -// +----------------------------------+-------------------+ -// | argv[n-1] | ^ -// |----------------------------------| | -// | ...... | | -// |----------------------------------| | -// | thisArg [maybe not exist] | | -// |----------------------------------| | -// | new_target [maybe not exist] | | -// |----------------------------------| | -// | ...... | | -// |----------------------------------| | -// | Vregs | | -// +----------------------------------+--------+ foo's frame -// | base.frameType | ^ | -// |----------------------------------| | | -// | base.prev(pre stack pointer) | | | -// |----------------------------------| | | -// | env | | | -// |----------------------------------| | | -// | acc | | | -// |----------------------------------| | | -// | profileTypeInfo |InterpretedFrame | -// |----------------------------------| | | -// | constantpool | | | -// |----------------------------------| | | -// | function | | | -// |----------------------------------| | | -// | sp(current stack point) | | | -// |----------------------------------| | | -// | pc(bytecode addr) | v v -// +----------------------------------+--------+----------+ -// | ............. | -// +--------------------------+---------------------------+ -// | patchID | ^ ^ -// |- - - - - - - - - | | | -// | fp | Fixed | -// |- - - - - - - - - | OptLeaveFrame | -// | sp | | bar's frame Header -// |- - - - - - - - - | | | -// | prev | | -// |- - - - - - - - - | | | -// | frameType | v | -// +--------------------------+---------------------------+ -// | ............. | -// +--------------------------+---------------------------+ -// | | -// | rtfunc's Frame | -// | | -// +------------------------------------------------------+ -// ``` -// Iterator: -// rtfunc get bar's Frame **currentfp** by calling GetCurrentSPFrame. -// 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 "plugins/ecmascript/runtime/js_tagged_value.h" - -namespace panda::ecmascript { -class JSThread; -enum class FrameType : uint64_t { - OPTIMIZED_FRAME = 0, - OPTIMIZED_ENTRY_FRAME = 1, - INTERPRETER_FRAME = 2, - OPTIMIZED_LEAVE_FRAME = 3, -}; - -struct FrameConstants { -public: -#ifdef PANDA_TARGET_AMD64 - static constexpr int SP_DWARF_REG_NUM = 7; - static constexpr int FP_DWARF_REG_NUM = 6; - static constexpr int SP_OFFSET = 2; -#else -#ifdef PANDA_TARGET_ARM64 - static constexpr int SP_DWARF_REG_NUM = 31; /* x31 */ - static constexpr int FP_DWARF_REG_NUM = 29; /* x29 */ - static constexpr int SP_OFFSET = -3; -#else -#ifdef PANDA_TARGET_ARM32 - static constexpr int SP_DWARF_REG_NUM = 13; - static constexpr int FP_DWARF_REG_NUM = 11; - static constexpr int SP_OFFSET = 0; -#else - static constexpr int SP_DWARF_REG_NUM = 0; - static constexpr int FP_DWARF_REG_NUM = 0; - static constexpr int SP_OFFSET = 0; -#endif -#endif -#endif - static constexpr int AARCH64_SLOT_SIZE = sizeof(uint64_t); - static constexpr int AMD64_SLOT_SIZE = sizeof(uint64_t); - static constexpr int ARM32_SLOT_SIZE = sizeof(uint32_t); -}; - -class InterpretedFrameBase { -public: - InterpretedFrameBase() = default; - ~InterpretedFrameBase() = default; - // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) - JSTaggedType *prev; // for llvm :c-fp ; for interrupt: thread-fp for gc - - // NOLINTNEXTLINE(misc-non-private-member-variables-in-classes) - FrameType type; - DEFAULT_MOVE_SEMANTIC(InterpretedFrameBase); - DEFAULT_COPY_SEMANTIC(InterpretedFrameBase); -}; - -// align with 8 -// NOLINTNEXTLINE(cppcoreguidelines-pro-type-member-init) -struct InterpretedFrame { - const uint8_t *pc; - JSTaggedType *sp; - // aligned with 8 bits - alignas(sizeof(uint64_t)) JSTaggedValue constpool; - JSTaggedValue function; - JSTaggedValue profile_type_info; - JSTaggedValue acc; - JSTaggedValue env; - InterpretedFrameBase base; - static InterpretedFrame *GetFrameFromSp(JSTaggedType *sp) - { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - return reinterpret_cast(sp) - 1; - } - static constexpr uint32_t K_SIZE_ON64_PLATFORM = - 2 * sizeof(int64_t) + 5 * sizeof(JSTaggedValue) + 2 * sizeof(uint64_t); - static constexpr uint32_t K_SIZE_ON32_PLATFORM = - 2 * sizeof(int32_t) + 5 * sizeof(JSTaggedValue) + 2 * sizeof(uint64_t); -}; -static_assert(sizeof(InterpretedFrame) % sizeof(uint64_t) == 0U); - -struct OptLeaveFrame { - FrameType type; - JSTaggedType *prev_fp; // set cursp here - uintptr_t sp; - uintptr_t fp; - uint64_t patch_id; - static OptLeaveFrame *GetFrameFromSp(JSTaggedType *sp) - { - return reinterpret_cast(reinterpret_cast(sp) - - MEMBER_OFFSET(OptLeaveFrame, prev_fp)); - } - static constexpr uint32_t K_SIZE_ON64_PLATFORM = sizeof(FrameType) + 4 * sizeof(uint64_t); - static constexpr uint32_t K_SIZE_ON32_PLATFORM = sizeof(FrameType) + 3 * sizeof(int32_t) + sizeof(uint64_t); - static constexpr uint32_t K_PREV_FP_OFFSET = sizeof(FrameType); -}; - -#ifdef PANDA_TARGET_64 -static_assert(InterpretedFrame::K_SIZE_ON64_PLATFORM == sizeof(InterpretedFrame)); -#endif -#ifdef PANDA_TARGET_32 -static_assert(InterpretedFrame::K_SIZE_ON32_PLATFORM == sizeof(InterpretedFrame)); -#endif -} // namespace panda::ecmascript -#endif // ECMASCRIPT_FRAMES_H diff --git a/runtime/interpreter/fast_runtime_stub-inl.h b/runtime/interpreter/fast_runtime_stub-inl.h index 52437167c..eb75b0131 100644 --- a/runtime/interpreter/fast_runtime_stub-inl.h +++ b/runtime/interpreter/fast_runtime_stub-inl.h @@ -644,14 +644,7 @@ bool FastRuntimeStub::FastSetPropertyByIndex(JSThread *thread, JSTaggedValue rec JSTaggedValue value) { INTERPRETER_TRACE(thread, FastSetPropertyByIndex); -#ifdef ECMASCRIPT_ENABLE_STUB_AOT1 - auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(SetPropertyByIndex)); - typedef JSTaggedValue (*PFSetPropertyByIndex)(uintptr_t, JSTaggedValue, uint32_t, JSTaggedValue); - auto setPropertyByIndex = reinterpret_cast(stubAddr); - JSTaggedValue result = setPropertyByIndex(thread->GetGlueAddr(), receiver, index, value); -#else JSTaggedValue result = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value); -#endif if (!result.IsHole()) { return result != JSTaggedValue::Exception(); } @@ -693,14 +686,7 @@ JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedV // Maybe moved by GC receiver = receiver_handler.GetTaggedValue(); } -#ifdef ECMASCRIPT_ENABLE_STUB_AOT1 - auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByName)); - typedef JSTaggedValue (*PFGetPropertyByName)(uintptr_t, JSTaggedValue, JSTaggedValue); - auto getPropertyByNamePtr = reinterpret_cast(stubAddr); - JSTaggedValue result = getPropertyByNamePtr(thread->GetGlueAddr(), receiver, key); -#else JSTaggedValue result = FastRuntimeStub::GetPropertyByName(thread, receiver, key); -#endif if (result.IsHole()) { return JSTaggedValue::GetProperty(thread, JSHandle(thread, receiver), JSHandle(thread, key)) @@ -713,14 +699,7 @@ JSTaggedValue FastRuntimeStub::FastGetPropertyByName(JSThread *thread, JSTaggedV JSTaggedValue FastRuntimeStub::FastGetPropertyByValue(JSThread *thread, JSTaggedValue receiver, JSTaggedValue key) { INTERPRETER_TRACE(thread, FastGetPropertyByValue); -#ifdef ECMASCRIPT_ENABLE_STUB_AOT1 - auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByValue)); - typedef JSTaggedValue (*PFGetPropertyByValue)(uintptr_t, JSTaggedValue, JSTaggedValue); - auto getPropertyByValuePtr = reinterpret_cast(stubAddr); - JSTaggedValue result = getPropertyByValuePtr(thread->GetGlueAddr(), receiver, key); -#else JSTaggedValue result = FastRuntimeStub::GetPropertyByValue(thread, &receiver, &key); -#endif if (result.IsHole()) { // CSA reports usage of 'receiver' and 'key' after GC in the function 'GetPropertyByValue'. // In case GC is triggered in the function and the objects are moved the function returns @@ -739,14 +718,7 @@ template // UseHole is only for Array::Sort() which requires Ho JSTaggedValue FastRuntimeStub::FastGetPropertyByIndex(JSThread *thread, JSTaggedValue receiver, uint32_t index) { INTERPRETER_TRACE(thread, FastGetPropertyByIndex); -#ifdef ECMASCRIPT_ENABLE_STUB_AOT1 - auto stubAddr = thread->GetFastStubEntry(FAST_STUB_ID(GetPropertyByIndex)); - typedef JSTaggedValue (*PFGetPropertyByIndex)(uintptr_t, JSTaggedValue, uint32_t); - auto getPropertyByIndex = reinterpret_cast(stubAddr); - JSTaggedValue result = getPropertyByIndex(thread->GetGlueAddr(), receiver, index); -#else JSTaggedValue result = FastRuntimeStub::GetPropertyByIndex(thread, receiver, index); -#endif if (result.IsHole() && !USE_HOLE) { // CSA reports usage of 'receiver' after GC in the function 'CallGetter' which is called from // GetPropertyByIndex. In case we reach CallGetter the result canot by JSTaggedValue::Hole(). diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index cfc0c012c..b6d3abe4e 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -20,7 +20,6 @@ #include "plugins/ecmascript/runtime/js_tagged_value.h" #include "plugins/ecmascript/runtime/js_handle.h" #include "plugins/ecmascript/runtime/js_thread.h" -#include "plugins/ecmascript/runtime/frames.h" namespace panda::ecmascript { class ConstantPool; diff --git a/runtime/js_runtime_options.h b/runtime/js_runtime_options.h index bfe74fc1d..4cc7e2d97 100644 --- a/runtime/js_runtime_options.h +++ b/runtime/js_runtime_options.h @@ -24,10 +24,6 @@ namespace panda::ecmascript { enum ArkProperties { DEFAULT = -1, OPTIONAL_LOG = 1, - GC_STATS_PRINT = 1 << 1, // NOLINT(hicpp-signed-bitwise) - PARALLEL_GC = 1 << 2, // NOLINT(hicpp-signed-bitwise) - CONCURRENT_MARK = 1 << 3, // NOLINT(hicpp-signed-bitwise) - CONCURRENT_SWEEP = 1 << 4, // NOLINT(hicpp-signed-bitwise) }; class JSRuntimeOptions : public RuntimeOptions { @@ -47,8 +43,6 @@ public: { RuntimeOptions::AddOptions(parser); parser->Add(&enable_ark_tools_); - parser->Add(&enable_stub_aot_); - parser->Add(&stub_module_file_); parser->Add(&ark_properties_); } @@ -67,56 +61,6 @@ public: 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(); - } - - bool IsEnableForceGC() const - { - return enable_force_gc_.GetValue(); - } - - void SetEnableForceGC(bool value) - { - enable_force_gc_.SetValue(value); - } - - bool IsForceCompressGC() const - { - return force_compress_gc_.GetValue(); - } - - void SetForceCompressGC(bool value) - { - force_compress_gc_.SetValue(value); - } - void SetArkProperties(int prop) { if (prop != ArkProperties::DEFAULT) { @@ -126,8 +70,7 @@ public: int GetDefaultProperties() { - // NOLINTNEXTLINE(hicpp-signed-bitwise) - return ArkProperties::PARALLEL_GC | ArkProperties::CONCURRENT_MARK | ArkProperties::CONCURRENT_SWEEP; + return 0; } int GetArkProperties() @@ -141,38 +84,8 @@ public: return (ark_properties_.GetValue() & ArkProperties::OPTIONAL_LOG) != 0; } - bool IsEnableGCStatsPrint() const - { - // NOLINTNEXTLINE(hicpp-signed-bitwise) - return (ark_properties_.GetValue() & ArkProperties::GC_STATS_PRINT) != 0; - } - - bool IsEnableParallelGC() const - { - // NOLINTNEXTLINE(hicpp-signed-bitwise) - return (ark_properties_.GetValue() & ArkProperties::PARALLEL_GC) != 0; - } - - bool IsEnableConcurrentMark() const - { - // NOLINTNEXTLINE(hicpp-signed-bitwise) - return (ark_properties_.GetValue() & ArkProperties::CONCURRENT_MARK) != 0; - } - - bool IsEnableConcurrentSweep() const - { - // NOLINTNEXTLINE(hicpp-signed-bitwise) - return (ark_properties_.GetValue() & ArkProperties::CONCURRENT_SWEEP) != 0; - } - 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")"}; - PandArg enable_force_gc_ {"enable-force-gc", true, R"(enable force gc when allocating object)"}; - PandArg force_compress_gc_ {"force-compress-gc", true, - R"(if true trigger compress gc, else trigger semi and old gc)"}; PandArg ark_properties_ {"ark-properties", GetDefaultProperties(), R"(set ark properties)"}; }; } // namespace panda::ecmascript diff --git a/runtime/js_thread.cpp b/runtime/js_thread.cpp index 9b72345c0..e3c4dc4d5 100644 --- a/runtime/js_thread.cpp +++ b/runtime/js_thread.cpp @@ -125,24 +125,6 @@ void JSThread::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) JSSpanHandle::IterateChain(this, v1); } -void JSThread::IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor) -{ - global_storage_->IterateWeakUsageGlobal([visitor](EcmaGlobalStorage::Node *node) { - JSTaggedValue value(node->GetObject()); - if (value.IsHeapObject()) { - auto object = value.GetTaggedObject(); - auto fwd = visitor(object); - if (fwd == nullptr) { - // undefind - node->SetObject(JSTaggedValue::Undefined().GetRawData()); - } else if (fwd != object) { - // update - node->SetObject(JSTaggedValue(fwd).GetRawData()); - } - } - }); -} - void JSThread::IterateEcmascriptEnvironment(const RootVisitor &v0, const RootRangeVisitor &v1) { auto *env = EcmascriptEnvironment::Cast(GetLanguageExtensionsData()); @@ -166,10 +148,6 @@ void JSThread::IterateEcmascriptEnvironment(const RootVisitor &v0, const RootRan properties_cache_->Clear(); } - if (!exception_.IsHole()) { - v0(Root::ROOT_VM, ObjectSlot(ToUintPtr(&exception_))); - } - // visit global Constant global_const_.VisitRangeSlot(v1); } @@ -235,9 +213,4 @@ void JSThread::ResetGuardians() { stable_array_elements_guardians_ = true; } - -void JSThread::LoadFastStubModule([[maybe_unused]] const char *module_file) -{ - UNREACHABLE(); -} } // namespace panda::ecmascript diff --git a/runtime/js_thread.h b/runtime/js_thread.h index e5ad952db..d71c60a89 100644 --- a/runtime/js_thread.h +++ b/runtime/js_thread.h @@ -21,7 +21,6 @@ #include "include/managed_thread.h" #include "plugins/ecmascript/runtime/ecma_global_storage.h" -#include "plugins/ecmascript/runtime/frames.h" #include "plugins/ecmascript/runtime/global_env_constants.h" #include "plugins/ecmascript/runtime/mem/object_xray.h" @@ -87,18 +86,6 @@ public: nested_level_ = level; } - const JSTaggedType *GetCurrentSPFrame() const - { - return current_frame_; - } - - void SetCurrentSPFrame(JSTaggedType *sp) - { - current_frame_ = sp; - } - - bool DoStackOverflowCheck(const JSTaggedType *sp); - void Iterate(const RootVisitor &v0, const RootRangeVisitor &v1); uintptr_t *ExpandHandleStorage(); @@ -204,10 +191,6 @@ public: JSTaggedValue GetCurrentLexenv() const; - void InitializeFastRuntimeStubs(); - - void LoadFastStubModule(const char *module_file); - InternalCallParams *GetInternalCallParams() const { return internal_call_params_; @@ -223,8 +206,6 @@ public: return os::thread::GetCurrentThreadId(); } - void IterateWeakEcmaGlobalStorage(const WeakRootVisitor &visitor); - PropertiesCache *GetPropertiesCache() const { return properties_cache_; @@ -250,48 +231,6 @@ public: return MEMBER_OFFSET(JSThread, global_obj_); } - static constexpr uint32_t GetCurrentFrameOffset() - { - return MEMBER_OFFSET(JSThread, current_frame_); - } - - bool CheckSafepoint() const; - - void SetGetStackSignal(bool is_parse_stack) - { - get_stack_signal_ = is_parse_stack; - } - - bool GetStackSignal() const - { - return get_stack_signal_; - } - - void SetGcState(bool gc_state) - { - gc_state_ = gc_state; - } - - bool GetGcState() const - { - return gc_state_; - } - static constexpr uint32_t GetExceptionOffset() - { - return MEMBER_OFFSET(JSThread, exception_); - } - - uintptr_t GetGlueAddr() const - { - return reinterpret_cast(this) + GetExceptionOffset(); - } - - static JSThread *GlueToJSThread(uintptr_t glue) - { - // very careful to modify here - return reinterpret_cast(glue - GetExceptionOffset()); - } - void SetGlobalObject(JSTaggedValue global_obj) { global_obj_ = global_obj; @@ -320,7 +259,7 @@ private: static const uint32_t NODE_BLOCK_SIZE = 1U << NODE_BLOCK_SIZE_LOG2; static constexpr int32_t MIN_HANDLE_STORAGE_SIZE = 2; - // MM: handles, global-handles, and aot-stubs. + // MM: handles, global-handles int nested_level_ = 0; JSTaggedType *handle_scope_storage_next_ {nullptr}; JSTaggedType *handle_scope_storage_end_ {nullptr}; @@ -328,22 +267,15 @@ private: int32_t current_handle_storage_index_ {-1}; int32_t handle_scope_count_ {0}; JSSpanHandle *span_handle_ {nullptr}; - JSTaggedValue stub_code_ {JSTaggedValue::Hole()}; // Run-time state - bool get_stack_signal_ {false}; - bool gc_state_ {false}; - volatile uint64_t thread_state_bit_field_ {0ULL}; - JSTaggedType *frame_base_ {nullptr}; bool stable_array_elements_guardians_ {true}; InternalCallParams *internal_call_params_ {nullptr}; // GLUE members start, very careful to modify here - JSTaggedValue exception_ {JSTaggedValue::Hole()}; GlobalEnvConstants global_const_; // Place-Holder PropertiesCache *properties_cache_ {nullptr}; EcmaGlobalStorage *global_storage_ {nullptr}; - JSTaggedType *current_frame_ {nullptr}; JSTaggedValue global_obj_ {JSTaggedValue::Hole()}; diff --git a/tests/runtime/common/huge_object_test.cpp b/tests/runtime/common/huge_object_test.cpp index 6b7bb531f..f27f3d1cb 100644 --- a/tests/runtime/common/huge_object_test.cpp +++ b/tests/runtime/common/huge_object_test.cpp @@ -38,7 +38,6 @@ public: void SetUp() override { TestHelper::CreateEcmaVMWithScope(instance, thread, scope); - thread->GetEcmaVM()->SetEnableForceGC(false); } void TearDown() override diff --git a/tests/runtime/common/js_object_test.cpp b/tests/runtime/common/js_object_test.cpp index 6b9d17a2b..c5871892b 100644 --- a/tests/runtime/common/js_object_test.cpp +++ b/tests/runtime/common/js_object_test.cpp @@ -849,7 +849,6 @@ TEST_F(JSObjectTest, FastToSlow) JSMutableHandle newkey(thread, JSTaggedValue(0)); JSHandle value(thread, JSTaggedValue(1)); - ecmaVM->SetEnableForceGC(false); for (uint32_t i = 0; i < PropertyAttributes::MAX_CAPACITY_OF_PROPERTIES; i++) { number.Update(JSTaggedValue(i)); number.Update(JSTaggedValue::ToString(thread, number).GetTaggedValue()); @@ -857,7 +856,6 @@ TEST_F(JSObjectTest, FastToSlow) newkey.Update(JSTaggedValue(newString)); JSObject::SetProperty(thread, JSHandle(obj1), newkey, value); } - ecmaVM->SetEnableForceGC(true); EXPECT_FALSE(TaggedArray::Cast(obj1->GetProperties().GetTaggedObject())->IsDictionaryMode()); diff --git a/tests/runtime/common/js_serializer_test.cpp b/tests/runtime/common/js_serializer_test.cpp index 049d88579..b9af24f5d 100644 --- a/tests/runtime/common/js_serializer_test.cpp +++ b/tests/runtime/common/js_serializer_test.cpp @@ -46,9 +46,7 @@ public: options.SetBootIntrinsicSpaces({"ecmascript"}); options.SetBootClassSpaces({"ecmascript"}); options.SetRuntimeType("ecmascript"); - options.SetEnableForceGC(true); ecmaVm = EcmaVM::Create(options); - ecmaVm->SetEnableForceGC(true); EXPECT_TRUE(ecmaVm != nullptr) << "Cannot create Runtime"; thread = ecmaVm->GetJSThread(); scope = new EcmaHandleScope(thread); @@ -57,7 +55,6 @@ public: { delete scope; scope = nullptr; - ecmaVm->SetEnableForceGC(false); thread->ClearException(); [[maybe_unused]] bool success = EcmaVM::Destroy(ecmaVm); EXPECT_TRUE(success) << "Cannot destroy Runtime"; diff --git a/tests/runtime/common/object_factory_test.cpp b/tests/runtime/common/object_factory_test.cpp index 134283c6b..e8789cb92 100644 --- a/tests/runtime/common/object_factory_test.cpp +++ b/tests/runtime/common/object_factory_test.cpp @@ -66,7 +66,6 @@ JSHandle GetGlobal(JSThread *thread) TEST_F(ObjectFactoryTest, DISABLED_NewJSObjectByConstructor) // TODO(vpukhov) { - thread->GetEcmaVM()->SetEnableForceGC(false); ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle objFun = GetGlobal(thread)->GetObjectFunction(); @@ -93,7 +92,6 @@ TEST_F(ObjectFactoryTest, DISABLED_NewJSObjectByConstructor) // TODO(vpukhov) thread->GetEcmaVM()->CollectGarbage(); // CompressGC not the same EXPECT_TRUE(prototype != newObjCls->GetPrototype().GetTaggedObject()); - thread->GetEcmaVM()->SetEnableForceGC(true); } TEST_F(ObjectFactoryTest, NewJSFunction) -- Gitee From 6a6f5c9c642c3853bf43e09f93f8e120a510a0d9 Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Thu, 20 Oct 2022 16:44:58 +0300 Subject: [PATCH 2/4] Speedup C2I Native calls, avoid Method::Invoke in all cases Signed-off-by: Vsevolod Pukhov --- .gitignore | 1 + .../arch/aarch64/builtin_bridge_aarch64.S | 35 +++++++++----- .../bridge/arch/amd64/builtin_bridge_amd64.S | 30 +++++++++--- runtime/ecma_runtime_call_info.h | 8 ++-- runtime/generator_helper.cpp | 1 - runtime/generator_helper.h | 2 - runtime/interpreter/ecma-interpreter-inl.h | 4 ++ runtime/interpreter/interpreter-inl.h | 48 ++++++++++++------- runtime/interpreter/interpreter.h | 2 - runtime/interpreter/js_frame-inl.h | 3 -- runtime/js_invoker.cpp | 31 +++++++----- 11 files changed, 107 insertions(+), 58 deletions(-) diff --git a/.gitignore b/.gitignore index de4d1f007..cf09da225 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ dist node_modules +es2panda diff --git a/runtime/bridge/arch/aarch64/builtin_bridge_aarch64.S b/runtime/bridge/arch/aarch64/builtin_bridge_aarch64.S index 951a80b2d..408d838c5 100644 --- a/runtime/bridge/arch/aarch64/builtin_bridge_aarch64.S +++ b/runtime/bridge/arch/aarch64/builtin_bridge_aarch64.S @@ -16,8 +16,8 @@ #include "arch/asm_support.h" #include "arch/aarch64/helpers_aarch64.S" -// extern "C" uint64_t InvokeBuiltin(JSThread *thread, Method *method, uint32_t numArgs, JSTaggedValue *stackArgs) -.extern InvokeBuiltin +// extern "C" uint64_t InvokeBuiltinHandleException(JSThread *thread, JSTaggedValue retval) +.extern InvokeBuiltinHandleException // DecodedTaggedValue CompiledCodeToBuiltinBridge, follows DynamicMethod calling convention .global CompiledCodeToBuiltinBridge @@ -33,10 +33,8 @@ CompiledCodeToBuiltinBridge: CFI_REL_OFFSET(fp, 0) mov fp, sp CFI_DEF_CFA_REGISTER(fp) - sub sp, sp, #16 - str x0, [sp, #8] mov x9, #CFRAME_KIND_NATIVE - str x9, [sp] + stp x9, x0, [sp, #-16]! str fp, [THREAD_REG, #MANAGED_THREAD_FRAME_OFFSET] mov w9, #1 strb w9, [THREAD_REG, #MANAGED_THREAD_FRAME_KIND_OFFSET] @@ -71,14 +69,23 @@ CompiledCodeToBuiltinBridge: sub sp, sp, 6 * 8 // 6 unused caller gp stp x0, x1, [sp, #-16]! - mov x2, x1 - mov x1, x0 - mov x0, THREAD_REG - add x3, fp, #16 // pointer to stackArgs + add x9, fp, #16 // pointer to stackArgs + + sub sp, sp, 4 * 8 + str THREAD_REG, [sp, 0 * 8] + str x1, [sp, 1 * 8] + str x9, [sp, 2 * 8] + + ldr lr, [x0, #METHOD_NATIVE_POINTER_OFFSET] + mov x0, sp + blr lr - bl InvokeBuiltin + // TODO(vpukhov): check ret instead + ldr x9, [THREAD_REG, #MANAGED_THREAD_EXCEPTION_OFFSET] + cbnz x9, .Lhandle_exception +1: - add sp, sp, 8 * 8 // skip caller gp + add sp, sp, 4 * 8 + 8 * 8 // skip call_info, skip caller gp POP_CALLEE_REGS sp CFI_RESTORE(THREAD_REG) CFI_RESTORE(x27) @@ -106,3 +113,9 @@ CompiledCodeToBuiltinBridge: CFI_DEF_CFA(sp, 0) ret CFI_ENDPROC + +.Lhandle_exception: + mov x1, x0 + mov x0, THREAD_REG + bl InvokeBuiltinHandleException + b 1b diff --git a/runtime/bridge/arch/amd64/builtin_bridge_amd64.S b/runtime/bridge/arch/amd64/builtin_bridge_amd64.S index 7fff4e6f0..140d20e17 100644 --- a/runtime/bridge/arch/amd64/builtin_bridge_amd64.S +++ b/runtime/bridge/arch/amd64/builtin_bridge_amd64.S @@ -17,8 +17,8 @@ #include "arch/asm_support.h" #include "arch/amd64/helpers_amd64.S" -// extern "C" uint64_t InvokeBuiltin(JSThread *thread, Method *method, uint32_t numArgs, JSTaggedValue *stackArgs) -.extern InvokeBuiltin +// extern "C" uint64_t InvokeBuiltinHandleException(JSThread *thread, JSTaggedValue retval) +.extern InvokeBuiltinHandleException // DecodedTaggedValue CompiledCodeToBuiltinBridge, follows DynamicMethod calling convention .global CompiledCodeToBuiltinBridge @@ -63,12 +63,22 @@ CompiledCodeToBuiltinBridge: movq %rdi, (1 * 8)(%rsp) movq %rsi, (2 * 8)(%rsp) - movl %esi, %edx - movq %rdi, %rsi - movq %THREAD_REG, %rdi - leaq 16(%rbp), %rcx // pointer to stackArgs + leaq 16(%rbp), %r10 // pointer to stack_args + + subq $(4 * 8), %rsp + movq %THREAD_REG, (0 * 8)(%rsp) + movl %esi, (1 * 8)(%rsp) + movq %r10, (2 * 8)(%rsp) + + movq METHOD_NATIVE_POINTER_OFFSET(%rdi), %r10 + movq %rsp, %rdi + callq *%r10 - callq InvokeBuiltin@plt + // TODO(vpukhov): check ret instead + movq MANAGED_THREAD_EXCEPTION_OFFSET(%THREAD_REG), %rdi + test %rdi, %rdi + jne .Lhandle_exception +1: // Restore callee registers, since GC may change its values while moving objects. movq -((CFRAME_CALLEE_REGS_START_SLOT + 0) * 8)(%rbp), %r15 @@ -88,3 +98,9 @@ CompiledCodeToBuiltinBridge: CFI_DEF_CFA(rsp, (1 * 8)) retq CFI_ENDPROC + +.Lhandle_exception: + movq %rax, %rsi + movq %THREAD_REG, %rdi + callq InvokeBuiltinHandleException@plt + jmp 1b diff --git a/runtime/ecma_runtime_call_info.h b/runtime/ecma_runtime_call_info.h index d53c89602..5ca84828c 100644 --- a/runtime/ecma_runtime_call_info.h +++ b/runtime/ecma_runtime_call_info.h @@ -30,7 +30,7 @@ using EcmaEntrypoint = JSTaggedValue (*)(EcmaRuntimeCallInfo *); class EcmaRuntimeCallInfo { public: EcmaRuntimeCallInfo(JSThread *thread, uint32_t num_args, JSTaggedValue *args) - : thread_(thread), args_(args), num_args_(num_args) + : thread_(thread), num_args_(num_args), args_(args) { ASSERT(num_args >= NUM_MANDATORY_JSFUNC_ARGS); } @@ -118,9 +118,9 @@ private: } private: - JSThread *thread_; - JSTaggedValue *args_ {nullptr}; - uint32_t num_args_; + alignas(sizeof(JSTaggedType)) JSThread *thread_ {nullptr}; + alignas(sizeof(JSTaggedType)) uint32_t num_args_ {0}; + alignas(sizeof(JSTaggedType)) JSTaggedValue *args_ {nullptr}; }; } // namespace panda::ecmascript diff --git a/runtime/generator_helper.cpp b/runtime/generator_helper.cpp index 808cfa5e1..697dcdf05 100644 --- a/runtime/generator_helper.cpp +++ b/runtime/generator_helper.cpp @@ -23,7 +23,6 @@ namespace panda::ecmascript { JSHandle GeneratorHelper::Continue(JSThread *thread, const JSHandle &genContext, GeneratorResumeMode resumeMode, JSTaggedValue value) { - [[maybe_unused]] C2IBridge c2i; EcmaInterpreter::ChangeGenContext(thread, genContext); JSHandle genObject(thread, genContext->GetGeneratorObject()); diff --git a/runtime/generator_helper.h b/runtime/generator_helper.h index 092c4616b..97362600d 100644 --- a/runtime/generator_helper.h +++ b/runtime/generator_helper.h @@ -28,8 +28,6 @@ enum class GeneratorResumeMode { NEXT, }; -using C2IBridge = std::array; // 4: means array length - class GeneratorHelper { public: static JSHandle Continue(JSThread *thread, const JSHandle &genContext, diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index fdf956816..e2878e1dc 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -247,7 +247,11 @@ public: num_actual_args); // Call native method + js_thread->SetCurrentFrame(frame); JSTaggedValue ret_value = JSFrame::ExecuteNativeMethod(js_thread, frame, method, num_actual_args); + ASSERT(js_thread->GetCurrentFrame() == frame); + js_thread->SetCurrentFrameIsCompiled(false); + js_thread->SetCurrentFrame(prev_frame); JSFrame::DestroyNativeFrame(js_thread, frame); if (UNLIKELY(js_thread->HasPendingException())) { diff --git a/runtime/interpreter/interpreter-inl.h b/runtime/interpreter/interpreter-inl.h index 4600296c0..910a37332 100644 --- a/runtime/interpreter/interpreter-inl.h +++ b/runtime/interpreter/interpreter-inl.h @@ -96,28 +96,33 @@ JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *js_thread, JSTaggedValue const JSTaggedValue *args) { ASSERT(!js_thread->HasPendingException()); - ASSERT(!js_thread->IsCurrentFrameCompiled()); // Boundary frame expected for c2i call + + Frame *current_frame = js_thread->GetCurrentFrame(); + bool is_compiled = js_thread->IsCurrentFrameCompiled(); + + // Boundary frame expected for c2i call + ASSERT(!is_compiled || StackWalker::IsBoundaryFrame(current_frame)); Method *method = ECMAObject::Cast(fn_object.GetHeapObject())->GetCallTarget(); ASSERT(method->GetNumVregs() == 0); uint32_t num_declared_args = method->GetNumArgs(); uint32_t nregs = std::max(num_declared_args, num_args); - - Frame *frame = JSFrame::CreateNativeFrame(js_thread, method, js_thread->GetCurrentFrame(), nregs, num_args); + Frame *frame = JSFrame::CreateNativeFrame(js_thread, method, current_frame, nregs, num_args); JSFrame::InitNativeFrameArgs(frame, num_args, args); + + js_thread->SetCurrentFrameIsCompiled(false); + js_thread->SetCurrentFrame(frame); JSTaggedValue ret_value = JSFrame::ExecuteNativeMethod(js_thread, frame, method, num_args); + ASSERT(js_thread->GetCurrentFrame() == frame); + js_thread->SetCurrentFrameIsCompiled(is_compiled); + js_thread->SetCurrentFrame(frame->GetPrevFrame()); + JSFrame::DestroyNativeFrame(js_thread, frame); return ret_value; } -JSTaggedValue EcmaInterpreter::ExecuteInvoke(JSThread *js_thread, JSHandle call_target, uint32_t num_args, - JSTaggedValue *args) -{ - return ExecuteInvoke(js_thread, call_target.GetTaggedValue(), num_args, args); -} - JSTaggedValue EcmaInterpreter::ExecuteInvoke(JSThread *thread, JSTaggedValue fn_object, uint32_t num_args, JSTaggedValue *args) { @@ -151,16 +156,27 @@ JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, JSHandle ca Method *method = call_target->GetCallTarget(); if (method->IsNative()) { - if (!thread->IsCurrentFrameCompiled()) { - return ExecuteNative(thread, call_target, num_actual_args, args); + auto current_frame = thread->GetCurrentFrame(); + + if (thread->IsCurrentFrameCompiled() && !StackWalker::IsBoundaryFrame(current_frame)) { + C2IBridge bridge {0, reinterpret_cast(current_frame), COMPILED_CODE_TO_INTERPRETER, + thread->GetNativePc()}; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + thread->SetCurrentFrame(reinterpret_cast(&bridge.v[1])); + JSTaggedValue ret_val = ExecuteNative(thread, call_target.GetTaggedValue(), num_actual_args, + reinterpret_cast(args)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ASSERT(thread->GetCurrentFrame() == reinterpret_cast(&bridge.v[1])); + thread->SetCurrentFrameIsCompiled(true); + thread->SetCurrentFrame(current_frame); + return ret_val; } - ASSERT(!thread->HasPendingException()); - TaggedValue ret_value = - method->InvokeDyn(thread, num_actual_args, reinterpret_cast(args)); - return JSTaggedValue(ret_value); + return ExecuteNative(thread, call_target.GetTaggedValue(), num_actual_args, + reinterpret_cast(args)); } - return ExecuteInvoke(thread, call_target, num_actual_args, reinterpret_cast(args)); + return ExecuteInvoke(thread, call_target.GetTaggedValue(), num_actual_args, + reinterpret_cast(args)); } JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSHandle context) diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index b6d3abe4e..1c2b9978f 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -36,8 +36,6 @@ public: JSTaggedType *args); static inline JSTaggedValue ExecuteNative(JSThread *js_thread, JSHandle call_target, uint32_t num_args, const JSTaggedType *args); - static inline JSTaggedValue ExecuteInvoke(JSThread *js_thread, JSHandle call_target, uint32_t num_args, - JSTaggedValue *args); 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/runtime/interpreter/js_frame-inl.h b/runtime/interpreter/js_frame-inl.h index f7c583fd7..da98e01aa 100644 --- a/runtime/interpreter/js_frame-inl.h +++ b/runtime/interpreter/js_frame-inl.h @@ -19,7 +19,6 @@ inline Frame *JSFrame::CreateNativeFrame(JSThread *js_thread, Method *method, Fr Frame *new_frame = CreateFrame(js_thread->GetStackFrameAllocator(), nregs, method, prev_frame, nregs, num_actual_args); - js_thread->SetCurrentFrame(new_frame); LOG_IF(new_frame == nullptr, FATAL, ECMASCRIPT) << "Cannot allocate native frame"; new_frame->SetInvoke(); new_frame->SetDynamic(); @@ -30,8 +29,6 @@ inline Frame *JSFrame::CreateNativeFrame(JSThread *js_thread, Method *method, Fr inline void JSFrame::DestroyNativeFrame(JSThread *js_thread, Frame *frame) { ASSERT(js_thread == JSThread::GetCurrent()); - - js_thread->SetCurrentFrame(frame->GetPrevFrame()); DestroyFrame(js_thread->GetStackFrameAllocator(), frame); } diff --git a/runtime/js_invoker.cpp b/runtime/js_invoker.cpp index 06bfb3ef2..b2cf6f196 100644 --- a/runtime/js_invoker.cpp +++ b/runtime/js_invoker.cpp @@ -29,6 +29,24 @@ JSTaggedValue JsInvoker::Invoke([[maybe_unused]] JSThread *thread) UNREACHABLE(); } +extern "C" uint64_t InvokeBuiltinHandleException(JSThread *thread, JSTaggedValue retval) +{ + ASSERT(thread->HasPendingException()); + + auto stack = StackWalker::Create(thread); + ASSERT(stack.IsCFrame() && stack.GetCFrame().IsNative()); + + // Return to caller if there is a BYPASS bridge, otherwise skip current frame + auto prev = stack.GetCFrame().GetPrevFrame(); + if (stack.GetBoundaryFrameMethod(prev) == FrameBridgeKind::BYPASS) { + return retval.GetRawData(); + } + stack.NextFrame(); + + FindCatchBlockInCFrames(thread, &stack, nullptr); + UNREACHABLE(); +} + extern "C" uint64_t InvokeBuiltin(JSThread *thread, Method *method, uint32_t numArgs, JSTaggedValue *stackArgs) { EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, numArgs, stackArgs); @@ -39,18 +57,7 @@ extern "C" uint64_t InvokeBuiltin(JSThread *thread, Method *method, uint32_t num reinterpret_cast(const_cast(method->GetNativePointer()))(&ecmaRuntimeCallInfo); if (thread->HasPendingException()) { - auto stack = StackWalker::Create(thread); - ASSERT(stack.IsCFrame() && stack.GetCFrame().IsNative()); - - // Return to caller if there is a BYPASS bridge, otherwise skip current frame - auto prev = stack.GetCFrame().GetPrevFrame(); - if (stack.GetBoundaryFrameMethod(prev) == FrameBridgeKind::BYPASS) { - return retValue.GetRawData(); - } - stack.NextFrame(); - - FindCatchBlockInCFrames(thread, &stack, nullptr); - UNREACHABLE(); + return InvokeBuiltinHandleException(thread, retValue); } return retValue.GetRawData(); -- Gitee From c384f17e3ac3e22acc06e56f577995e1db762fed Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Tue, 25 Oct 2022 16:25:29 +0300 Subject: [PATCH 3/4] Unify interpreter/runtime calls, implement ScopedCallInfo Signed-off-by: Vsevolod Pukhov --- compiler/ecmascript_call_params.h | 9 +- runtime/base/array_helper.cpp | 8 +- runtime/base/json_parser.cpp | 7 +- runtime/base/json_stringifier.cpp | 12 +- runtime/base/object_helper.cpp | 14 +- runtime/base/typed_array_helper.cpp | 14 +- runtime/builtins.cpp | 1 - runtime/builtins/builtins_array.cpp | 136 +++++++------- runtime/builtins/builtins_arraybuffer.cpp | 7 +- .../builtins_async_from_sync_iterator.cpp | 85 ++++----- runtime/builtins/builtins_date.cpp | 3 +- runtime/builtins/builtins_function.cpp | 79 ++++++--- runtime/builtins/builtins_global.cpp | 13 +- runtime/builtins/builtins_map.cpp | 7 +- runtime/builtins/builtins_object.cpp | 11 +- runtime/builtins/builtins_promise.cpp | 96 ++++++---- runtime/builtins/builtins_promise_handler.cpp | 9 +- runtime/builtins/builtins_promise_job.cpp | 35 ++-- runtime/builtins/builtins_reflect.cpp | 17 +- runtime/builtins/builtins_regexp.cpp | 28 +-- runtime/builtins/builtins_set.cpp | 19 +- runtime/builtins/builtins_string.cpp | 81 +++++---- runtime/builtins/builtins_typedarray.cpp | 84 ++++----- runtime/builtins/builtins_weak_map.cpp | 16 +- runtime/builtins/builtins_weak_set.cpp | 12 +- runtime/common.h | 3 +- runtime/ecma_call_params.h | 33 ++++ runtime/ecma_exceptions.cpp | 2 +- runtime/ecma_macros.h | 92 +++++----- runtime/ecma_runtime_call_info.h | 166 ++++++++++++++++-- runtime/ecma_vm.cpp | 13 +- runtime/interpreter/ecma-interpreter-inl.h | 8 +- runtime/interpreter/fast_runtime_stub-inl.h | 7 +- runtime/interpreter/fast_runtime_stub.h | 2 +- runtime/interpreter/interpreter-inl.h | 75 ++++---- runtime/interpreter/interpreter.h | 13 +- runtime/interpreter/js_frame-inl.h | 3 + runtime/interpreter/slow_runtime_helper.cpp | 103 +++++------ runtime/interpreter/slow_runtime_helper.h | 7 +- runtime/interpreter/slow_runtime_stub.cpp | 58 +++--- runtime/intrinsics-inl.h | 84 ++++----- runtime/jobs/micro_job_queue.cpp | 4 +- runtime/jobs/pending_job.h | 6 +- runtime/js_array.cpp | 7 +- runtime/js_async_generator_object.cpp | 23 +-- runtime/js_eval.cpp | 23 +-- runtime/js_finalization_registry.cpp | 8 +- runtime/js_function.cpp | 163 +++++++---------- runtime/js_function.h | 49 ++---- runtime/js_function_kind.h | 19 +- runtime/js_hclass.h | 5 - runtime/js_invoker.cpp | 28 +-- runtime/js_invoker.h | 4 +- runtime/js_iterator.cpp | 23 ++- runtime/js_object-inl.h | 4 - runtime/js_object.cpp | 17 +- runtime/js_object.h | 1 - runtime/js_promise.cpp | 13 +- runtime/js_proxy.cpp | 147 +++++++++------- runtime/js_proxy.h | 9 +- runtime/js_tagged_value.cpp | 10 +- runtime/js_thread.cpp | 1 + runtime/js_thread.h | 3 + runtime/napi/jsnapi.cpp | 77 ++++---- runtime/napi/jsnapi_helper.h | 14 +- runtime/object_factory.cpp | 52 +++++- .../builtins/builtins_promise_test.cpp | 10 +- tests/runtime/common/js_function_test.cpp | 6 +- tests/runtime/common/js_promise_test.cpp | 14 +- tests/runtime/common/js_proxy_test.cpp | 28 ++- 70 files changed, 1241 insertions(+), 999 deletions(-) create mode 100644 runtime/ecma_call_params.h diff --git a/compiler/ecmascript_call_params.h b/compiler/ecmascript_call_params.h index d1f473f38..3f2bc43db 100644 --- a/compiler/ecmascript_call_params.h +++ b/compiler/ecmascript_call_params.h @@ -17,6 +17,7 @@ #define PANDA_COMPILER_ECMASCRIPT_CALL_PARAMS #include "compiler/optimizer/code_generator/callconv.h" +#include "plugins/ecmascript/runtime/ecma_call_params.h" // NOLINTNEXTLINE(modernize-concat-nested-namespaces) namespace panda::compiler { @@ -24,11 +25,13 @@ namespace panda::compiler { namespace EcmascriptCallParams { enum : uint8_t { SLOT_FUNCTION = CallConvDynInfo::SLOT_CALLEE, - SLOT_NEWTARGET, - SLOT_THIS, - SLOT_FIRST_ARG, + SLOT_NEWTARGET = ::panda::ecmascript::JSMethodArgs::NEW_TARGET_IDX, + SLOT_THIS = ::panda::ecmascript::JSMethodArgs::THIS_IDX, + SLOT_FIRST_ARG = ::panda::ecmascript::JSMethodArgs::FIRST_ARG_IDX, }; } // namespace EcmascriptCallParams +static_assert(static_cast(EcmascriptCallParams::SLOT_FUNCTION) == + static_cast(::panda::ecmascript::JSMethodArgs::FUNC_IDX)); } // namespace panda::compiler diff --git a/runtime/base/array_helper.cpp b/runtime/base/array_helper.cpp index 9ad0588e7..f771344d9 100644 --- a/runtime/base/array_helper.cpp +++ b/runtime/base/array_helper.cpp @@ -81,10 +81,10 @@ int32_t ArrayHelper::SortCompare(JSThread *thread, const JSHandle // d. Return v. if (!callbackfnHandle->IsUndefined()) { JSHandle thisArgHandle(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(valueX, valueY); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackfnHandle, thisArgHandle, 2, arguments->GetArgv()); // 2: two args + + auto info = NewRuntimeCallInfo(thread, callbackfnHandle, thisArgHandle, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(valueX, valueY); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 2: two args if (callResult.IsInt()) { return callResult.GetInt(); } diff --git a/runtime/base/json_parser.cpp b/runtime/base/json_parser.cpp index 0b033388c..9cb10f43d 100644 --- a/runtime/base/json_parser.cpp +++ b/runtime/base/json_parser.cpp @@ -56,9 +56,10 @@ JSHandle Internalize::InternalizeJsonProperty(JSThread *thread, c } // Return ? Call(receiver, holder, « name, val »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(name, val); - JSTaggedValue result = JSFunction::Call(thread, receiver, objHandle, 2, arguments->GetArgv()); // 2: two args + + auto info = NewRuntimeCallInfo(thread, receiver, objHandle, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(name, val); + JSTaggedValue result = JSFunction::Call(info.get()); // 2: two args return JSHandle(thread, result); } diff --git a/runtime/base/json_stringifier.cpp b/runtime/base/json_stringifier.cpp index 49cceb45c..6d646709b 100644 --- a/runtime/base/json_stringifier.cpp +++ b/runtime/base/json_stringifier.cpp @@ -305,9 +305,9 @@ JSTaggedValue JsonStringifier::GetSerializeValue(const JSHandle & // c. If IsCallable(toJSON) is true if (UNLIKELY(toJsonFun->IsCallable())) { // Let value be Call(toJSON, value, «key»). - InternalCallParams *arguments = thread_->GetInternalCallParams(); - arguments->MakeArgv(key); - tagValue = JSFunction::Call(thread_, toJsonFun, value, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread_, toJsonFun, value, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(key); + tagValue = JSFunction::Call(info.get()); // ii. ReturnIfAbrupt(value). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); } @@ -316,9 +316,9 @@ JSTaggedValue JsonStringifier::GetSerializeValue(const JSHandle & if (UNLIKELY(replacer->IsCallable())) { handleValue_.Update(tagValue); // a. Let value be Call(ReplacerFunction, holder, «key, value»). - InternalCallParams *arguments = thread_->GetInternalCallParams(); - arguments->MakeArgv(key, handleValue_); - tagValue = JSFunction::Call(thread_, replacer, object, 2, arguments->GetArgv()); // 2: two args + auto info = NewRuntimeCallInfo(thread_, replacer, object, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(key, handleValue_); + tagValue = JSFunction::Call(info.get()); // 2: two args // b. ReturnIfAbrupt(value). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread_); } diff --git a/runtime/base/object_helper.cpp b/runtime/base/object_helper.cpp index c9f2572e5..0814273f7 100644 --- a/runtime/base/object_helper.cpp +++ b/runtime/base/object_helper.cpp @@ -71,7 +71,7 @@ JSTaggedValue ObjectHelper::AddEntriesFromIterable(JSThread *thread, const JSHan JSHandle record( factory->NewCompletionRecord(CompletionRecord::THROW, JSHandle(typeError))); JSTaggedValue ret = JSIterator::IteratorClose(thread, iter, record).GetTaggedValue(); - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { THROW_NEW_ERROR_AND_RETURN_VALUE(thread, typeError.GetTaggedValue(), ret); }; return ret; @@ -79,23 +79,23 @@ JSTaggedValue ObjectHelper::AddEntriesFromIterable(JSThread *thread, const JSHan // Let k be Get(nextItem, "0"). JSHandle key = JSObject::GetProperty(thread, nextValue, keyIndex).GetValue(); // If k is an abrupt completion, return IteratorClose(iter, k). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, key); } // Let v be Get(nextItem, "1"). JSHandle value = JSObject::GetProperty(thread, nextValue, valueIndex).GetValue(); // If v is an abrupt completion, return IteratorClose(iter, v). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, value); } - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(key, value); // 2: key and value pair // Let status be Call(adder, target, «nextValue.[[value]]»). - JSTaggedValue ret = JSFunction::Call(thread, adder, JSHandle(target), 2U, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, adder, target, JSTaggedValue::Undefined(), 2U); + info->SetCallArgs(key, value); // 2: key and value pair + JSTaggedValue ret = JSFunction::Call(info.get()); status.Update(ret); // If status is an abrupt completion, return IteratorClose(iter, status). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, status); } // Let next be IteratorStep(iter). diff --git a/runtime/base/typed_array_helper.cpp b/runtime/base/typed_array_helper.cpp index e99a7737b..436871d03 100644 --- a/runtime/base/typed_array_helper.cpp +++ b/runtime/base/typed_array_helper.cpp @@ -456,8 +456,10 @@ JSHandle TypedArrayHelper::TypedArrayCreate(JSThread *thread, const JS ) { // 1. Let newTypedArray be ? Construct(constructor, argumentList). - JSTaggedValue taggedArray = JSFunction::Construct(thread, constructor, argc, argv, - JSHandle(thread, JSTaggedValue::Undefined())); + auto info = NewRuntimeCallInfo(thread, constructor, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), argc); + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle(thread, JSTaggedValue::Exception())); + info->SetCallArg(argc, argv); + JSTaggedValue taggedArray = JSFunction::Construct(info.get()); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSHandle(thread, JSTaggedValue::Exception())); if (!taggedArray.IsECMAObject()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Failed to construct the Typedarray.", @@ -516,10 +518,10 @@ int32_t TypedArrayHelper::SortCompare(JSThread *thread, const JSHandleIsUndefined()) { JSHandle thisArgHandle = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(firstValue, secondValue); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackfnHandle, thisArgHandle, 2, arguments->GetArgv()); // 2: two args + + auto info = NewRuntimeCallInfo(thread, callbackfnHandle, thisArgHandle, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(firstValue, secondValue); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 2: two args RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, 0); if (BuiltinsArrayBuffer::IsDetachedBuffer(buffer.GetTaggedValue())) { THROW_TYPE_ERROR_AND_RETURN(thread, "The buffer is detached buffer.", 0); diff --git a/runtime/builtins.cpp b/runtime/builtins.cpp index 10f16cb47..382098dc6 100644 --- a/runtime/builtins.cpp +++ b/runtime/builtins.cpp @@ -241,7 +241,6 @@ void Builtins::Initialize(const JSHandle &env, JSThread *thread) // Object = new Function() JSHandle objectFunction( NewBuiltinConstructor(env, objFuncPrototype, Object::ObjectConstructor, "Object", FunctionLength::ONE)); - ASSERT(objectFunction->IsBuiltinsConstructor()); objectFunction.GetObject()->SetFunctionPrototype(thread_, objFuncDynclass.GetTaggedValue()); // initialize object method. env->SetObjectFunction(thread_, objectFunction); diff --git a/runtime/builtins/builtins_array.cpp b/runtime/builtins/builtins_array.cpp index e3bdb9ee5..841f16340 100644 --- a/runtime/builtins/builtins_array.cpp +++ b/runtime/builtins/builtins_array.cpp @@ -136,7 +136,7 @@ JSTaggedValue BuiltinsArray::From(EcmaRuntimeCallInfo *argv) BUILTINS_API_TRACE(argv->GetThread(), Array, From); JSThread *thread = argv->GetThread(); [[maybe_unused]] EcmaHandleScope handleScope(thread); - InternalCallParams *arguments = thread->GetInternalCallParams(); + JSHandle lengthKey = thread->GlobalConstants()->GetHandledLengthString(); // 1. Let C be the this value. JSHandle thisHandle = GetThis(argv); @@ -173,8 +173,9 @@ JSTaggedValue BuiltinsArray::From(EcmaRuntimeCallInfo *argv) // c. ReturnIfAbrupt(A). JSTaggedValue newArray; if (thisHandle->IsConstructor()) { - newArray = JSFunction::Construct(thread, thisHandle, 0, nullptr, - JSHandle(thread, JSTaggedValue::Undefined())); + auto info = + NewRuntimeCallInfo(thread, thisHandle, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 0); + newArray = JSFunction::Construct(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } else { newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(0)).GetTaggedValue(); @@ -219,9 +220,9 @@ JSTaggedValue BuiltinsArray::From(EcmaRuntimeCallInfo *argv) // 3. Let mappedValue be mappedValue.[[value]]. // viii. Else, let mappedValue be nextValue. if (mapping) { - arguments->MakeArgv(nextValue, key); - JSTaggedValue callResult = - JSFunction::Call(thread, mapfn, thisArgHandle, 2, arguments->GetArgv()); // 2: two args + auto info = NewRuntimeCallInfo(thread, mapfn, thisArgHandle, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(nextValue, key); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 2: two args mapValue.Update(callResult); JSTaggedValue mapResult = JSIterator::IteratorClose(thread, iterator, mapValue).GetTaggedValue(); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue(mapResult)); @@ -255,9 +256,9 @@ JSTaggedValue BuiltinsArray::From(EcmaRuntimeCallInfo *argv) // 14. ReturnIfAbrupt(A). JSTaggedValue newArray; if (thisHandle->IsConstructor()) { - arguments->MakeArgv(JSTaggedValue(len)); - newArray = JSFunction::Construct(thread, thisHandle, 1, arguments->GetArgv(), - JSHandle(thread, JSTaggedValue::Undefined())); + auto info = NewRuntimeCallInfo(thread, thisHandle, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 1); + info->SetCallArgs(JSTaggedValue(len)); + newArray = JSFunction::Construct(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } else { newArray = JSArray::ArrayCreate(thread, JSTaggedNumber(len)).GetTaggedValue(); @@ -283,9 +284,9 @@ JSTaggedValue BuiltinsArray::From(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (mapping) { key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key); - JSTaggedValue callResult = - JSFunction::Call(thread, mapfn, thisArgHandle, 2, arguments->GetArgv()); // 2: two args + auto info = NewRuntimeCallInfo(thread, mapfn, thisArgHandle, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(kValue, key); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 2: two args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); mapValue.Update(callResult); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -340,9 +341,10 @@ JSTaggedValue BuiltinsArray::Of(EcmaRuntimeCallInfo *argv) JSHandle newArray; if (thisHandle->IsConstructor()) { JSHandle undefined = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(argc)); - JSTaggedValue taggedArray = JSFunction::Construct(thread, thisHandle, 1, arguments->GetArgv(), undefined); + + auto info = NewRuntimeCallInfo(thread, thisHandle, JSTaggedValue::Undefined(), undefined, 1); + info->SetCallArgs(JSTaggedValue(argc)); + JSTaggedValue taggedArray = JSFunction::Construct(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); newArray = JSHandle(thread, taggedArray); } else { @@ -693,7 +695,7 @@ JSTaggedValue BuiltinsArray::Every(EcmaRuntimeCallInfo *argv) // iv. ReturnIfAbrupt(testResult). // v. If testResult is false, return false. // e. Increase k by 1. - InternalCallParams *arguments = thread->GetInternalCallParams(); + JSMutableHandle key(thread, JSTaggedValue::Undefined()); uint32_t k = 0; while (k < len) { @@ -703,9 +705,9 @@ JSTaggedValue BuiltinsArray::Every(EcmaRuntimeCallInfo *argv) JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); bool boolResult = callResult.ToBoolean(); if (!boolResult) { @@ -750,10 +752,10 @@ static JSTaggedValue FlattenIntoArray(JSThread *thread, const JSHandle RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!mapperFunc->IsHole()) { ASSERT(!thisArg->IsHole()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(element.GetTaggedValue(), JSTaggedNumber(srcIdx), source.GetTaggedValue()); - JSTaggedValue res = - JSFunction::Call(thread, mapperFunc, thisArg, 3, arguments->GetArgv()); // 3: three args + + auto info = NewRuntimeCallInfo(thread, mapperFunc, thisArg, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(element.GetTaggedValue(), JSTaggedNumber(srcIdx), source.GetTaggedValue()); + JSTaggedValue res = JSFunction::Call(info.get()); // 3: three args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); element = JSHandle(thread, res); } @@ -1014,7 +1016,7 @@ JSTaggedValue BuiltinsArray::Filter(EcmaRuntimeCallInfo *argv) double toIndex = 0; JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle toIndexHandle(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + uint32_t k = 0; while (k < len) { bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); @@ -1023,9 +1025,9 @@ JSTaggedValue BuiltinsArray::Filter(EcmaRuntimeCallInfo *argv) JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args bool boolResult = callResult.ToBoolean(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (boolResult) { @@ -1081,15 +1083,15 @@ JSTaggedValue BuiltinsArray::Find(EcmaRuntimeCallInfo *argv) // f. If testResult is true, return kValue. // g. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + uint32_t k = 0; while (k < len) { JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); bool boolResult = callResult.ToBoolean(); if (boolResult) { @@ -1141,15 +1143,15 @@ JSTaggedValue BuiltinsArray::FindIndex(EcmaRuntimeCallInfo *argv) // f. If testResult is true, return k. // g. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + uint32_t k = 0; while (k < len) { JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args bool boolResult = callResult.ToBoolean(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (boolResult) { @@ -1202,7 +1204,7 @@ JSTaggedValue BuiltinsArray::ForEach(EcmaRuntimeCallInfo *argv) // iv. ReturnIfAbrupt(funcResult). // e. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + uint32_t k = 0; while (k < len) { bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); @@ -1211,9 +1213,9 @@ JSTaggedValue BuiltinsArray::ForEach(EcmaRuntimeCallInfo *argv) JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue funcResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue funcResult = JSFunction::Call(info.get()); // 3: three args RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); } k++; @@ -1622,7 +1624,7 @@ JSTaggedValue BuiltinsArray::Map(EcmaRuntimeCallInfo *argv) // e. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSMutableHandle mapResultHandle(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + uint32_t k = 0; while (k < len) { bool exists = JSTaggedValue::HasProperty(thread, thisObjVal, k); @@ -1631,9 +1633,9 @@ JSTaggedValue BuiltinsArray::Map(EcmaRuntimeCallInfo *argv) JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue mapResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue mapResult = JSFunction::Call(info.get()); // 3: three args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); mapResultHandle.Update(mapResult); JSObject::CreateDataPropertyOrThrow(thread, newArrayHandle, k, mapResultHandle); @@ -1837,7 +1839,7 @@ JSTaggedValue BuiltinsArray::Reduce(EcmaRuntimeCallInfo *argv) // e. Increase k by 1. JSTaggedValue callResult = JSTaggedValue::Undefined(); JSMutableHandle key(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + while (k < len) { bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -1845,10 +1847,10 @@ JSTaggedValue BuiltinsArray::Reduce(EcmaRuntimeCallInfo *argv) JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(accumulator, kValue, key, thisObjVal); JSHandle thisArgHandle = globalConst->GetHandledUndefined(); - callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 4, arguments->GetArgv()); // 4: four args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 4); + info->SetCallArgs(accumulator, kValue, key, thisObjVal); + callResult = JSFunction::Call(info.get()); // 4: four args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); accumulator.Update(callResult); } @@ -1939,7 +1941,7 @@ JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv) // e. Decrease k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); JSTaggedValue callResult = JSTaggedValue::Undefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); + while (k >= 0) { key.Update(JSTaggedValue(k)); bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, key)); @@ -1947,10 +1949,10 @@ JSTaggedValue BuiltinsArray::ReduceRight(EcmaRuntimeCallInfo *argv) if (exists) { JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, key); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - arguments->MakeArgv(accumulator, kValue, key, thisObjVal); JSHandle thisArgHandle = globalConst->GetHandledUndefined(); - callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 4, arguments->GetArgv()); // 4: four args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 4); + info->SetCallArgs(accumulator, kValue, key, thisObjVal); + callResult = JSFunction::Call(info.get()); // 4: four args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); accumulator.Update(callResult); } @@ -2310,7 +2312,7 @@ JSTaggedValue BuiltinsArray::Some(EcmaRuntimeCallInfo *argv) // v. If testResult is true, return true. // e. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + double k = 0; while (k < len) { bool exists = (thisHandle->IsTypedArray() || JSTaggedValue::HasProperty(thread, thisObjVal, k)); @@ -2319,9 +2321,9 @@ JSTaggedValue BuiltinsArray::Some(EcmaRuntimeCallInfo *argv) key.Update(JSTaggedValue(k)); JSHandle kValue = JSArray::FastGetPropertyByValue(thread, thisObjVal, key); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args bool boolResult = callResult.ToBoolean(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (boolResult) { @@ -2666,17 +2668,19 @@ JSTaggedValue BuiltinsArray::ToLocaleString(EcmaRuntimeCallInfo *argv) // f. Let R be a String value produced by concatenating S and R. // g. Increase k by 1. auto globalConst = thread->GlobalConstants(); - InternalCallParams *arguments = thread->GetInternalCallParams(); + for (int32_t k = 0; k < len; k++) { JSTaggedValue next = globalConst->GetEmptyString(); JSHandle nextElement = JSArray::FastGetPropertyByValue(thread, thisObjVal, k); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!nextElement->IsUndefined() && !nextElement->IsNull()) { JSHandle nextValueHandle = nextElement; - arguments->MakeArgv(locales, options); - JSTaggedValue callResult = - JSFunction::Invoke(thread, nextValueHandle, globalConst->GetHandledToLocaleStringString(), 2, - arguments->GetArgv()); // 2: two args + JSHandle key = globalConst->GetHandledToLocaleStringString(); + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), nextValueHandle, + JSTaggedValue::Undefined(), 2); // 2: two args + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArgs(locales, options); + JSTaggedValue callResult = JSFunction::Invoke(info.get(), key); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); next = callResult; } @@ -2728,10 +2732,14 @@ JSTaggedValue BuiltinsArray::ToString(EcmaRuntimeCallInfo *argv) callbackFnHandle = JSTaggedValue::GetProperty(thread, objectPrototype, toStringKey).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - JSHandle argsList = GetArgsArray(argv); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgList(*argsList); - return JSFunction::Call(thread, callbackFnHandle, thisObjVal, argsList->GetLength(), arguments->GetArgv()); + + auto info = + NewRuntimeCallInfo(thread, callbackFnHandle, thisObjVal, JSTaggedValue::Undefined(), argv->GetArgsNumber()); + if (argv->GetArgsNumber() > 0) { + info->SetCallArg(argv->GetArgsNumber(), + reinterpret_cast(argv->GetArgAddress(JSMethodArgs::NUM_MANDATORY_ARGS))); + } + return JSFunction::Call(info.get()); } // 22.1.3.28 Array.prototype.unshift ( ...items ) diff --git a/runtime/builtins/builtins_arraybuffer.cpp b/runtime/builtins/builtins_arraybuffer.cpp index 4c966c09a..45fabce3f 100644 --- a/runtime/builtins/builtins_arraybuffer.cpp +++ b/runtime/builtins/builtins_arraybuffer.cpp @@ -172,9 +172,10 @@ JSTaggedValue BuiltinsArrayBuffer::Slice(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 15. Let new be Construct(ctor, «newLen»). JSHandle undefined = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(newLen)); - JSTaggedValue taggedNewArrBuf = JSFunction::Construct(thread, constructor, 1, arguments->GetArgv(), undefined); + + auto info = NewRuntimeCallInfo(thread, constructor, JSTaggedValue::Undefined(), undefined, 1); + info->SetCallArgs(JSTaggedValue(newLen)); + JSTaggedValue taggedNewArrBuf = JSFunction::Construct(info.get()); JSHandle newArrBuf(thread, taggedNewArrBuf); // 16. ReturnIfAbrupt(new). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); diff --git a/runtime/builtins/builtins_async_from_sync_iterator.cpp b/runtime/builtins/builtins_async_from_sync_iterator.cpp index cc481f40c..d12294e38 100644 --- a/runtime/builtins/builtins_async_from_sync_iterator.cpp +++ b/runtime/builtins/builtins_async_from_sync_iterator.cpp @@ -49,7 +49,7 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeNext( } // 7. IfAbruptRejectPromise(result, promiseCapability). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { result.Update(JSPromise::IfThrowGetThrowValue(thread)); } RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); @@ -66,7 +66,6 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeRetur JSThread *thread = argv->GetThread(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConstants = thread->GlobalConstants(); - InternalCallParams *arguments = thread->GetInternalCallParams(); [[maybe_unused]] EcmaHandleScope handleScope(thread); @@ -97,10 +96,10 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeRetur JSHandle iterResult = JSIterator::CreateIterResultObject(thread, GetCallArg(argv, 0), true); // b. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iterResult »). - arguments->MakeArgv(iterResult); JSHandle resolve(thread, promiseCapability->GetResolve()); - [[maybe_unused]] JSTaggedValue res = - JSFunction::Call(thread, resolve, globalConstants->GetHandledUndefined(), 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, resolve, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 1); + info->SetCallArgs(iterResult); + [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info.get()); // c. Return promiseCapability.[[Promise]]. return promiseCapability->GetPromise(); @@ -108,20 +107,23 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeRetur JSMutableHandle result(thread, globalConstants->GetHandledUndefined()); - // 8. If value is present, then - if (argv->GetArgsNumber() > 0) { - // a. Let result be Call(return, syncIterator, « value »). - arguments->MakeArgv(GetCallArg(argv, 0)); - result.Update(JSFunction::Call(thread, returnMethod, iterator, 1, arguments->GetArgv())); - } else { - // 9. Else, - // a. Let result be Call(return, syncIterator). - arguments->MakeEmptyArgv(); - result.Update(JSFunction::Call(thread, returnMethod, iterator, 0, arguments->GetArgv())); + { + ScopedCallInfo info; + // 8. If value is present, then + if (argv->GetArgsNumber() > 0) { + // a. Let result be Call(return, syncIterator, « value »). + info = NewRuntimeCallInfo(thread, returnMethod, iterator, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(GetCallArg(argv, 0)); + } else { + // 9. Else, + // a. Let result be Call(return, syncIterator). + info = NewRuntimeCallInfo(thread, returnMethod, iterator, JSTaggedValue::Undefined(), 0); + } + result.Update(JSFunction::Call(info.get())); } // 10. IfAbruptRejectPromise(result, promiseCapability). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { result.Update(JSPromise::IfThrowGetThrowValue(thread)); } RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); @@ -132,10 +134,10 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeRetur ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle typeError = factory->GetJSError(ErrorType::TYPE_ERROR, "Return is not an object"); - arguments->MakeArgv(typeError); JSHandle reject(thread, promiseCapability->GetReject()); - [[maybe_unused]] JSTaggedValue res = - JSFunction::Call(thread, reject, globalConstants->GetHandledUndefined(), 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, reject, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 1); + info->SetCallArgs(typeError); + [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info.get()); // b. Return promiseCapability.[[Promise]]. return promiseCapability->GetPromise(); @@ -154,7 +156,6 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeThrow ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle env = thread->GetEcmaVM()->GetGlobalEnv(); const GlobalEnvConstants *globalConstants = thread->GlobalConstants(); - InternalCallParams *arguments = thread->GetInternalCallParams(); [[maybe_unused]] EcmaHandleScope handleScope(thread); @@ -182,15 +183,15 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeThrow // 7. If throw is undefined, then if (throwMethod->IsUndefined()) { // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « value »). + JSHandle reject(thread, promiseCapability->GetReject()); + ScopedCallInfo info; if (argv->GetArgsNumber() > 0) { - arguments->MakeArgv(GetCallArg(argv, 0)); + info = NewRuntimeCallInfo(thread, reject, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 1); + info->SetCallArgs(GetCallArg(argv, 0)); } else { - arguments->MakeEmptyArgv(); + info = NewRuntimeCallInfo(thread, reject, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 0); } - - JSHandle reject(thread, promiseCapability->GetReject()); - [[maybe_unused]] JSTaggedValue callResult = JSFunction::Call( - thread, reject, globalConstants->GetHandledUndefined(), arguments->GetLength(), arguments->GetArgv()); + [[maybe_unused]] JSTaggedValue callResult = JSFunction::Call(info.get()); // b. Return promiseCapability.[[Promise]]. return promiseCapability->GetPromise(); @@ -198,20 +199,23 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeThrow JSMutableHandle result(thread, globalConstants->GetHandledUndefined()); - // 8. If value is present, then - if (argv->GetArgsNumber() > 0) { - // a. Let result be Call(throw, syncIterator, « value »). - arguments->MakeArgv(GetCallArg(argv, 0)); - result.Update(JSFunction::Call(thread, throwMethod, iterator, 1, arguments->GetArgv())); - } else { - // 9. Else, - // a. Let result be Call(throw, syncIterator). - arguments->MakeEmptyArgv(); - result.Update(JSFunction::Call(thread, throwMethod, iterator, 0, arguments->GetArgv())); + { + ScopedCallInfo info; + // 8. If value is present, then + if (argv->GetArgsNumber() > 0) { + // a. Let result be Call(throw, syncIterator, « value »). + info = NewRuntimeCallInfo(thread, throwMethod, iterator, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(GetCallArg(argv, 0)); + } else { + // 9. Else, + // a. Let result be Call(throw, syncIterator). + info = NewRuntimeCallInfo(thread, throwMethod, iterator, JSTaggedValue::Undefined(), 0); + } + result.Update(JSFunction::Call(info.get())); } // 10. IfAbruptRejectPromise(result, promiseCapability). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { result.Update(JSPromise::IfThrowGetThrowValue(thread)); } RETURN_REJECT_PROMISE_IF_ABRUPT(thread, result, promiseCapability); @@ -220,11 +224,10 @@ JSTaggedValue BuiltinsAsyncFromSyncIterator::AsyncFromSyncIteratorPrototypeThrow if (!result->IsECMAObject()) { // a. Perform ! Call(promiseCapability.[[Reject]], undefined, « a newly created TypeError object »).. JSHandle typeError = factory->GetJSError(ErrorType::TYPE_ERROR, "Throw is not an object"); - arguments->MakeArgv(typeError); JSHandle reject(thread, promiseCapability->GetReject()); - [[maybe_unused]] JSTaggedValue callResult = - JSFunction::Call(thread, reject, globalConstants->GetHandledUndefined(), 1, arguments->GetArgv()); - + auto info = NewRuntimeCallInfo(thread, reject, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 1); + info->SetCallArgs(typeError); + [[maybe_unused]] JSTaggedValue callResult = JSFunction::Call(info.get()); // b. Return promiseCapability.[[Promise]]. return promiseCapability->GetPromise(); } diff --git a/runtime/builtins/builtins_date.cpp b/runtime/builtins/builtins_date.cpp index 53f34fc64..a49e2d34d 100644 --- a/runtime/builtins/builtins_date.cpp +++ b/runtime/builtins/builtins_date.cpp @@ -175,7 +175,8 @@ JSTaggedValue BuiltinsDate::ToJSON(EcmaRuntimeCallInfo *argv) } } JSHandle calleeKey(thread->GetEcmaVM()->GetFactory()->NewFromCanBeCompressString("toISOString")); - return JSFunction::Invoke(thread, objectHandle, calleeKey, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), objectHandle, JSTaggedValue::Undefined(), 0); + return JSFunction::Invoke(info.get(), calleeKey); } // 20.4.4.44 diff --git a/runtime/builtins/builtins_function.cpp b/runtime/builtins/builtins_function.cpp index a85e6ba66..7e6fc75f2 100644 --- a/runtime/builtins/builtins_function.cpp +++ b/runtime/builtins/builtins_function.cpp @@ -37,34 +37,50 @@ JSTaggedValue BuiltinsFunction::FunctionPrototypeInvokeSelf([[maybe_unused]] Ecm } namespace { -bool BuildArgumentsListFast(JSThread *thread, const JSHandle &arrayObj) + +size_t MakeArgListWithHole(JSThread *thread, TaggedArray *argv, size_t length) +{ + if (length > argv->GetLength()) { + length = argv->GetLength(); + } + for (size_t index = 0; index < length; ++index) { + JSTaggedValue value = argv->Get(thread, index); + if (value.IsHole()) { + argv->Set(thread, index, JSTaggedValue::Undefined()); + } + } + return length; +} + +std::pair BuildArgumentsListFast(JSThread *thread, const JSHandle &arrayObj) { if (!arrayObj->HasStableElements(thread)) { - return false; + return std::make_pair(nullptr, 0); } - InternalCallParams *arguments = thread->GetInternalCallParams(); if (arrayObj->IsStableJSArguments(thread)) { JSHandle argList = JSHandle::Cast(arrayObj); TaggedArray *elements = TaggedArray::Cast(argList->GetElements().GetTaggedObject()); auto env = thread->GetEcmaVM()->GetGlobalEnv(); if (argList->GetClass() != env->GetArgumentsClass().GetObject()) { - return false; + return std::make_pair(nullptr, 0); } auto result = argList->GetPropertyInlinedProps(JSArguments::LENGTH_INLINE_PROPERTY_INDEX); if (!result.IsInt()) { - return false; + return std::make_pair(nullptr, 0); } - auto length = static_cast(result.GetInt()); - arguments->MakeArgListWithHole(elements, length); - } else if (arrayObj->IsStableJSArray(thread)) { + auto length = static_cast(result.GetInt()); + size_t res = MakeArgListWithHole(thread, elements, length); + return std::make_pair(elements, res); + } + + if (arrayObj->IsStableJSArray(thread)) { JSHandle argList = JSHandle::Cast(arrayObj); TaggedArray *elements = TaggedArray::Cast(argList->GetElements().GetTaggedObject()); - uint32_t length = argList->GetArrayLength(); - arguments->MakeArgListWithHole(elements, length); - } else { - UNREACHABLE(); + size_t length = argList->GetArrayLength(); + size_t res = MakeArgListWithHole(thread, elements, length); + return std::make_pair(elements, res); } - return true; + UNREACHABLE(); } } // anonymous namespace @@ -83,24 +99,33 @@ JSTaggedValue BuiltinsFunction::FunctionPrototypeApply(EcmaRuntimeCallInfo *argv JSHandle func = GetThis(argv); JSHandle thisArg = GetCallArg(argv, 0); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); // 2. If argArray is null or undefined, then if (GetCallArg(argv, 1)->IsUndefined()) { // null will also get undefined // a. Return Call(func, thisArg). - return JSFunction::Call(thread, func, thisArg, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, func, thisArg, undefined, 0); + return JSFunction::Call(info.get()); } // 3. Let argList be CreateListFromArrayLike(argArray). JSHandle arrayObj = GetCallArg(argv, 1); - InternalCallParams *arguments = thread->GetInternalCallParams(); - if (!BuildArgumentsListFast(thread, arrayObj)) { - auto listRes = JSObject::CreateListFromArrayLike(thread, arrayObj); + auto [array, length] = BuildArgumentsListFast(thread, arrayObj); + if (array == nullptr) { + auto arg_list_res = JSObject::CreateListFromArrayLike(thread, arrayObj); // 4. ReturnIfAbrupt(argList). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - JSHandle argList = JSHandle::Cast(listRes); - arguments->MakeArgList(*argList); + JSHandle arg_list = JSHandle::Cast(arg_list_res); + const auto args_length = static_cast(arg_list->GetLength()); + auto info = NewRuntimeCallInfo(thread, func, thisArg, undefined, args_length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(args_length, arg_list->GetData()); + return JSFunction::Call(info.get()); } - // 6. Return Call(func, thisArg, argList). - return JSFunction::Call(thread, func, thisArg, arguments->GetLength(), arguments->GetArgv()); + const auto args_length = static_cast(length); + auto info = NewRuntimeCallInfo(thread, func, thisArg, undefined, args_length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(args_length, array->GetData()); + return JSFunction::Call(info.get()); } // ecma 19.2.3.2 Function.prototype.bind (thisArg , ...args) @@ -217,11 +242,15 @@ JSTaggedValue BuiltinsFunction::FunctionPrototypeCall(EcmaRuntimeCallInfo *argv) // 2. Let argList be an empty List. // 3. If this method was called with more than one argument then in left to right order, // starting with the second argument, append each argument as the last element of argList. - InternalCallParams *argsList = thread->GetInternalCallParams(); - argsList->MakeArgv(argv, 1); - // 5. Return Call(func, thisArg, argList). - return JSFunction::Call(thread, func, thisArg, argsLength, argsList->GetArgv()); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + auto info = NewRuntimeCallInfo(thread, func, thisArg, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (argsLength > 0) { + info->SetCallArg(argsLength, + reinterpret_cast(argv->GetArgAddress(JSMethodArgs::NUM_MANDATORY_ARGS + 1))); + } + return JSFunction::Call(info.get()); } // ecma 19.2.3.5 Function.prototype.toString () diff --git a/runtime/builtins/builtins_global.cpp b/runtime/builtins/builtins_global.cpp index 1f6e15062..e51a1001a 100644 --- a/runtime/builtins/builtins_global.cpp +++ b/runtime/builtins/builtins_global.cpp @@ -940,10 +940,8 @@ JSTaggedValue BuiltinsGlobal::CallJsBoundFunction(EcmaRuntimeCallInfo *msg) JSHandle boundFunc(GetConstructor(msg)); JSHandle thisObj(thread, boundFunc->GetBoundThis()); - - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(msg, 0); - return SlowRuntimeHelper::CallBoundFunction(thread, boundFunc, thisObj); + msg->SetThis(thisObj.GetTaggedValue()); + return SlowRuntimeHelper::CallBoundFunction(msg); } JSTaggedValue BuiltinsGlobal::CallJsProxy(EcmaRuntimeCallInfo *msg) @@ -958,12 +956,7 @@ JSTaggedValue BuiltinsGlobal::CallJsProxy(EcmaRuntimeCallInfo *msg) } // Calling proxy directly should transfer 'undefined' as this - JSHandle thisObj(GetThis(msg)); - - JSHandle argsList = GetArgsArray(msg); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgList(*argsList); - return JSProxy::CallInternal(thread, proxy, thisObj, argsList->GetLength(), arguments->GetArgv()); + return JSProxy::CallInternal(msg); } #if ECMASCRIPT_ENABLE_RUNTIME_STAT diff --git a/runtime/builtins/builtins_map.cpp b/runtime/builtins/builtins_map.cpp index f0cef100f..8f6530444 100644 --- a/runtime/builtins/builtins_map.cpp +++ b/runtime/builtins/builtins_map.cpp @@ -194,15 +194,16 @@ JSTaggedValue BuiltinsMap::ForEach([[maybe_unused]] EcmaRuntimeCallInfo *argv) JSHandle keyIndex(thread, JSTaggedValue(0)); JSHandle valueIndex(thread, JSTaggedValue(1)); JSHandle result = JSIterator::IteratorStep(thread, iter); - InternalCallParams *arguments = thread->GetInternalCallParams(); + while (!result->IsFalse()) { RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, result.GetTaggedValue()); JSHandle iterValue(JSIterator::IteratorValue(thread, result)); JSHandle key = JSObject::GetProperty(thread, iterValue, keyIndex).GetValue(); JSHandle value = JSObject::GetProperty(thread, iterValue, valueIndex).GetValue(); // Let funcResult be Call(callbackfn, T, «e, e, S»). - arguments->MakeArgv(value, key, JSHandle(map)); - JSTaggedValue ret = JSFunction::Call(thread, func, thisArg, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, func, thisArg, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(value, key, JSHandle(map)); + JSTaggedValue ret = JSFunction::Call(info.get()); // 3: three args // returnIfAbrupt RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret); result = JSIterator::IteratorStep(thread, iter); diff --git a/runtime/builtins/builtins_object.cpp b/runtime/builtins/builtins_object.cpp index d8cf2836c..b193d8a0c 100644 --- a/runtime/builtins/builtins_object.cpp +++ b/runtime/builtins/builtins_object.cpp @@ -830,10 +830,13 @@ JSTaggedValue BuiltinsObject::ToLocaleString(EcmaRuntimeCallInfo *argv) // 2. Return Invoke(O, "toString"). JSHandle calleeKey = thread->GlobalConstants()->GetHandledToStringString(); - JSHandle argsList = GetArgsArray(argv); - ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgList(*argsList); - return JSFunction::Invoke(thread, object, calleeKey, argsList->GetLength(), arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), object, JSTaggedValue::Undefined(), + argv->GetArgsNumber()); + if (argv->GetArgsNumber() > 0) { + info->SetCallArg(argv->GetArgsNumber(), + reinterpret_cast(argv->GetArgAddress(JSMethodArgs::NUM_MANDATORY_ARGS))); + } + return JSFunction::Invoke(info.get(), calleeKey); } JSTaggedValue BuiltinsObject::GetBuiltinTag(JSThread *thread, const JSHandle &object) diff --git a/runtime/builtins/builtins_promise.cpp b/runtime/builtins/builtins_promise.cpp index 88a881db0..1e8d0704a 100644 --- a/runtime/builtins/builtins_promise.cpp +++ b/runtime/builtins/builtins_promise.cpp @@ -70,21 +70,26 @@ JSTaggedValue BuiltinsPromise::PromiseConstructor([[maybe_unused]] EcmaRuntimeCa // 9. Let completion be Call(executor, undefined, «resolvingFunctions.[[Resolve]], resolvingFunctions.[[reject]]) auto resolveFunc = resolvingFunction->GetResolveFunction(); auto rejectFunc = resolvingFunction->GetRejectFunction(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(resolveFunc, rejectFunc); + + JSTaggedValue taggedValue; JSHandle thisValue = globalConst->GetHandledUndefined(); - JSTaggedValue taggedValue = JSFunction::Call(thread, executor, thisValue, 2, arguments->GetArgv()); // 2: two args + { + auto info = NewRuntimeCallInfo(thread, executor, thisValue, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(resolveFunc, rejectFunc); + taggedValue = JSFunction::Call(info.get()); // 2: two args + } JSHandle completionValue(thread, taggedValue); // 10. If completion is an abrupt completion, then // a. Let status be Call(resolvingFunctions.[[Reject]], undefined, «completion.[[value]]»). // b. ReturnIfAbrupt(status). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { completionValue = JSPromise::IfThrowGetThrowValue(thread); thread->ClearException(); JSHandle reject(thread, resolvingFunction->GetRejectFunction()); - arguments->MakeArgv(completionValue); - JSFunction::Call(thread, reject, thisValue, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, reject, thisValue, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(completionValue); + JSFunction::Call(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } @@ -126,7 +131,7 @@ JSTaggedValue BuiltinsPromise::All(EcmaRuntimeCallInfo *argv) // 8. Let iterator be GetIterator(iterable). JSHandle itor = JSIterator::GetIterator(thread, GetCallArg(argv, 0)); // 9. IfAbruptRejectPromise(iterator, promiseCapability). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { itor = JSPromise::IfThrowGetThrowValue(thread); } RETURN_REJECT_PROMISE_IF_ABRUPT(thread, itor, capa); @@ -192,7 +197,7 @@ JSTaggedValue BuiltinsPromise::Race(EcmaRuntimeCallInfo *argv) // 9. IfAbruptRejectPromise(iterator, promiseCapability). JSHandle iterable = GetCallArg(argv, 0); JSHandle iterator = JSIterator::GetIterator(thread, iterable); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { iterator = JSPromise::IfThrowGetThrowValue(thread); } RETURN_REJECT_PROMISE_IF_ABRUPT(thread, iterator, promiseCapability); @@ -269,9 +274,10 @@ JSTaggedValue BuiltinsPromise::Reject(EcmaRuntimeCallInfo *argv) JSHandle reason = GetCallArg(argv, 0); JSHandle reject(thread, promiseCapability->GetReject()); JSHandle undefined = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(reason); - JSFunction::Call(thread, reject, undefined, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, reject, undefined, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(reason); + JSFunction::Call(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 7. Return promiseCapability.[[Promise]]. @@ -300,9 +306,9 @@ JSTaggedValue BuiltinsPromise::Catch(EcmaRuntimeCallInfo *argv) JSHandle thenKey = globalConst->GetHandledPromiseThenString(); JSHandle reject = GetCallArg(argv, 0); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(globalConst->GetHandledUndefined(), reject); - return JSFunction::Invoke(thread, promise, thenKey, 2, arguments->GetArgv()); // 2: two args + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), promise, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(JSTaggedValue::Undefined(), reject); + return JSFunction::Invoke(info.get(), thenKey); // 2: two args } // 25.4.5.3 Promise.prototype.then ( onFulfilled , onRejected ) @@ -436,7 +442,7 @@ JSHandle BuiltinsPromise::PerformPromiseAll(JSThread *thread, // a. Let next be IteratorStep(iteratorRecord.[[iterator]]). next.Update(JSIterator::IteratorStep(thread, itor).GetTaggedValue()); // b. If next is an abrupt completion, set iteratorRecord.[[done]] to true. - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { itRecord->SetDone(thread, JSTaggedValue::True()); next.Update(JSPromise::IfThrowGetThrowValue(thread).GetTaggedValue()); } @@ -455,10 +461,11 @@ JSHandle BuiltinsPromise::PerformPromiseAll(JSThread *thread, JSArray::CreateArrayFromList(thread, JSHandle(thread, values->GetValue())); // 2. Let resolveResult be Call(resultCapability.[[Resolve]], undefined, «valuesArray»). JSHandle resCapaFunc(thread, capa->GetResolve()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(jsArrayValues.GetTaggedValue()); - JSTaggedValue resolveRes = - JSFunction::Call(thread, resCapaFunc, globalConst->GetHandledUndefined(), 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, resCapaFunc, globalConst->GetHandledUndefined(), + JSTaggedValue::Undefined(), 1); + info->SetCallArgs(jsArrayValues.GetTaggedValue()); + JSTaggedValue resolveRes = JSFunction::Call(info.get()); // 3. ReturnIfAbrupt(resolveResult) JSHandle resolveAbrupt(thread, resolveRes); RETURN_COMPLETION_IF_ABRUPT(thread, resolveAbrupt); @@ -471,7 +478,7 @@ JSHandle BuiltinsPromise::PerformPromiseAll(JSThread *thread, // e. Let nextValue be IteratorValue(next). JSHandle nextVal = JSIterator::IteratorValue(thread, next); // f. If nextValue is an abrupt completion, set iteratorRecord.[[done]] to true. - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { itRecord->SetDone(thread, JSTaggedValue::True()); if (thread->GetException().IsObjectWrapper()) { JSHandle wrapperVal(thread, thread->GetException()); @@ -492,9 +499,12 @@ JSHandle BuiltinsPromise::PerformPromiseAll(JSThread *thread, values->SetValue(thread, valuesArray); // i. Let nextPromise be Invoke(constructor, "resolve", «‍nextValue»). JSHandle resolveKey = globalConst->GetHandledPromiseResolveString(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(nextVal); - JSTaggedValue taggedNextPromise = JSFunction::Invoke(thread, ctor, resolveKey, 1, arguments->GetArgv()); + JSTaggedValue taggedNextPromise; + { + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), ctor, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(nextVal); + taggedNextPromise = JSFunction::Invoke(info.get(), resolveKey); + } // j. ReturnIfAbrupt(nextPromise). JSHandle nextPromise(thread, taggedNextPromise); RETURN_COMPLETION_IF_ABRUPT(thread, nextPromise); @@ -517,10 +527,14 @@ JSHandle BuiltinsPromise::PerformPromiseAll(JSThread *thread, // q. Set remainingElementsCount.[[value]] to remainingElementsCount.[[value]] + 1. remainCnt->SetValue(thread, ++JSTaggedNumber(remainCnt->GetValue())); // r. Let result be Invoke(nextPromise, "then", «‍resolveElement, resultCapability.[[Reject]]»). - JSHandle thenKey = globalConst->GetHandledPromiseThenString(); - arguments->MakeArgv(resoleveElement.GetTaggedValue(), capa->GetReject()); - JSTaggedValue taggedResult = - JSFunction::Invoke(thread, nextPromise, thenKey, 2, arguments->GetArgv()); // 2: two args + JSTaggedValue taggedResult; + { + JSHandle thenKey = globalConst->GetHandledPromiseThenString(); + auto info = + NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), nextPromise, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(resoleveElement, capa->GetReject()); + taggedResult = JSFunction::Invoke(info.get(), thenKey); + } JSHandle result(thread, taggedResult); // s. ReturnIfAbrupt(result). @@ -556,7 +570,7 @@ JSHandle BuiltinsPromise::PerformPromiseRace(JSThread *thread, JSMutableHandle next(thread, globalConst->GetUndefined()); while (true) { next.Update(JSIterator::IteratorStep(thread, iterator).GetTaggedValue()); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { iteratorRecord->SetDone(thread, JSTaggedValue::True()); next.Update(JSPromise::IfThrowGetThrowValue(thread).GetTaggedValue()); } @@ -569,29 +583,37 @@ JSHandle BuiltinsPromise::PerformPromiseRace(JSThread *thread, return completionRecord; } JSHandle nextValue = JSIterator::IteratorValue(thread, next); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { iteratorRecord->SetDone(thread, JSTaggedValue::True()); nextValue = JSPromise::IfThrowGetThrowValue(thread); } RETURN_COMPLETION_IF_ABRUPT(thread, nextValue); JSHandle resolveStr = globalConst->GetHandledPromiseResolveString(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(nextValue); - JSTaggedValue result = JSFunction::Invoke(thread, constructor, resolveStr, 1, arguments->GetArgv()); + JSTaggedValue result; + { + auto info = + NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), constructor, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(nextValue); + result = JSFunction::Invoke(info.get(), resolveStr); + } JSHandle nextPromise(thread, result); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { nextPromise = JSPromise::IfThrowGetThrowValue(thread); } RETURN_COMPLETION_IF_ABRUPT(thread, nextPromise); - JSHandle thenStr = globalConst->GetHandledPromiseThenString(); - arguments->MakeArgv(capability->GetResolve(), capability->GetReject()); - result = JSFunction::Invoke(thread, nextPromise, thenStr, 2, arguments->GetArgv()); // 2: two args + { + JSHandle thenStr = globalConst->GetHandledPromiseThenString(); + auto info = + NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), nextPromise, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(capability->GetResolve(), capability->GetReject()); + result = JSFunction::Invoke(info.get(), thenStr); // 2: two args + } JSHandle handleResult(thread, result); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { handleResult = JSPromise::IfThrowGetThrowValue(thread); } RETURN_COMPLETION_IF_ABRUPT(thread, handleResult); diff --git a/runtime/builtins/builtins_promise_handler.cpp b/runtime/builtins/builtins_promise_handler.cpp index bfaf0c02a..369cad69c 100644 --- a/runtime/builtins/builtins_promise_handler.cpp +++ b/runtime/builtins/builtins_promise_handler.cpp @@ -72,7 +72,7 @@ JSTaggedValue BuiltinsPromiseHandler::Resolve(EcmaRuntimeCallInfo *argv) // a. Return RejectPromise(promise, then.[[value]]). JSHandle thenKey(thread->GlobalConstants()->GetHandledPromiseThenString()); JSHandle thenValue = JSObject::GetProperty(thread, resolution, thenKey).GetValue(); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { if (!thenValue->IsJSError()) { if (thread->GetException().IsObjectWrapper()) { JSHandle wrapperValue(thread, thread->GetException()); @@ -210,9 +210,10 @@ JSTaggedValue BuiltinsPromiseHandler::ResolveElementFunction(EcmaRuntimeCallInfo // b. Return Call(promiseCapability.[[Resolve]], undefined, «valuesArray»). JSHandle capaResolve(thread, capa->GetResolve()); JSHandle undefine = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(jsArrayValues); - return JSFunction::Call(thread, capaResolve, undefine, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, capaResolve, undefine, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(jsArrayValues); + return JSFunction::Call(info.get()); } // 11. Return undefined. return JSTaggedValue::Undefined(); diff --git a/runtime/builtins/builtins_promise_job.cpp b/runtime/builtins/builtins_promise_job.cpp index 585a5b107..88957e6bd 100644 --- a/runtime/builtins/builtins_promise_job.cpp +++ b/runtime/builtins/builtins_promise_job.cpp @@ -43,11 +43,10 @@ JSTaggedValue BuiltinsPromiseJob::PromiseReactionJob(EcmaRuntimeCallInfo *argv) JSHandle handler(thread, reaction->GetHandler()); JSHandle thisValue = globalConst->GetHandledUndefined(); - InternalCallParams *result = thread->GetInternalCallParams(); - result->MakeArgv(argument); - + auto info = NewRuntimeCallInfo(thread, handler, thisValue, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(argument); if (capabilitiesValue.IsUndefined()) { - [[maybe_unused]] JSTaggedValue val = JSFunction::Call(thread, handler, thisValue, 1, result->GetArgv()); + [[maybe_unused]] JSTaggedValue val = JSFunction::Call(info.get()); return JSTaggedValue::Undefined(); } @@ -65,20 +64,21 @@ JSTaggedValue BuiltinsPromiseJob::PromiseReactionJob(EcmaRuntimeCallInfo *argv) } } else { // 6. Else, let handlerResult be Call(handler, undefined, «argument»). - JSTaggedValue taggedValue = JSFunction::Call(thread, handler, thisValue, 1, result->GetArgv()); - result->MakeArgv(taggedValue); + JSTaggedValue taggedValue = JSFunction::Call(info.get()); + info->SetCallArgs(taggedValue); // 7. If handlerResult is an abrupt completion, then // a. Let status be Call(promiseCapability.[[Reject]], undefined, «handlerResult.[[value]]»). // b. NextJob Completion(status). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { JSHandle throwValue = JSPromise::IfThrowGetThrowValue(thread); thread->ClearException(); - result->MakeArgv(throwValue); + info->SetCallArgs(throwValue); call.Update(capability->GetReject()); } } // 8. Let status be Call(promiseCapability.[[Resolve]], undefined, «handlerResult.[[value]]»). - return JSFunction::Call(thread, call, thisValue, 1, result->GetArgv()); + info->SetFunction(call.GetTaggedValue()); + return JSFunction::Call(info.get()); } JSTaggedValue BuiltinsPromiseJob::PromiseResolveThenableJob(EcmaRuntimeCallInfo *argv) @@ -97,20 +97,25 @@ JSTaggedValue BuiltinsPromiseJob::PromiseResolveThenableJob(EcmaRuntimeCallInfo JSHandle then = GetCallArg(argv, BuiltinsBase::ArgsPosition::THIRD); // 2. Let thenCallResult be Call(then, thenable, «resolvingFunctions.[[Resolve]], resolvingFunctions.[[Reject]]»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(resolvingFunctions->GetResolveFunction(), resolvingFunctions->GetRejectFunction()); - JSTaggedValue result = JSFunction::Call(thread, then, thenable, 2, arguments->GetArgv()); // 2: two args + + JSTaggedValue result; + { + auto info = NewRuntimeCallInfo(thread, then, thenable, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(resolvingFunctions->GetResolveFunction(), resolvingFunctions->GetRejectFunction()); + result = JSFunction::Call(info.get()); // 2: two args + } JSHandle thenResult(thread, result); // 3. If thenCallResult is an abrupt completion, // a. Let status be Call(resolvingFunctions.[[Reject]], undefined, «thenCallResult.[[value]]»). // b. NextJob Completion(status). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { thenResult = JSPromise::IfThrowGetThrowValue(thread); thread->ClearException(); JSHandle reject(thread, resolvingFunctions->GetRejectFunction()); JSHandle undefined = globalConst->GetHandledUndefined(); - arguments->MakeArgv(thenResult); - return JSFunction::Call(thread, reject, undefined, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, reject, undefined, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(thenResult); + return JSFunction::Call(info.get()); } // 4. NextJob Completion(thenCallResult). return result; diff --git a/runtime/builtins/builtins_reflect.cpp b/runtime/builtins/builtins_reflect.cpp index a19edcdaa..309723212 100644 --- a/runtime/builtins/builtins_reflect.cpp +++ b/runtime/builtins/builtins_reflect.cpp @@ -39,9 +39,12 @@ JSTaggedValue BuiltinsReflect::ReflectApply(EcmaRuntimeCallInfo *argv) // 3. Perform PrepareForTailCall(). // 4. Return ? Call(target, thisArgument, args). - ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgList(*args); - return JSFunction::Call(thread, target, thisArgument, args->GetLength(), arguments->GetArgv()); + const auto args_length = args->GetLength(); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + auto info = NewRuntimeCallInfo(thread, target, thisArgument, undefined, args_length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(args_length, args->GetData()); + return JSFunction::Call(info.get()); } // ecma 26.1.2 Reflect.construct (target, argumentsList [ , new_target]) @@ -70,9 +73,11 @@ JSTaggedValue BuiltinsReflect::ReflectConstruct(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle args = JSHandle::Cast(argOrAbrupt); // 5. Return ? Construct(target, args, new_target). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgList(*args); - return JSFunction::Construct(thread, target, args->GetLength(), arguments->GetArgv(), new_target); + const auto args_length = args->GetLength(); + auto info = NewRuntimeCallInfo(thread, target, JSTaggedValue::Undefined(), new_target, args_length); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(args_length, args->GetData()); + return JSFunction::Construct(info.get()); } // ecma 26.1.3 Reflect.defineProperty (target, propertyKey, attributes) diff --git a/runtime/builtins/builtins_regexp.cpp b/runtime/builtins/builtins_regexp.cpp index ac08e5a95..6537673c0 100644 --- a/runtime/builtins/builtins_regexp.cpp +++ b/runtime/builtins/builtins_regexp.cpp @@ -580,10 +580,9 @@ JSTaggedValue BuiltinsRegExp::MatchAll(EcmaRuntimeCallInfo *argv) // 6. Let matcher be ? Construct(C, « R, flags »). JSHandle undefined = globalConstants->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisObj.GetTaggedValue(), flagsStrHandle.GetTaggedValue()); - - JSTaggedValue taggedMatcher = JSFunction::Construct(thread, constructor, 2, arguments->GetArgv(), undefined); + auto info = NewRuntimeCallInfo(thread, constructor, JSTaggedValue::Undefined(), undefined, 2); + info->SetCallArgs(thisObj.GetTaggedValue(), flagsStrHandle.GetTaggedValue()); + JSTaggedValue taggedMatcher = JSFunction::Construct(info.get()); JSHandle matcherHandle(thread, taggedMatcher); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -996,10 +995,11 @@ JSTaggedValue BuiltinsRegExp::Replace(EcmaRuntimeCallInfo *argv) } // iv. Let replValue be Call(replaceValue, undefined, replacerArgs). const int32_t argsLength = replacerArgs->GetLength(); - JSHandle undefined = globalConst->GetHandledUndefined(); - - JSTaggedValue replaceResult = - JSFunction::Call(thread, inputReplaceValue, undefined, argsLength, replacerArgs->GetData()); + auto info = NewRuntimeCallInfo(thread, inputReplaceValue, JSTaggedValue::Undefined(), + JSTaggedValue::Undefined(), argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetCallArg(argsLength, replacerArgs->GetData()); + JSTaggedValue replaceResult = JSFunction::Call(info.get()); JSHandle replValue(thread, replaceResult); // v. Let replacement be ToString(replValue). JSHandle replacementString = JSTaggedValue::ToString(thread, replValue); @@ -1198,9 +1198,9 @@ JSTaggedValue BuiltinsRegExp::Split(EcmaRuntimeCallInfo *argv) JSHandle globalObject(thread, thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject()); JSHandle undefined = globalConstants->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisObj.GetTaggedValue(), newFlagsHandle.GetTaggedValue()); - JSTaggedValue taggedSplitter = JSFunction::Construct(thread, constructor, 2, arguments->GetArgv(), undefined); + auto info = NewRuntimeCallInfo(thread, constructor, JSTaggedValue::Undefined(), undefined, 2); + info->SetCallArgs(thisObj.GetTaggedValue(), newFlagsHandle.GetTaggedValue()); + JSTaggedValue taggedSplitter = JSFunction::Construct(info.get()); // 14. ReturnIfAbrupt(splitter). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -1571,9 +1571,9 @@ JSTaggedValue BuiltinsRegExp::RegExpExec(JSThread *thread, const JSHandleIsCallable()) { - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(inputStr.GetTaggedValue()); - JSTaggedValue result = JSFunction::Call(thread, exec, regexp, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, exec, regexp, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(inputStr.GetTaggedValue()); + JSTaggedValue result = JSFunction::Call(info.get()); // b. ReturnIfAbrupt(result). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!result.IsECMAObject() && !result.IsNull()) { diff --git a/runtime/builtins/builtins_set.cpp b/runtime/builtins/builtins_set.cpp index f57501ad5..60240f01c 100644 --- a/runtime/builtins/builtins_set.cpp +++ b/runtime/builtins/builtins_set.cpp @@ -75,7 +75,7 @@ JSTaggedValue BuiltinsSet::SetConstructor(EcmaRuntimeCallInfo *argv) // jsarray JSHandle valueIndex(thread, JSTaggedValue(1)); JSHandle next = JSIterator::IteratorStep(thread, iter); - InternalCallParams *arguments = thread->GetInternalCallParams(); + while (!next->IsFalse()) { // ReturnIfAbrupt(next). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, next.GetTaggedValue()); @@ -83,16 +83,18 @@ JSTaggedValue BuiltinsSet::SetConstructor(EcmaRuntimeCallInfo *argv) JSHandle nextValue(JSIterator::IteratorValue(thread, next)); // ReturnIfAbrupt(nextValue). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, nextValue.GetTaggedValue()); - arguments->MakeArgv(nextValue); + auto info = NewRuntimeCallInfo(thread, adder, set, JSTaggedValue::Undefined(), 1); if (nextValue->IsArray(thread)) { auto prop = JSObject::GetProperty(thread, nextValue, valueIndex).GetValue(); - arguments->MakeArgv(prop); + info->SetCallArgs(prop); + } else { + info->SetCallArgs(nextValue); } - JSTaggedValue ret = JSFunction::Call(thread, adder, JSHandle(set), 1, arguments->GetArgv()); + JSTaggedValue ret = JSFunction::Call(info.get()); // Let status be Call(adder, set, «nextValue.[[value]]»). JSHandle status(thread, ret); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, status); } // Let next be IteratorStep(iter). @@ -206,13 +208,14 @@ JSTaggedValue BuiltinsSet::ForEach([[maybe_unused]] EcmaRuntimeCallInfo *argv) // composed arguments JSHandle iter(factory->NewJSSetIterator(set, IterationKind::KEY)); JSHandle result = JSIterator::IteratorStep(thread, iter); - InternalCallParams *arguments = thread->GetInternalCallParams(); + while (!result->IsFalse()) { RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, result.GetTaggedValue()); JSHandle value = JSIterator::IteratorValue(thread, result); // Let funcResult be Call(callbackfn, T, «e, e, S»). - arguments->MakeArgv(value, value, JSHandle(set)); - JSTaggedValue ret = JSFunction::Call(thread, func, thisArg, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, func, thisArg, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(value, value, JSHandle(set)); + JSTaggedValue ret = JSFunction::Call(info.get()); // 3: three args // returnIfAbrupt RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, ret); result = JSIterator::IteratorStep(thread, iter); diff --git a/runtime/builtins/builtins_string.cpp b/runtime/builtins/builtins_string.cpp index fa9cc9fb2..993770e97 100644 --- a/runtime/builtins/builtins_string.cpp +++ b/runtime/builtins/builtins_string.cpp @@ -597,9 +597,10 @@ JSTaggedValue BuiltinsString::Match(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!matcher->IsUndefined()) { ASSERT(matcher->IsJSFunction()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisTag); - return JSFunction::Call(thread, matcher, regexp, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, matcher, regexp, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(thisTag); + return JSFunction::Call(info.get()); } } } @@ -608,9 +609,10 @@ JSTaggedValue BuiltinsString::Match(EcmaRuntimeCallInfo *argv) JSHandle undifinedHandle = globalConst->GetHandledUndefined(); JSHandle rx(thread, BuiltinsRegExp::RegExpCreate(thread, regexp, undifinedHandle)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisVal.GetTaggedValue()); - return JSFunction::Invoke(thread, rx, matchTag, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), rx, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(thisVal.GetTaggedValue()); + return JSFunction::Invoke(info.get(), matchTag); } JSTaggedValue BuiltinsString::MatchAll(EcmaRuntimeCallInfo *argv) @@ -658,9 +660,10 @@ JSTaggedValue BuiltinsString::MatchAll(EcmaRuntimeCallInfo *argv) if (!matcher->IsUndefined()) { ASSERT(matcher->IsJSFunction()); // i. i. Return ? Call(matcher, regexp, « O »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisTag.GetTaggedValue()); - return JSFunction::Call(thread, matcher, regexp, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, matcher, regexp, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(thisTag.GetTaggedValue()); + return JSFunction::Call(info.get()); } } } @@ -669,9 +672,10 @@ JSTaggedValue BuiltinsString::MatchAll(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 4. Let rx be ? RegExpCreate(regexp, "g"). JSHandle rx(thread, BuiltinsRegExp::RegExpCreate(thread, regexp, gvalue)); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisVal.GetTaggedValue()); - return JSFunction::Invoke(thread, rx, matchAllTag, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), rx, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(thisVal.GetTaggedValue()); + return JSFunction::Invoke(info.get(), matchAllTag); } // 21.1.3.12 @@ -842,9 +846,10 @@ JSTaggedValue BuiltinsString::Replace(EcmaRuntimeCallInfo *argv) // If replacer is not undefined, then if (!replaceMethod->IsUndefined()) { // Return Call(replacer, searchValue, «O, replaceValue»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisTag, replaceTag); - return JSFunction::Call(thread, replaceMethod, searchTag, 2, arguments->GetArgv()); // 2: two args + + auto info = NewRuntimeCallInfo(thread, replaceMethod, searchTag, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(thisTag, replaceTag); + return JSFunction::Call(info.get()); // 2: two args } } @@ -876,11 +881,9 @@ JSTaggedValue BuiltinsString::Replace(EcmaRuntimeCallInfo *argv) // If functionalReplace is true, then if (replaceTag->IsCallable()) { // Let replValue be Call(replaceValue, undefined,«matched, pos, and string»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSHandle(searchString), JSHandle(thread, JSTaggedValue(pos)), - JSHandle(thisString)); - JSTaggedValue replStrDeocodeValue = JSFunction::Call(thread, replaceTag, globalConst->GetHandledUndefined(), 3, - arguments->GetArgv()); // 3: «matched, pos, and string» + auto info = NewRuntimeCallInfo(thread, replaceTag, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 3); + info->SetCallArgs(searchString, JSTaggedValue(pos), thisString); + JSTaggedValue replStrDeocodeValue = JSFunction::Call(info.get()); // 3: «matched, pos, and string» replHandle.Update(replStrDeocodeValue); } else { JSHandle undefined = globalConst->GetHandledUndefined(); @@ -955,9 +958,10 @@ JSTaggedValue BuiltinsString::ReplaceAll(EcmaRuntimeCallInfo *argv) // d. If replacer is not undefined, then if (!replaceMethod->IsUndefined()) { // i. Return ? Call(replacer, searchValue, «O, replaceValue»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisTag.GetTaggedValue(), replaceTag.GetTaggedValue()); - return JSFunction::Call(thread, replaceMethod, searchTag, 2, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, replaceMethod, searchTag, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(thisTag.GetTaggedValue(), replaceTag.GetTaggedValue()); + return JSFunction::Call(info.get()); } } @@ -994,10 +998,10 @@ JSTaggedValue BuiltinsString::ReplaceAll(EcmaRuntimeCallInfo *argv) // If functionalReplace is true, then if (replaceTag->IsCallable()) { // Let replValue be Call(replaceValue, undefined, «matched, pos, and string»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(searchString.GetTaggedValue(), JSTaggedValue(pos), thisString.GetTaggedValue()); - JSTaggedValue replStrDeocodeValue = - JSFunction::Call(thread, replaceTag, undefined, 3U, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, replaceTag, undefined, JSTaggedValue::Undefined(), 3U); + info->SetCallArgs(searchString.GetTaggedValue(), JSTaggedValue(pos), thisString.GetTaggedValue()); + JSTaggedValue replStrDeocodeValue = JSFunction::Call(info.get()); replHandle.Update(replStrDeocodeValue); } else { // Let captures be an empty List. @@ -1289,9 +1293,10 @@ JSTaggedValue BuiltinsString::Search(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!searcher->IsUndefined()) { ASSERT(searcher->IsJSFunction()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisTag); - return JSFunction::Call(thread, searcher, regexp, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, searcher, regexp, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(thisTag); + return JSFunction::Call(info.get()); } } } @@ -1300,9 +1305,10 @@ JSTaggedValue BuiltinsString::Search(EcmaRuntimeCallInfo *argv) JSHandle undifinedHandle = globalConst->GetHandledUndefined(); JSHandle rx(thread, BuiltinsRegExp::RegExpCreate(thread, regexp, undifinedHandle)); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisVal.GetTaggedValue()); - return JSFunction::Invoke(thread, rx, searchTag, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), rx, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(thisVal.GetTaggedValue()); + return JSFunction::Invoke(info.get(), searchTag); } // 21.1.3.16 @@ -1370,9 +1376,10 @@ JSTaggedValue BuiltinsString::Split(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (!splitter->IsUndefined()) { // Return Call(splitter, separator, «‍O, limit»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(thisTag, limitTag); - return JSFunction::Call(thread, splitter, seperatorTag, 2, arguments->GetArgv()); // 2: two args + + auto info = NewRuntimeCallInfo(thread, splitter, seperatorTag, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(thisTag, limitTag); + return JSFunction::Call(info.get()); // 2: two args } } // Let S be ToString(O). @@ -1700,7 +1707,7 @@ static std::u16string ToU16String(EcmaRuntimeCallInfo *argv) JSHandle thisTag( JSTaggedValue::RequireObjectCoercible(thread, ecmascript::base::BuiltinsBase::GetThis(argv))); JSHandle thisHandle = JSTaggedValue::ToString(thread, thisTag); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return std::u16string(); } diff --git a/runtime/builtins/builtins_typedarray.cpp b/runtime/builtins/builtins_typedarray.cpp index 8479cf25b..876738a5d 100644 --- a/runtime/builtins/builtins_typedarray.cpp +++ b/runtime/builtins/builtins_typedarray.cpp @@ -182,10 +182,9 @@ JSTaggedValue BuiltinsTypedArray::From(EcmaRuntimeCallInfo *argv) vec.push_back(nextValue); } } - int32_t len = vec.size(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(len)); - JSHandle targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, arguments->GetArgv()); + uint32_t len = vec.size(); + std::array args = {JSTaggedValue(len).GetRawData()}; + JSHandle targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, args.size(), args.data()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // d. Let k be 0. // e. Repeat, while k < len @@ -203,9 +202,9 @@ JSTaggedValue BuiltinsTypedArray::From(EcmaRuntimeCallInfo *argv) tKey.Update(JSTaggedValue(k)); JSHandle kValue = vec[k]; if (mapping) { - arguments->MakeArgv(kValue, tKey); - JSTaggedValue callResult = - JSFunction::Call(thread, mapfn, thisArgHandle, 2, arguments->GetArgv()); // 2: two args + auto info = NewRuntimeCallInfo(thread, mapfn, thisArgHandle, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(kValue, tKey); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 2: two args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); mapValue.Update(callResult); } else { @@ -236,9 +235,9 @@ JSTaggedValue BuiltinsTypedArray::From(EcmaRuntimeCallInfo *argv) double len = tLen.GetNumber(); // 10. Let targetObj be ? TypedArrayCreate(C, « len »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(len)); - JSHandle targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, arguments->GetArgv()); + + std::array args = {JSTaggedValue(len).GetRawData()}; + JSHandle targetObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, args.size(), args.data()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 11. Let k be 0. // 12. Repeat, while k < len @@ -258,9 +257,9 @@ JSTaggedValue BuiltinsTypedArray::From(EcmaRuntimeCallInfo *argv) RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle mapValue; if (mapping) { - arguments->MakeArgv(kValue, tKey); - JSTaggedValue callResult = - JSFunction::Call(thread, mapfn, thisArgHandle, 2, arguments->GetArgv()); // 2: two args + auto info = NewRuntimeCallInfo(thread, mapfn, thisArgHandle, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(kValue, tKey); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 2: two args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); mapValue = JSHandle(thread, callResult); } else { @@ -291,9 +290,9 @@ JSTaggedValue BuiltinsTypedArray::Of(EcmaRuntimeCallInfo *argv) THROW_TYPE_ERROR_AND_RETURN(thread, "the this value is not a Constructor.", JSTaggedValue::Exception()); } // 5. Let newObj be TypedArrayCreate(C, « len »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(len)); - JSHandle newObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, 1, arguments->GetArgv()); + + std::array args = {JSTaggedValue(len).GetRawData()}; + JSHandle newObj = TypedArrayHelper::TypedArrayCreate(thread, thisHandle, args.size(), args.data()); // 6. ReturnIfAbrupt(newObj). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 7. Let k be 0. @@ -485,16 +484,16 @@ JSTaggedValue BuiltinsTypedArray::Every(EcmaRuntimeCallInfo *argv) // v. If testResult is false, return false. // e. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + int32_t k = 0; while (k < len) { RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSHandle kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); bool boolResult = callResult.ToBoolean(); if (!boolResult) { @@ -560,15 +559,15 @@ JSTaggedValue BuiltinsTypedArray::Filter(EcmaRuntimeCallInfo *argv) // g. Increase k by 1. int32_t captured = 0; JSMutableHandle tKey(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + for (int32_t k = 0; k < len; k++) { tKey.Update(JSTaggedValue(k)); JSHandle kKey(JSTaggedValue::ToString(thread, tKey)); JSHandle kValue = JSTaggedValue::GetProperty(thread, thisHandle, kKey).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - arguments->MakeArgv(kValue, tKey, thisHandle); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, tKey, thisHandle); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args bool testResult = callResult.ToBoolean(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); if (testResult) { @@ -577,8 +576,8 @@ JSTaggedValue BuiltinsTypedArray::Filter(EcmaRuntimeCallInfo *argv) } } // es11 9. Let A be ? TypedArraySpeciesCreate(O, « captured »). - arguments->MakeArgv(JSTaggedValue(captured)); - JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, arguments->GetArgv()); + std::array args = {JSTaggedValue(captured).GetRawData()}; + JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, args.size(), args.data()); // 15. ReturnIfAbrupt(A). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 16. Let n be 0. @@ -663,15 +662,15 @@ JSTaggedValue BuiltinsTypedArray::ForEach(EcmaRuntimeCallInfo *argv) // iv. ReturnIfAbrupt(funcResult). // e. Increase k by 1. JSMutableHandle key(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); + int32_t k = 0; while (k < len) { JSHandle kValue = JSTaggedValue::GetProperty(thread, thisObjVal, k).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); key.Update(JSTaggedValue(k)); - arguments->MakeArgv(kValue, key, thisObjVal); - JSTaggedValue funcResult = - JSFunction::Call(thread, callbackFnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackFnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisObjVal); + JSTaggedValue funcResult = JSFunction::Call(info.get()); // 3: three args RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, funcResult); k++; } @@ -862,9 +861,9 @@ JSTaggedValue BuiltinsTypedArray::Map(EcmaRuntimeCallInfo *argv) // 6. If thisArg was supplied, let T be thisArg; else let T be undefined. JSHandle thisArgHandle = GetCallArg(argv, 1); // es11 5. Let A be ? TypedArraySpeciesCreate(O, « len »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(len)); - JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, arguments->GetArgv()); + + std::array args = {JSTaggedValue(len).GetRawData()}; + JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, args.size(), args.data()); // 11. ReturnIfAbrupt(A). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -884,9 +883,9 @@ JSTaggedValue BuiltinsTypedArray::Map(EcmaRuntimeCallInfo *argv) key.Update(JSTaggedValue(k)); JSHandle kValue = JSTaggedValue::GetProperty(thread, thisHandle, key).GetValue(); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - arguments->MakeArgv(kValue, key, thisHandle); - JSTaggedValue callResult = - JSFunction::Call(thread, callbackfnHandle, thisArgHandle, 3, arguments->GetArgv()); // 3: three args + auto info = NewRuntimeCallInfo(thread, callbackfnHandle, thisArgHandle, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(kValue, key, thisHandle); + JSTaggedValue callResult = JSFunction::Call(info.get()); // 3: three args mapValue.Update(callResult); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); JSTaggedValue::SetProperty(thread, JSHandle(newArrObj), key, mapValue, true); @@ -1185,9 +1184,9 @@ JSTaggedValue BuiltinsTypedArray::Slice(EcmaRuntimeCallInfo *argv) // 11. Let count be max(final – k, 0). double count = (final - k) > 0 ? (final - k) : 0; // es11 9. Let A be ? TypedArraySpeciesCreate(O, « count »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(count)); - JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 1, arguments->GetArgv()); + + std::array args = {JSTaggedValue(count).GetRawData()}; + JSHandle newArrObj = TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, args.size(), args.data()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 17. Let srcName be the String value of O’s [[TypedArrayName]] internal slot. // 18. Let srcType be the String value of the Element Type value in Table 49 for srcName. @@ -1390,10 +1389,11 @@ JSTaggedValue BuiltinsTypedArray::Subarray(EcmaRuntimeCallInfo *argv) // 5. Let buffer be the value of O’s [[ViewedArrayBuffer]] internal slot. JSTaggedValue buffer = JSTypedArray::Cast(*thisObj)->GetViewedArrayBuffer(); // 22. Return Construct(constructor, argumentsList). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(buffer, JSTaggedValue(beginByteOffset), JSTaggedValue(new_length)); + + std::array args = {buffer.GetRawData(), JSTaggedValue(beginByteOffset).GetRawData(), + JSTaggedValue(new_length).GetRawData()}; JSHandle newArr = - TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, 3, arguments->GetArgv()); // 3: three args + TypedArrayHelper::TypedArraySpeciesCreate(thread, thisObj, args.size(), args.data()); // 3: three args RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return newArr.GetTaggedValue(); } diff --git a/runtime/builtins/builtins_weak_map.cpp b/runtime/builtins/builtins_weak_map.cpp index d47501ec3..ea8e41ece 100644 --- a/runtime/builtins/builtins_weak_map.cpp +++ b/runtime/builtins/builtins_weak_map.cpp @@ -90,7 +90,7 @@ JSTaggedValue BuiltinsWeakMap::WeakMapConstructor(EcmaRuntimeCallInfo *argv) JSHandle record( factory->NewCompletionRecord(CompletionRecord::THROW, JSHandle(typeError))); JSTaggedValue ret = JSIterator::IteratorClose(thread, iter, record).GetTaggedValue(); - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { THROW_NEW_ERROR_AND_RETURN_VALUE(thread, typeError.GetTaggedValue(), ret); }; return ret; @@ -98,26 +98,26 @@ JSTaggedValue BuiltinsWeakMap::WeakMapConstructor(EcmaRuntimeCallInfo *argv) // Let k be Get(nextItem, "0"). JSHandle key = JSObject::GetProperty(thread, nextValue, keyIndex).GetValue(); // If k is an abrupt completion, return IteratorClose(iter, k). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, key); } // Let v be Get(nextItem, "1"). JSHandle value = JSObject::GetProperty(thread, nextValue, valueIndex).GetValue(); // If v is an abrupt completion, return IteratorClose(iter, v). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, value); } // Let status be Call(adder, weakMap, «nextValue.[[value]]»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(key, value); - JSTaggedValue ret = JSFunction::Call(thread, adder, JSHandle(weakMap), 2, - arguments->GetArgv()); // 2: key and value pair + + auto info = NewRuntimeCallInfo(thread, adder, JSHandle(weakMap), JSTaggedValue::Undefined(), 2); + info->SetCallArgs(key, value); + JSTaggedValue ret = JSFunction::Call(info.get()); // 2: key and value pair status.Update(ret); // If status is an abrupt completion, return IteratorClose(iter, status). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, status); } // Let next be IteratorStep(iter). diff --git a/runtime/builtins/builtins_weak_set.cpp b/runtime/builtins/builtins_weak_set.cpp index 5f954ae69..33d44e886 100644 --- a/runtime/builtins/builtins_weak_set.cpp +++ b/runtime/builtins/builtins_weak_set.cpp @@ -83,18 +83,20 @@ JSTaggedValue BuiltinsWeakSet::WeakSetConstructor(EcmaRuntimeCallInfo *argv) JSHandle nextValue(JSIterator::IteratorValue(thread, next)); // ReturnIfAbrupt(nextValue). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, nextValue.GetTaggedValue()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(nextValue); + + auto info = NewRuntimeCallInfo(thread, adder, weakSet, JSTaggedValue::Undefined(), 1); if (nextValue->IsArray(thread)) { auto prop = JSObject::GetProperty(thread, nextValue, valueIndex).GetValue(); - arguments->MakeArgv(prop); + info->SetCallArgs(prop); + } else { + info->SetCallArgs(nextValue); } - JSTaggedValue ret = JSFunction::Call(thread, adder, JSHandle(weakSet), 1, arguments->GetArgv()); + JSTaggedValue ret = JSFunction::Call(info.get()); // Let status be Call(adder, weakset, «nextValue.[[value]]»). status.Update(ret); // If status is an abrupt completion, return IteratorClose(iter, status). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return JSIterator::IteratorCloseAndReturn(thread, iter, status); } // Let next be IteratorStep(iter). diff --git a/runtime/common.h b/runtime/common.h index 4c13fee7f..36e4b9cd0 100644 --- a/runtime/common.h +++ b/runtime/common.h @@ -17,11 +17,12 @@ #define ECMASCRIPT_COMMON_H #include "libpandabase/macros.h" +#include "plugins/ecmascript/runtime/ecma_call_params.h" namespace panda::ecmascript { enum BarrierMode { SKIP_BARRIER, WRITE_BARRIER, READ_BARRIER }; -constexpr size_t NUM_MANDATORY_JSFUNC_ARGS = 3; +static constexpr size_t NUM_MANDATORY_JSFUNC_ARGS = 3; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define PUBLIC_API PANDA_PUBLIC_API diff --git a/runtime/ecma_call_params.h b/runtime/ecma_call_params.h new file mode 100644 index 000000000..71250ab8b --- /dev/null +++ b/runtime/ecma_call_params.h @@ -0,0 +1,33 @@ +/** + * 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 PANDA_RUNTIME_ECMASCRIPT_CALL_PARAMS +#define PANDA_RUNTIME_ECMASCRIPT_CALL_PARAMS + +#include + +namespace panda::ecmascript::JSMethodArgs { +enum : uint8_t { + FUNC_IDX = 0, + NEW_TARGET_IDX = 1, + THIS_IDX = 2, + + NUM_MANDATORY_ARGS = 3, + FIRST_ARG_IDX = NUM_MANDATORY_ARGS, +}; + +} // namespace panda::ecmascript::JSMethodArgs + +#endif // PANDA_RUNTIME_ECMASCRIPT_CALL_PARAMS diff --git a/runtime/ecma_exceptions.cpp b/runtime/ecma_exceptions.cpp index b164d32a5..c81967331 100644 --- a/runtime/ecma_exceptions.cpp +++ b/runtime/ecma_exceptions.cpp @@ -24,7 +24,7 @@ namespace panda::ecmascript { void SetException(JSThread *thread, JSObject *error) { - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { thread->SetException(JSTaggedValue(error)); } } diff --git a/runtime/ecma_macros.h b/runtime/ecma_macros.h index 3e6c6ea1f..87a8141ce 100644 --- a/runtime/ecma_macros.h +++ b/runtime/ecma_macros.h @@ -88,33 +88,33 @@ static inline void UnalignedStore(T *p, T v) } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define RETURN_IF_ABRUPT_COMPLETION(thread) \ - do { \ - if (thread->HasPendingException()) { \ - return; \ - } \ +#define RETURN_IF_ABRUPT_COMPLETION(thread) \ + do { \ + if (UNLIKELY(thread->HasPendingException())) { \ + return; \ + } \ } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, value) \ do { \ - if (thread->HasPendingException()) { \ + if (UNLIKELY(thread->HasPendingException())) { \ return (value); \ } \ } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread) \ - do { \ - if (thread->HasPendingException()) { \ - return JSTaggedValue::Exception(); \ - } \ +#define RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread) \ + do { \ + if (UNLIKELY(thread->HasPendingException())) { \ + return JSTaggedValue::Exception(); \ + } \ } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define RETURN_HANDLE_IF_ABRUPT_COMPLETION(type, thread) \ do { \ - if (thread->HasPendingException()) { \ + if (UNLIKELY(thread->HasPendingException())) { \ return JSHandle(thread, JSTaggedValue::Exception()); \ } \ } while (false) @@ -125,7 +125,7 @@ static inline void UnalignedStore(T *p, T v) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define THROW_NEW_ERROR_AND_RETURN_VALUE(thread, error, value) \ do { \ - if (!thread->HasPendingException()) { \ + if (LIKELY(!thread->HasPendingException())) { \ thread->SetException(error); \ } \ return (value); \ @@ -200,12 +200,12 @@ static inline void UnalignedStore(T *p, T v) } // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define THROW_NEW_ERROR_AND_RETURN(thread, error) \ - do { \ - if (!thread->HasPendingException()) { \ - thread->SetException(error); \ - } \ - return; \ +#define THROW_NEW_ERROR_AND_RETURN(thread, error) \ + do { \ + if (LIKELY(!thread->HasPendingException())) { \ + thread->SetException(error); \ + } \ + return; \ } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) @@ -257,36 +257,36 @@ static inline void UnalignedStore(T *p, T v) } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability) \ - do { \ - const GlobalEnvConstants *globalConst = thread->GlobalConstants(); \ - if (value.GetTaggedValue().IsCompletionRecord()) { \ - JSHandle record = JSHandle::Cast(value); \ - if (record->IsThrow()) { \ - JSHandle reject(thread, capability->GetReject()); \ - JSHandle undefine = globalConst->GetHandledUndefined(); \ - InternalCallParams *arg = thread->GetInternalCallParams(); \ - arg->MakeArgv(record->GetValue()); \ - JSTaggedValue res = JSFunction::Call(thread, reject, undefine, 1, arg->GetArgv()); \ - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res); \ - return capability->GetPromise(); \ - } \ - } \ - if (thread->HasPendingException()) { \ - thread->ClearException(); \ - JSHandle reject(thread, capability->GetReject()); \ - JSHandle undefined = globalConst->GetHandledUndefined(); \ - InternalCallParams *arg = thread->GetInternalCallParams(); \ - arg->MakeArgv(value); \ - JSTaggedValue res = JSFunction::Call(thread, reject, undefined, 1, arg->GetArgv()); \ - RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res); \ - return capability->GetPromise(); \ - } \ +#define RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability) \ + do { \ + if ((value).GetTaggedValue().IsCompletionRecord()) { \ + JSHandle record = JSHandle::Cast(value); \ + if (record->IsThrow()) { \ + JSHandle reject(thread, (capability)->GetReject()); \ + auto info = \ + NewRuntimeCallInfo(thread, reject, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 1); \ + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); \ + info->SetCallArgs(record->GetValue()); \ + JSTaggedValue res = JSFunction::Call(info.get()); \ + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res); \ + return (capability)->GetPromise(); \ + } \ + } \ + if (UNLIKELY((thread)->HasPendingException())) { \ + (thread)->ClearException(); \ + JSHandle reject(thread, (capability)->GetReject()); \ + auto info = NewRuntimeCallInfo(thread, reject, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), 1); \ + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); \ + info->SetCallArgs(value.GetTaggedValue()); \ + JSTaggedValue res = JSFunction::Call(info.get()); \ + RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, res); \ + return (capability)->GetPromise(); \ + } \ } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define RETURN_REJECT_PROMISE_IF_ABRUPT_THROWN_VALUE(thread, value, capability) \ - if (thread->HasPendingException()) { \ + if (UNLIKELY(thread->HasPendingException())) { \ value = JSPromise::IfThrowGetThrowValue(thread); \ } \ RETURN_REJECT_PROMISE_IF_ABRUPT(thread, value, capability) @@ -294,7 +294,7 @@ static inline void UnalignedStore(T *p, T v) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define RETURN_COMPLETION_IF_ABRUPT(thread, value) \ do { \ - if (thread->HasPendingException()) { \ + if (UNLIKELY(thread->HasPendingException())) { \ JSHandle completionRecord = \ factory->NewCompletionRecord(CompletionRecord::THROW, value); \ return (completionRecord); \ diff --git a/runtime/ecma_runtime_call_info.h b/runtime/ecma_runtime_call_info.h index 5ca84828c..7044007c9 100644 --- a/runtime/ecma_runtime_call_info.h +++ b/runtime/ecma_runtime_call_info.h @@ -32,7 +32,7 @@ public: EcmaRuntimeCallInfo(JSThread *thread, uint32_t num_args, JSTaggedValue *args) : thread_(thread), num_args_(num_args), args_(args) { - ASSERT(num_args >= NUM_MANDATORY_JSFUNC_ARGS); + ASSERT(num_args >= JSMethodArgs::NUM_MANDATORY_ARGS); } ~EcmaRuntimeCallInfo() = default; @@ -42,46 +42,46 @@ public: return thread_; } - inline void SetNewTarget(JSTaggedValue tagged, [[maybe_unused]] int64_t tag = 0) + inline void SetNewTarget(JSTaggedValue tagged) { - SetArg(NEW_TARGET_INDEX, tagged); + SetArg(JSMethodArgs::NEW_TARGET_IDX, tagged); } - inline void SetFunction(JSTaggedValue tagged, [[maybe_unused]] int64_t tag = 0) + inline void SetFunction(JSTaggedValue tagged) { - SetArg(FUNC_INDEX, tagged); + SetArg(JSMethodArgs::FUNC_IDX, tagged); } - inline void SetThis(JSTaggedValue tagged, [[maybe_unused]] int64_t tag = 0) + inline void SetThis(JSTaggedValue tagged) { - SetArg(THIS_INDEX, tagged); + SetArg(JSMethodArgs::THIS_IDX, tagged); } - inline void SetCallArg(uint32_t idx, JSTaggedValue tagged, [[maybe_unused]] int64_t tag = 0) + inline void SetCallArg(uint32_t idx, JSTaggedValue tagged) { ASSERT_PRINT(idx < GetArgsNumber(), "Can not set values out of index range"); - SetArg(idx + FIRST_ARGS_INDEX, tagged); + SetArg(idx + JSMethodArgs::FIRST_ARG_IDX, tagged); } inline JSHandle GetFunction() const { - return GetArg(FUNC_INDEX); + return GetArg(JSMethodArgs::FUNC_IDX); } inline JSHandle GetNewTarget() const { - return GetArg(NEW_TARGET_INDEX); + return GetArg(JSMethodArgs::NEW_TARGET_IDX); } inline JSHandle GetThis() const { - return GetArg(THIS_INDEX); + return GetArg(JSMethodArgs::THIS_IDX); } inline JSHandle GetCallArg(uint32_t idx) const { ASSERT_PRINT(idx < GetArgsNumber(), "Can not set values out of index range"); - return GetArg(idx + FIRST_ARGS_INDEX); + return GetArg(idx + JSMethodArgs::FIRST_ARG_IDX); } /* @@ -90,7 +90,7 @@ public: */ inline uint32_t GetArgsNumber() const { - return num_args_ - NUM_MANDATORY_JSFUNC_ARGS; + return num_args_ - JSMethodArgs::NUM_MANDATORY_ARGS; } inline uintptr_t GetArgAddress(uint32_t idx) const @@ -100,11 +100,43 @@ public: return reinterpret_cast(&args_[idx]); } -private: + template + ALWAYS_INLINE inline void SetCallArgs(Args... args); + + inline void SetCallArg(uint32_t argc, const JSTaggedType *argv, uint32_t bias = 0) + { + for (uint32_t i = 0; i < argc; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + SetCallArg(bias + i, JSTaggedValue(argv[i])); // NOLINT(clang-analyzer-core.NullDereference) + } + } + + inline uint32_t GetInternalArgsNum() const + { + return num_args_; + } + + inline JSTaggedValue *GetInternalArgs() const + { + return args_; + } + + template + static inline JSTaggedValue UnpackIfHandle(JSHandle v) + { + return v.GetTaggedValue(); + } + static inline JSTaggedValue UnpackIfHandle(JSTaggedValue v) + { + return v; + } + DEFAULT_COPY_SEMANTIC(EcmaRuntimeCallInfo); DEFAULT_MOVE_SEMANTIC(EcmaRuntimeCallInfo); - enum ArgsIndex : uint8_t { FUNC_INDEX = 0, NEW_TARGET_INDEX, THIS_INDEX, FIRST_ARGS_INDEX }; +private: + EcmaRuntimeCallInfo() = default; + friend class ScopedCallInfo; inline void SetArg(uint32_t idx, JSTaggedValue tagged) { @@ -122,6 +154,108 @@ private: alignas(sizeof(JSTaggedType)) uint32_t num_args_ {0}; alignas(sizeof(JSTaggedType)) JSTaggedValue *args_ {nullptr}; }; + +template +ALWAYS_INLINE inline void EcmaRuntimeCallInfo::SetCallArgs(Args... args) +{ + std::array args_arr {UnpackIfHandle(args).GetRawData()...}; + SetCallArg(args_arr.size(), args_arr.data(), 0); +} + +class ScopedCallInfo { +public: + ScopedCallInfo() = default; + + ScopedCallInfo(JSThread *thread, uint32_t num_args) + { + num_args += JSMethodArgs::NUM_MANDATORY_ARGS; + auto allocator = thread->GetStackFrameAllocator(); + auto *mem = reinterpret_cast( + allocator->Alloc(AlignUp(num_args * sizeof(JSTaggedValue), GetAlignmentInBytes(DEFAULT_FRAME_ALIGNMENT)))); + LOG_IF(mem == nullptr, FATAL, ECMASCRIPT) << "Cannot allocate ScopedCallInfo frame"; + new (&cinfo_) EcmaRuntimeCallInfo(thread, num_args, mem); + AddToChain(); + } + + ~ScopedCallInfo() + { + if (cinfo_.thread_ != nullptr) { + RemoveFromChain(); + auto thread = cinfo_.thread_; + auto allocator = thread->GetStackFrameAllocator(); + allocator->Free(cinfo_.args_); + } + } + + ScopedCallInfo &operator=(ScopedCallInfo &&other) + { + auto thread = other.cinfo_.thread_; + ASSERT(this->cinfo_.thread_ == nullptr); + ASSERT(thread->scoped_call_info_ == &other); + thread->scoped_call_info_ = this; + + std::swap(this->prev_, other.prev_); + std::swap(this->cinfo_, other.cinfo_); + return *this; + } + + ScopedCallInfo(ScopedCallInfo &&other) + { + *this = std::move(other); + } + + static void IterateChain(JSThread *thread, const RootRangeVisitor &v0) + { + for (auto head = thread->scoped_call_info_; head != nullptr; head = head->prev_) { + auto *args = head->cinfo_.args_; + auto num_args = head->cinfo_.num_args_; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + v0(Root::ROOT_HANDLE, ObjectSlot(ToUintPtr(args)), ObjectSlot(ToUintPtr(args + num_args))); + } + } + + inline EcmaRuntimeCallInfo *operator->() + { + return &cinfo_; + } + + inline EcmaRuntimeCallInfo *get() + { + return &cinfo_; + } + +private: + NO_COPY_SEMANTIC(ScopedCallInfo); + + void AddToChain() + { + auto thread = cinfo_.thread_; + prev_ = thread->scoped_call_info_; + thread->scoped_call_info_ = this; + } + + void RemoveFromChain() + { + auto thread = cinfo_.thread_; + ASSERT(thread->scoped_call_info_ == this); + thread->scoped_call_info_ = prev_; + } + + EcmaRuntimeCallInfo cinfo_ {}; + ScopedCallInfo *prev_ {}; +}; + +template +static inline ScopedCallInfo NewRuntimeCallInfo(JSThread *thread, TF func, TT this_obj, TN new_target, + uint32_t num_args) +{ + ScopedCallInfo info(thread, num_args); + info->SetFunction(EcmaRuntimeCallInfo::UnpackIfHandle(func)); + info->SetThis(EcmaRuntimeCallInfo::UnpackIfHandle(this_obj)); + info->SetNewTarget(EcmaRuntimeCallInfo::UnpackIfHandle(new_target)); + return info; +} + } // namespace panda::ecmascript #endif // ECMASCRIPT_ECMA_RUNTIM_CALL_INFO_H diff --git a/runtime/ecma_vm.cpp b/runtime/ecma_vm.cpp index 1f31c8162..ad3c63b10 100644 --- a/runtime/ecma_vm.cpp +++ b/runtime/ecma_vm.cpp @@ -617,18 +617,17 @@ Expected EcmaVM::InvokeEcmaEntrypoint(const panda_file::Fil JSHandle func(thread_, resolveFunc.Value()); JSHandle global = GlobalEnv::Cast(global_env_.GetTaggedObject())->GetJSGlobalObject(); JSHandle new_target(thread_, JSTaggedValue::Undefined()); - JSHandle jsargs = factory_->NewTaggedArray(args.size()); + auto info = NewRuntimeCallInfo(thread_, func, global, new_target, args.size()); uint32_t i = 0; for (const std::string &str : args) { JSHandle strobj(factory_->NewFromStdString(str)); - jsargs->Set(thread_, i++, strobj); + info->SetCallArg(i++, strobj.GetTaggedValue()); } - InternalCallParams *params = thread_->GetInternalCallParams(); - params->MakeArgList(*jsargs); JSRuntimeOptions options = this->GetJSOptions(); - panda::ecmascript::InvokeJsFunction(thread_, func, global, new_target, params); - if (!thread_->HasPendingException()) { + InvokeJsFunction(info.get()); + + if (LIKELY(!thread_->HasPendingException())) { job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); } @@ -846,7 +845,7 @@ void EcmaVM::ClearBufferData() bool EcmaVM::ExecutePromisePendingJob() const { - if (!thread_->HasPendingException()) { + if (LIKELY(!thread_->HasPendingException())) { job::MicroJobQueue::ExecutePendingJob(thread_, GetMicroJobQueue()); return true; } diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index e2878e1dc..83ca56121 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -561,8 +561,8 @@ public: LOG_INST() << "getunmappedargs"; uint32_t actual_num_args = - this->GetFrame()->GetNumActualArgs() - NUM_MANDATORY_JSFUNC_ARGS; // not compile-time - uint32_t start_idx = this->GetFrame()->GetMethod()->GetNumVregs() + NUM_MANDATORY_JSFUNC_ARGS; + this->GetFrame()->GetNumActualArgs() - JSMethodArgs::NUM_MANDATORY_ARGS; // not compile-time + uint32_t start_idx = this->GetFrame()->GetMethod()->GetNumVregs() + JSMethodArgs::NUM_MANDATORY_ARGS; auto thread = JSThread::Cast(this->GetThread()); JSTaggedValue res = SlowRuntimeStub::GetUnmappedArgs(thread, actual_num_args, GetStkArgs(start_idx)); @@ -1906,10 +1906,10 @@ public: auto *state = this->GetFrame(); uint32_t num_vregs = state->GetMethod()->GetNumVregs(); // Exclude func, new_target and "this" - int32_t actual_num_args = state->GetNumActualArgs() - NUM_MANDATORY_JSFUNC_ARGS; + int32_t actual_num_args = state->GetNumActualArgs() - JSMethodArgs::NUM_MANDATORY_ARGS; int32_t tmp = actual_num_args - rest_idx; uint32_t rest_num_args = (tmp > 0) ? tmp : 0; - uint32_t start_idx = num_vregs + NUM_MANDATORY_JSFUNC_ARGS + rest_idx; + uint32_t start_idx = num_vregs + JSMethodArgs::NUM_MANDATORY_ARGS + rest_idx; auto thread = JSThread::Cast(this->GetThread()); JSTaggedValue res = SlowRuntimeStub::CopyRestArgs(thread, rest_num_args, GetStkArgs(start_idx)); diff --git a/runtime/interpreter/fast_runtime_stub-inl.h b/runtime/interpreter/fast_runtime_stub-inl.h index eb75b0131..ab778f90d 100644 --- a/runtime/interpreter/fast_runtime_stub-inl.h +++ b/runtime/interpreter/fast_runtime_stub-inl.h @@ -1042,9 +1042,10 @@ bool FastRuntimeStub::SetGlobalOwnProperty(JSThread *thread, JSTaggedValue recei JSHandle obj_handle(thread, receiver); JSHandle set_func(thread, setter); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(value); - JSFunction::Call(thread, set_func, obj_handle, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, set_func, obj_handle, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(value); + JSFunction::Call(info.get()); // 10. ReturnIfAbrupt(setterResult). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); return true; diff --git a/runtime/interpreter/fast_runtime_stub.h b/runtime/interpreter/fast_runtime_stub.h index af74653df..4df9f2e7b 100644 --- a/runtime/interpreter/fast_runtime_stub.h +++ b/runtime/interpreter/fast_runtime_stub.h @@ -18,7 +18,7 @@ #include #include "plugins/ecmascript/runtime/global_env_constants.h" -#include "plugins/ecmascript/runtime/js_tagged_value.h" +#include "plugins/ecmascript/runtime/js_hclass.h" namespace panda::ecmascript { class GlobalEnv; diff --git a/runtime/interpreter/interpreter-inl.h b/runtime/interpreter/interpreter-inl.h index 910a37332..4f988086b 100644 --- a/runtime/interpreter/interpreter-inl.h +++ b/runtime/interpreter/interpreter-inl.h @@ -85,20 +85,16 @@ public: } }; -JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *js_thread, JSHandle call_target, uint32_t num_args, - const JSTaggedType *args) +JSTaggedValue EcmaInterpreter::ExecuteNative(EcmaRuntimeCallInfo *info) { - return ExecuteNative(js_thread, call_target.GetTaggedValue(), num_args, - reinterpret_cast(args)); -} + JSThread *thread = info->GetThread(); + uint32_t num_args = info->GetInternalArgsNum(); + JSTaggedValue fn_object = info->GetFunction().GetTaggedValue(); -JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *js_thread, JSTaggedValue fn_object, uint32_t num_args, - const JSTaggedValue *args) -{ - ASSERT(!js_thread->HasPendingException()); + ASSERT(!thread->HasPendingException()); - Frame *current_frame = js_thread->GetCurrentFrame(); - bool is_compiled = js_thread->IsCurrentFrameCompiled(); + Frame *current_frame = thread->GetCurrentFrame(); + bool is_compiled = thread->IsCurrentFrameCompiled(); // Boundary frame expected for c2i call ASSERT(!is_compiled || StackWalker::IsBoundaryFrame(current_frame)); @@ -108,24 +104,25 @@ JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *js_thread, JSTaggedValue uint32_t num_declared_args = method->GetNumArgs(); uint32_t nregs = std::max(num_declared_args, num_args); - Frame *frame = JSFrame::CreateNativeFrame(js_thread, method, current_frame, nregs, num_args); - JSFrame::InitNativeFrameArgs(frame, num_args, args); + Frame *frame = JSFrame::CreateNativeFrame(thread, method, current_frame, nregs, num_args); + JSFrame::InitNativeFrameArgs(frame, num_args, info->GetInternalArgs()); - js_thread->SetCurrentFrameIsCompiled(false); - js_thread->SetCurrentFrame(frame); - JSTaggedValue ret_value = JSFrame::ExecuteNativeMethod(js_thread, frame, method, num_args); - ASSERT(js_thread->GetCurrentFrame() == frame); - js_thread->SetCurrentFrameIsCompiled(is_compiled); - js_thread->SetCurrentFrame(frame->GetPrevFrame()); + thread->SetCurrentFrameIsCompiled(false); + thread->SetCurrentFrame(frame); + JSTaggedValue ret_value = JSFrame::ExecuteNativeMethod(thread, frame, method, num_args); + ASSERT(thread->GetCurrentFrame() == frame); + thread->SetCurrentFrameIsCompiled(is_compiled); + thread->SetCurrentFrame(frame->GetPrevFrame()); - JSFrame::DestroyNativeFrame(js_thread, frame); + JSFrame::DestroyNativeFrame(thread, frame); return ret_value; } -JSTaggedValue EcmaInterpreter::ExecuteInvoke(JSThread *thread, JSTaggedValue fn_object, uint32_t num_args, - JSTaggedValue *args) +JSTaggedValue EcmaInterpreter::ExecuteInvoke(EcmaRuntimeCallInfo *info, JSTaggedValue fn_object) { + JSThread *thread = info->GetThread(); + ASSERT(!thread->HasPendingException()); ASSERT(fn_object.IsJSFunction()); @@ -139,22 +136,30 @@ JSTaggedValue EcmaInterpreter::ExecuteInvoke(JSThread *thread, JSTaggedValue fn_ // Set current functional object to thread so we can get it from InvokeHelper thread->SetFunctionalObject(fn_object); thread->SetInvocationLexicalEnv(js_function->GetLexicalEnv()); - TaggedValue ret_value = method->InvokeDyn(thread, num_args, args); + TaggedValue ret_value = + method->InvokeDyn(thread, info->GetInternalArgsNum(), info->GetInternalArgs()); ASSERT(thread->GetEcmascriptEnv() == prev_env); return JSTaggedValue(ret_value); } -JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, JSHandle call_target, uint32_t num_actual_args, - JSTaggedType *args) +JSTaggedValue EcmaInterpreter::ExecuteInEnv(EcmaRuntimeCallInfo *info, JSTaggedValue fn_object) { - ASSERT(JSHandle::Cast(call_target)->IsJSFunction()); + JSThread *thread = info->GetThread(); - if (UNLIKELY(thread->HasPendingException())) { + if (UNLIKELY(thread->HasPendingException())) { // TODO(vpukhov): replace with assert return JSTaggedValue::Undefined(); } - Method *method = call_target->GetCallTarget(); + if (UNLIKELY(!fn_object.IsCallable())) { // TODO(vpukhov): replace with assert + JSHandle error = + thread->GetEcmaVM()->GetFactory()->GetJSError(ErrorType::TYPE_ERROR, "is not callable"); + thread->SetException(error.GetTaggedValue()); + return JSTaggedValue::Exception(); + } + + Method *method = ECMAObject::Cast(fn_object.GetHeapObject())->GetCallTarget(); + if (method->IsNative()) { auto current_frame = thread->GetCurrentFrame(); @@ -163,20 +168,22 @@ JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, JSHandle ca thread->GetNativePc()}; // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) thread->SetCurrentFrame(reinterpret_cast(&bridge.v[1])); - JSTaggedValue ret_val = ExecuteNative(thread, call_target.GetTaggedValue(), num_actual_args, - reinterpret_cast(args)); + JSTaggedValue ret_val = ExecuteNative(info); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) ASSERT(thread->GetCurrentFrame() == reinterpret_cast(&bridge.v[1])); thread->SetCurrentFrameIsCompiled(true); thread->SetCurrentFrame(current_frame); return ret_val; } - return ExecuteNative(thread, call_target.GetTaggedValue(), num_actual_args, - reinterpret_cast(args)); + return ExecuteNative(info); } - return ExecuteInvoke(thread, call_target.GetTaggedValue(), num_actual_args, - reinterpret_cast(args)); + return ExecuteInvoke(info, fn_object); +} + +JSTaggedValue EcmaInterpreter::Execute(EcmaRuntimeCallInfo *info) +{ + return ExecuteInEnv(info, info->GetFunction().GetTaggedValue()); } JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSHandle context) diff --git a/runtime/interpreter/interpreter.h b/runtime/interpreter/interpreter.h index 1c2b9978f..62dfe5698 100644 --- a/runtime/interpreter/interpreter.h +++ b/runtime/interpreter/interpreter.h @@ -20,6 +20,7 @@ #include "plugins/ecmascript/runtime/js_tagged_value.h" #include "plugins/ecmascript/runtime/js_handle.h" #include "plugins/ecmascript/runtime/js_thread.h" +#include "plugins/ecmascript/runtime/ecma_runtime_call_info.h" namespace panda::ecmascript { class ConstantPool; @@ -28,14 +29,10 @@ class GeneratorContext; class EcmaInterpreter { public: - static inline JSTaggedValue ExecuteNative(JSThread *thread, JSTaggedValue fn_object, uint32_t num_args, - const JSTaggedValue *args); - static inline JSTaggedValue ExecuteInvoke(JSThread *thread, JSTaggedValue fn_object, uint32_t num_args, - JSTaggedValue *args); - static inline JSTaggedValue Execute(JSThread *thread, JSHandle call_target, uint32_t num_actual_args, - JSTaggedType *args); - static inline JSTaggedValue ExecuteNative(JSThread *js_thread, JSHandle call_target, uint32_t num_args, - const JSTaggedType *args); + static inline JSTaggedValue Execute(EcmaRuntimeCallInfo *info); + static inline JSTaggedValue ExecuteInEnv(EcmaRuntimeCallInfo *info, JSTaggedValue fn_object); + static inline JSTaggedValue ExecuteInvoke(EcmaRuntimeCallInfo *info, JSTaggedValue fn_object); + static inline JSTaggedValue ExecuteNative(EcmaRuntimeCallInfo *info); 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/runtime/interpreter/js_frame-inl.h b/runtime/interpreter/js_frame-inl.h index da98e01aa..6ba3e1654 100644 --- a/runtime/interpreter/js_frame-inl.h +++ b/runtime/interpreter/js_frame-inl.h @@ -53,6 +53,9 @@ inline JSTaggedValue JSFrame::ExecuteNativeMethod(JSThread *js_thread, Frame *fr uint32_t num_actual_args) { ASSERT(js_thread == JSThread::GetCurrent()); + if (UNLIKELY((!js_thread->StackOverflowCheck()))) { + return JSTaggedValue::Exception(); + } EcmaRuntimeCallInfo call_info(js_thread, num_actual_args, reinterpret_cast(&frame->GetVReg(0))); auto ecma_entry_point = reinterpret_cast(method->GetNativePointer()); diff --git a/runtime/interpreter/slow_runtime_helper.cpp b/runtime/interpreter/slow_runtime_helper.cpp index ff7f44bb1..cf7b51628 100644 --- a/runtime/interpreter/slow_runtime_helper.cpp +++ b/runtime/interpreter/slow_runtime_helper.cpp @@ -33,59 +33,59 @@ JSTaggedValue GetGlobalObject(JSThread *thread) } #endif -JSTaggedValue SlowRuntimeHelper::CallBoundFunction(JSThread *thread, JSHandle bound_func, - JSHandle obj) +JSTaggedValue SlowRuntimeHelper::CallBoundFunction(EcmaRuntimeCallInfo *info) { + JSThread *thread = info->GetThread(); + JSHandle bound_func(info->GetFunction()); JSHandle target_func(thread, bound_func->GetBoundTarget()); if (target_func->IsClassConstructor()) { THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot called without 'new'", JSTaggedValue::Exception()); } - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeBoundArgv(thread, bound_func); - JSHandle new_target(thread, JSTaggedValue::Undefined()); - return InvokeJsFunction(thread, target_func, obj, new_target, arguments); + JSHandle boundArgs(thread, bound_func->GetBoundArguments()); + const uint32_t boundLength = boundArgs->GetLength(); + const uint32_t argsLength = info->GetArgsNumber(); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + auto runtime_info = NewRuntimeCallInfo(thread, JSHandle(target_func), info->GetThis(), undefined, + boundLength + argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (boundLength != 0) { + // 0 ~ boundLength is boundArgs; boundLength ~ argsLength is args of EcmaRuntimeCallInfo. + runtime_info->SetCallArg(boundLength, boundArgs->GetData()); + } + if (argsLength != 0) { + runtime_info->SetCallArg( + argsLength, reinterpret_cast(info->GetArgAddress(JSMethodArgs::NUM_MANDATORY_ARGS)), + boundLength); + } + return EcmaInterpreter::Execute(runtime_info.get()); } -JSTaggedValue SlowRuntimeHelper::NewObject(JSThread *thread, JSHandle func, - JSHandle new_target, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) -) +JSTaggedValue SlowRuntimeHelper::NewObject(EcmaRuntimeCallInfo *info) { + JSThread *thread = info->GetThread(); + JSHandle func(info->GetFunction()); if (!func->IsHeapObject()) { THROW_TYPE_ERROR_AND_RETURN(thread, "function is nullptr", JSTaggedValue::Exception()); } if (!func->IsJSFunction()) { if (func->IsBoundFunction()) { - JSTaggedValue result = - JSBoundFunction::ConstructInternal(thread, JSHandle::Cast(func), new_target); + JSTaggedValue result = JSBoundFunction::ConstructInternal(info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; } if (func->IsJSProxy()) { - JSTaggedValue js_obj = JSProxy::ConstructInternal(thread, JSHandle(func), argc, argv, new_target); + JSTaggedValue js_obj = JSProxy::ConstructInternal(info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return js_obj; } THROW_TYPE_ERROR_AND_RETURN(thread, "Constructed NonConstructable", JSTaggedValue::Exception()); } - JSHandle js_func = JSHandle::Cast(func); - ASSERT(js_func->GetCallTarget() != nullptr); - ASSERT(JSFunction::Cast(new_target->GetTaggedObject())->GetCallTarget() != nullptr); - - if (js_func->GetCallTarget()->IsNative()) { - if (js_func->IsBuiltinsConstructor()) { - return InvokeJsFunction(thread, js_func, JSHandle(thread, JSTaggedValue::Undefined()), - new_target, thread->GetInternalCallParams()); - } - THROW_TYPE_ERROR_AND_RETURN(thread, "Constructed NonConstructable", JSTaggedValue::Exception()); - } - - JSTaggedValue result = JSFunction::ConstructInternal(thread, js_func, argc, argv, new_target); + JSTaggedValue result = JSFunction::ConstructInternal(info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; } @@ -120,49 +120,34 @@ JSTaggedValue ConstructGeneric(JSThread *thread, JSHandle ctor, JSHa } JSHandle obj(thread, JSTaggedValue::Undefined()); - if (!ctor->IsBuiltinsConstructor() && ctor->IsBase()) { + if (ctor->IsBase()) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); obj = JSHandle(factory->NewJSObjectByConstructor(ctor, new_tgt)); } + ASSERT(ctor->GetCallTarget()); + uint32_t pre_args_size = pre_args->IsUndefined() ? 0 : JSHandle::Cast(pre_args)->GetLength(); const uint32_t size = pre_args_size + args_count; - PandaVector values; - values.reserve(size); - - JSMethod *method = ctor->GetCallTarget(); - if (method == nullptr) { - THROW_TYPE_ERROR_AND_RETURN(thread, "Undefined target", JSTaggedValue::Exception()); - } - - // add default arg func - values.emplace_back(ctor.GetTaggedType()); - - // add default arg new_target, this - values.emplace_back(new_tgt.GetTaggedType()); - values.emplace_back(obj.GetTaggedType()); + auto info = NewRuntimeCallInfo(thread, ctor, obj, new_tgt, size); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // add preArgs when boundfunction is encountered + uint32_t arg_idx = 0; if (pre_args_size > 0) { JSHandle tga_pre_args = JSHandle::Cast(pre_args); for (uint32_t i = 0; i < pre_args_size; ++i) { - values.emplace_back(tga_pre_args->Get(i).GetRawData()); - } - for (ArraySizeT i = 0; i < args_count; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - values.emplace_back(stkargs[i]); - } - } else { - for (ArraySizeT i = 0; i < args_count; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - values.emplace_back(stkargs[i]); + info->SetCallArg(arg_idx++, tga_pre_args->Get(i)); } } - - JSTaggedValue result_value = - EcmaInterpreter::Execute(thread, JSHandle::Cast(ctor), values.size(), values.data()); + for (uint32_t i = 0; i < args_count; ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + info->SetCallArg(arg_idx++, JSTaggedValue(stkargs[i])); + } + JSTaggedValue result_value = EcmaInterpreter::Execute(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + // 9.3.2 [[Construct]] (argumentsList, new_target) - if (ctor->IsBuiltinsConstructor() || result_value.IsECMAObject()) { + if (result_value.IsECMAObject()) { return result_value; } @@ -238,10 +223,10 @@ JSTaggedValue ConstructProxy(JSThread *thread, JSHandle ctor, JSHandle< } // step 8 ~ 9 Call(trap, handler, «target, argArray, new_target »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(target, JSHandle(args), new_tgt); - JSTaggedValue new_obj_value = - JSFunction::Call(thread, method, handler, 3, arguments->GetArgv()); // 3: «target, argArray, new_target » + + auto info = NewRuntimeCallInfo(thread, method, handler, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(target, JSHandle(args), new_tgt); + JSTaggedValue new_obj_value = JSFunction::Call(info.get()); // 3: «target, argArray, new_target » // 10.ReturnIfAbrupt(newObj). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 11.If Type(newObj) is not Object, throw a TypeError exception. diff --git a/runtime/interpreter/slow_runtime_helper.h b/runtime/interpreter/slow_runtime_helper.h index e2c18fbf2..0a6f7d5e5 100644 --- a/runtime/interpreter/slow_runtime_helper.h +++ b/runtime/interpreter/slow_runtime_helper.h @@ -23,12 +23,9 @@ namespace panda::ecmascript { class SlowRuntimeHelper { public: - static JSTaggedValue NewObject(JSThread *thread, JSHandle func, JSHandle new_target, - uint32_t argc, const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) - ); + static JSTaggedValue NewObject(EcmaRuntimeCallInfo *info); - static JSTaggedValue CallBoundFunction(JSThread *thread, JSHandle bound_func, - JSHandle obj); + static JSTaggedValue CallBoundFunction(EcmaRuntimeCallInfo *info); static void SaveFrameToContext(JSThread *thread, JSHandle context); diff --git a/runtime/interpreter/slow_runtime_stub.cpp b/runtime/interpreter/slow_runtime_stub.cpp index 3a3e9b3d0..1e2cf8246 100644 --- a/runtime/interpreter/slow_runtime_stub.cpp +++ b/runtime/interpreter/slow_runtime_stub.cpp @@ -65,12 +65,11 @@ JSTaggedValue SlowRuntimeStub::CallSpreadDyn(JSThread *thread, JSTaggedValue fun JSHandle tagged_obj(thread, obj); JSHandle coretypes_array(thread, GetCallSpreadArgs(thread, js_array.GetTaggedValue())); - InternalCallParams *params = thread->GetInternalCallParams(); - params->MakeArgList(*coretypes_array); - JSHandle new_target(thread, JSTaggedValue::Undefined()); - JSTaggedValue res = InvokeJsFunction(thread, js_func, tagged_obj, new_target, params); - return res; + auto info = + NewRuntimeCallInfo(thread, js_func, tagged_obj, JSTaggedValue::Undefined(), coretypes_array->GetLength()); + info->SetCallArg(coretypes_array->GetLength(), coretypes_array->GetData()); + return InvokeJsFunction(info.get()); } JSTaggedValue SlowRuntimeStub::NegDyn(JSThread *thread, JSTaggedValue value) @@ -783,9 +782,9 @@ JSTaggedValue SlowRuntimeStub::AsyncFunctionResolveOrReject(JSThread *thread, JS } else { active_func = JSHandle(thread, reactions->GetRejectFunction()); } - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(value_handle); - [[maybe_unused]] JSTaggedValue res = JSFunction::Call(thread, active_func, this_arg, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, active_func, this_arg, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(value_handle); + [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return promise.GetTaggedValue(); @@ -832,25 +831,19 @@ JSTaggedValue SlowRuntimeStub::NewObjSpreadDyn(JSThread *thread, JSTaggedValue f INTERPRETER_TRACE(thread, NewobjspreadDyn); [[maybe_unused]] EcmaHandleScope handle_scope(thread); - ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - JSHandle func_handle(thread, func); - JSHandle new_target_handle(thread, new_target); JSHandle js_array(thread, array); if (!js_array->IsJSArray()) { return ThrowTypeError(thread, "Cannot Newobjspread"); } uint32_t length = JSHandle::Cast(js_array)->GetArrayLength(); - JSHandle args_array = factory->NewTaggedArray(length); + auto info = NewRuntimeCallInfo(thread, func, JSTaggedValue::Undefined(), new_target, length); for (uint32_t i = 0; i < length; ++i) { auto prop = JSTaggedValue::GetProperty(thread, js_array, i).GetValue(); - args_array->Set(thread, i, prop); + info->SetCallArg(i, prop.GetTaggedValue()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgList(*args_array); - auto tagged = SlowRuntimeHelper::NewObject(thread, func_handle, new_target_handle, length, arguments->GetArgv()); - return tagged; + return SlowRuntimeHelper::NewObject(info.get()); } void SlowRuntimeStub::ThrowTdz(JSThread *thread, JSTaggedValue bindingName) @@ -1113,7 +1106,7 @@ JSTaggedValue SlowRuntimeStub::CloseIterator(JSThread *thread, JSTaggedValue ite JSHandle iter_handle(thread, iter); JSHandle record; - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { JSHandle exception(thread, ObjectWrapper::Cast(thread->GetException().GetTaggedObject())->GetValue()); record = JSHandle(factory->NewCompletionRecord(CompletionRecord::THROW, exception)); @@ -1434,8 +1427,8 @@ JSTaggedValue SlowRuntimeStub::ClassPrivateFieldGet(JSThread *thread, JSTaggedVa THROW_TYPE_ERROR_AND_RETURN(thread, "Private field was defined without a getter", JSTaggedValue::Exception()); } - JSTaggedValue res = JSFunction::Call(thread, prop_desc.GetGetter(), obj_handle, 0, - nullptr); // TODO(vpukhov): return Exception on unwind + auto info = NewRuntimeCallInfo(thread, prop_desc.GetGetter(), obj_handle, JSTaggedValue::Undefined(), 0); + JSTaggedValue res = JSFunction::Call(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res; } @@ -1478,10 +1471,9 @@ JSTaggedValue SlowRuntimeStub::ClassPrivateFieldSet(JSThread *thread, JSTaggedVa THROW_TYPE_ERROR_AND_RETURN(thread, "Private field was defined without a setter", JSTaggedValue::Exception()); } - InternalCallParams *params = thread->GetInternalCallParams(); - params->MakeArgv(value_handle); - JSTaggedValue res = JSFunction::Call(thread, prop_desc.GetSetter(), obj_handle, 1, - params->GetArgv()); // TODO(vpukhov): return Exception on unwind + auto info = NewRuntimeCallInfo(thread, prop_desc.GetSetter(), obj_handle, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(value_handle); + JSTaggedValue res = JSFunction::Call(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res; } @@ -1704,9 +1696,8 @@ JSTaggedValue SlowRuntimeStub::GetIterator(JSThread *thread, JSTaggedValue obj, } // 4. Let iterator be ? Call(method, obj). - InternalCallParams *params = thread->GetInternalCallParams(); - params->MakeEmptyArgv(); - JSTaggedValue iterator = JSFunction::Call(thread, method_handle, obj_handle, 0, params->GetArgv()); + auto info = NewRuntimeCallInfo(thread, method_handle, obj_handle, JSTaggedValue::Undefined(), 0); + JSTaggedValue iterator = JSFunction::Call(info.get()); // 5. If Type(iterator) is not Object, throw a TypeError exception. if (!iterator.IsECMAObject()) { @@ -2115,7 +2106,9 @@ JSTaggedValue SlowRuntimeStub::SuperCall(JSThread *thread, JSTaggedValue func, J JSHandle super_func(thread, JSHandle::Cast(func_handle)->GetPrototype(thread)); ASSERT(super_func->IsJSFunction()); - JSTaggedValue result = JSFunction::Construct(thread, super_func, args_count, stkargs, new_target_handle); + auto info = NewRuntimeCallInfo(thread, super_func, JSTaggedValue::Undefined(), new_target_handle, args_count); + info->SetCallArg(args_count, stkargs); + JSTaggedValue result = JSFunction::Construct(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; @@ -2135,10 +2128,11 @@ JSTaggedValue SlowRuntimeStub::SuperCallSpread(JSThread *thread, JSTaggedValue f ASSERT(super_func->IsJSFunction()); JSHandle argv(thread, GetCallSpreadArgs(thread, js_array.GetTaggedValue())); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgList(*argv); - JSTaggedValue result = - JSFunction::Construct(thread, super_func, argv->GetLength(), arguments->GetArgv(), new_target_handle); + + auto info = + NewRuntimeCallInfo(thread, super_func, JSTaggedValue::Undefined(), new_target_handle, argv->GetLength()); + info->SetCallArg(argv->GetLength(), argv->GetData()); + JSTaggedValue result = JSFunction::Construct(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return result; diff --git a/runtime/intrinsics-inl.h b/runtime/intrinsics-inl.h index 6847b21c5..d4d6364b2 100644 --- a/runtime/intrinsics-inl.h +++ b/runtime/intrinsics-inl.h @@ -47,11 +47,8 @@ static inline JSTaggedValue GetRuntimeProfileTypeInfo(JSThread *thread) #endif template -static inline JSTaggedValue HandlerCall(JSThread *thread, JSTaggedValue fn_object, JSTaggedValue *args, - uint32_t num_args) +static inline JSTaggedValue HandlerCall(JSThread *thread, EcmaRuntimeCallInfo *info, JSTaggedValue fn_object) { - ASSERT(num_args >= 3); - if (UNLIKELY(!fn_object.IsCallable())) { JSHandle error = GetFactory(thread)->GetJSError(ErrorType::TYPE_ERROR, "is not callable"); thread->SetException(error.GetTaggedValue()); @@ -63,11 +60,10 @@ static inline JSTaggedValue HandlerCall(JSThread *thread, JSTaggedValue fn_objec // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon) if constexpr (!THIS_CALL) { - ASSERT(args[2] == JSTaggedValue::Undefined()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + ASSERT(info->GetThis().GetTaggedValue() == JSTaggedValue::Undefined()); if (fn_object.IsJSFunction() && !JSFunction::Cast(js_object)->IsStrict()) { // Set this=GlobalObject for sloppy function - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - args[2] = thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject(); + info->SetThis(thread->GetEcmaVM()->GetGlobalEnv()->GetGlobalObject()); } } @@ -77,7 +73,7 @@ static inline JSTaggedValue HandlerCall(JSThread *thread, JSTaggedValue fn_objec LOG(DEBUG, INTERPRETER) << "Native function"; LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call."; - JSTaggedValue ret_value = EcmaInterpreter::ExecuteNative(thread, fn_object, num_args, args); + JSTaggedValue ret_value = EcmaInterpreter::ExecuteNative(info); if (UNLIKELY(thread->HasPendingException())) { return JSTaggedValue::Exception(); } @@ -94,7 +90,7 @@ static inline JSTaggedValue HandlerCall(JSThread *thread, JSTaggedValue fn_objec } LOG(DEBUG, INTERPRETER) << "Method name: " << method->GetName().data; - JSTaggedValue ret_value = EcmaInterpreter::ExecuteInvoke(thread, fn_object, num_args, args); + JSTaggedValue ret_value = EcmaInterpreter::ExecuteInvoke(info, fn_object); if (UNLIKELY(thread->HasPendingException())) { return JSTaggedValue::Exception(); @@ -618,8 +614,8 @@ INLINE_ECMA_INTRINSICS uint64_t GetUnmappedArgs([[maybe_unused]] JSThread *threa INLINE_ECMA_INTRINSICS uint64_t GetUnmappedArgsInterp(JSThread *thread) { ASSERT(!thread->IsCurrentFrameCompiled()); - uint32_t actual_num_args = thread->GetCurrentFrame()->GetNumActualArgs() - NUM_MANDATORY_JSFUNC_ARGS; - uint32_t start_idx = thread->GetCurrentFrame()->GetMethod()->GetNumVregs() + NUM_MANDATORY_JSFUNC_ARGS; + uint32_t actual_num_args = thread->GetCurrentFrame()->GetNumActualArgs() - JSMethodArgs::NUM_MANDATORY_ARGS; + uint32_t start_idx = thread->GetCurrentFrame()->GetMethod()->GetNumVregs() + JSMethodArgs::NUM_MANDATORY_ARGS; auto args = reinterpret_cast(&thread->GetCurrentFrame()->GetVReg(start_idx)); return SlowRuntimeStub::GetUnmappedArgs(thread, actual_num_args, reinterpret_cast(args)) .GetRawData(); @@ -711,10 +707,10 @@ INLINE_ECMA_INTRINSICS uint64_t CopyrestargsInterp(JSThread *thread, uint16_t in ASSERT(!thread->IsCurrentFrameCompiled()); auto *frame = thread->GetCurrentFrame(); uint32_t num_vregs = frame->GetMethod()->GetNumVregs(); - int32_t actual_num_args = frame->GetNumActualArgs() - NUM_MANDATORY_JSFUNC_ARGS; + int32_t actual_num_args = frame->GetNumActualArgs() - JSMethodArgs::NUM_MANDATORY_ARGS; int32_t tmp = actual_num_args - index; uint32_t rest_num_args = (tmp > 0) ? tmp : 0; - uint32_t start_idx = num_vregs + NUM_MANDATORY_JSFUNC_ARGS + index; + uint32_t start_idx = num_vregs + JSMethodArgs::NUM_MANDATORY_ARGS + index; auto args = reinterpret_cast(&thread->GetCurrentFrame()->GetVReg(start_idx)); @@ -742,7 +738,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call0Dyn(JSThread *thread, uint64_t raw_fn_objec JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -754,7 +751,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call1Dyn(JSThread *thread, uint64_t raw_fn_objec JSTaggedValue::Undefined(), JSTaggedValue(raw_a0), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -764,7 +762,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call2Dyn(JSThread *thread, uint64_t raw_fn_objec JSTaggedValue(raw_fn_object), JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), JSTaggedValue(raw_a0), JSTaggedValue(raw_a1), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -775,7 +774,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call3Dyn(JSThread *thread, uint64_t raw_fn_objec JSTaggedValue(raw_fn_object), JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), JSTaggedValue(raw_a0), JSTaggedValue(raw_a1), JSTaggedValue(raw_a2), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // Just declared here, not used @@ -794,7 +794,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call0ThisDyn(JSThread *thread, uint64_t raw_fn_o JSTaggedValue::Undefined(), JSTaggedValue(raw_this), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -807,7 +808,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call1ThisDyn(JSThread *thread, uint64_t raw_fn_o JSTaggedValue(raw_this), JSTaggedValue(raw_a0), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -818,7 +820,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call2ThisDyn(JSThread *thread, uint64_t raw_fn_o JSTaggedValue(raw_fn_object), JSTaggedValue::Undefined(), JSTaggedValue(raw_this), JSTaggedValue(raw_a0), JSTaggedValue(raw_a1), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) @@ -829,7 +832,8 @@ INLINE_ECMA_INTRINSICS uint64_t Call3ThisDyn(JSThread *thread, uint64_t raw_fn_o JSTaggedValue(raw_fn_object), JSTaggedValue::Undefined(), JSTaggedValue(raw_this), JSTaggedValue(raw_a0), JSTaggedValue(raw_a1), JSTaggedValue(raw_a2), }; - return HandlerCall(thread, JSTaggedValue(raw_fn_object), args.data(), args.size()).GetRawData(); + EcmaRuntimeCallInfo info(thread, args.size(), args.data()); + return HandlerCall(thread, &info, JSTaggedValue(raw_fn_object)).GetRawData(); } // Just declared here, not used @@ -837,36 +841,34 @@ INLINE_ECMA_INTRINSICS uint64_t Call3ThisDyn(JSThread *thread, uint64_t raw_fn_o INLINE_ECMA_INTRINSICS uint64_t CalliRangeDynInterp(JSThread *thread, uint16_t args_num, uint64_t args_ptr) { auto args = reinterpret_cast(args_ptr); - thread_local std::vector args_vec; - const size_t actual_num_args = args_num + NUM_MANDATORY_JSFUNC_ARGS; - args_vec.reserve(actual_num_args); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - auto fn_object = args[0]; - args_vec = {fn_object, JSTaggedValue::Undefined(), JSTaggedValue::Undefined()}; - for (int i(0); i < args_num; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - args_vec[i + NUM_MANDATORY_JSFUNC_ARGS] = args[i + 1]; + auto fn_obj = args[0]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto *fn_args = &args[1]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + + // TODO(vpukhov): copy in-place + auto info = NewRuntimeCallInfo(thread, fn_obj, JSTaggedValue::Undefined(), JSTaggedValue::Undefined(), args_num); + for (size_t i = 0; i < args_num; ++i) { + info->SetCallArg(i, fn_args[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } - return HandlerCall(thread, fn_object, args_vec.data(), actual_num_args).GetRawData(); + return HandlerCall(thread, info.get(), fn_obj).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) INLINE_ECMA_INTRINSICS uint64_t CalliThisRangeDyn(JSThread *thread, uint16_t args_num, uint64_t args_ptr) { auto args = reinterpret_cast(args_ptr); - thread_local std::vector args_vec; - const size_t actual_num_args = args_num + NUM_MANDATORY_JSFUNC_ARGS - 1; - args_vec.reserve(actual_num_args); - auto fn_object = args[0]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - args_vec = {fn_object, JSTaggedValue::Undefined(), args[1]}; - for (int i(0); i < args_num - 1; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - args_vec[i + NUM_MANDATORY_JSFUNC_ARGS] = args[i + 2]; + auto fn_obj = args[0]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto this_obj = args[1]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto *fn_args = &args[2U]; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + args_num--; + + // TODO(vpukhov): copy in-place + auto info = NewRuntimeCallInfo(thread, fn_obj, this_obj, JSTaggedValue::Undefined(), args_num); + for (size_t i = 0; i < args_num; ++i) { + info->SetCallArg(i, fn_args[i]); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) } - return HandlerCall(thread, fn_object, args_vec.data(), actual_num_args).GetRawData(); + return HandlerCall(thread, info.get(), fn_obj).GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) diff --git a/runtime/jobs/micro_job_queue.cpp b/runtime/jobs/micro_job_queue.cpp index 620905c1f..8051f6317 100644 --- a/runtime/jobs/micro_job_queue.cpp +++ b/runtime/jobs/micro_job_queue.cpp @@ -61,7 +61,7 @@ void MicroJobQueue::ExecutePendingJob(JSThread *thread, JSHandle pendingJob.Update(promiseQueue->Pop(thread)); LOG_ECMA(DEBUG) << "promiseQueue end length: " << promiseQueue->Size(); PendingJob::ExecutePendingJob(pendingJob, thread); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return; } promiseQueue.Update(jobQueue->GetPromiseJobQueue()); @@ -71,7 +71,7 @@ void MicroJobQueue::ExecutePendingJob(JSThread *thread, JSHandle while (!scriptQueue->Empty()) { pendingJob.Update(scriptQueue->Pop(thread)); PendingJob::ExecutePendingJob(pendingJob, thread); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return; } } diff --git a/runtime/jobs/pending_job.h b/runtime/jobs/pending_job.h index b6e8af611..6314a01fa 100644 --- a/runtime/jobs/pending_job.h +++ b/runtime/jobs/pending_job.h @@ -39,9 +39,9 @@ public: ASSERT(job->IsCallable()); JSHandle thisValue(thread, JSTaggedValue::Undefined()); JSHandle argv(thread, pendingJob->GetArguments()); - InternalCallParams *args = thread->GetInternalCallParams(); - args->MakeArgList(*argv); - return JSFunction::Call(thread, job, thisValue, argv->GetLength(), args->GetArgv()); + auto info = NewRuntimeCallInfo(thread, job, thisValue, JSTaggedValue::Undefined(), argv->GetLength()); + info->SetCallArg(argv->GetLength(), argv->GetData()); + return JSFunction::Call(info.get()); } ACCESSORS_BASE(Record) diff --git a/runtime/js_array.cpp b/runtime/js_array.cpp index 2282a185e..012b3d6ad 100644 --- a/runtime/js_array.cpp +++ b/runtime/js_array.cpp @@ -157,9 +157,10 @@ JSTaggedValue JSArray::ArraySpeciesCreate(JSThread *thread, const JSHandle new_target(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(array_length)); - JSTaggedValue result = JSFunction::Construct(thread, constructor, 1, arguments->GetArgv(), new_target); + + auto info = NewRuntimeCallInfo(thread, constructor, JSTaggedValue::Undefined(), new_target, 1); + info->SetCallArgs(JSTaggedValue(array_length)); + JSTaggedValue result = JSFunction::Construct(info.get()); // NOTEIf original_array was created using the standard built-in Array constructor for // a Realm that is not the Realm of the running execution context, then a new Array is diff --git a/runtime/js_async_generator_object.cpp b/runtime/js_async_generator_object.cpp index c41b895af..f4bfd8ac3 100644 --- a/runtime/js_async_generator_object.cpp +++ b/runtime/js_async_generator_object.cpp @@ -96,10 +96,11 @@ JSHandle JSAsyncGeneratorObject::AsyncGeneratorResolve(JSThread * // 8. Perform ! Call(promiseCapability.[[Resolve]], undefined, « iteratorResult »). JSHandle thisArg = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(iteratorResult); + JSHandle resolve(thread, promiseCapability->GetResolve()); - [[maybe_unused]] JSTaggedValue res = JSFunction::Call(thread, resolve, thisArg, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, resolve, thisArg, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(iteratorResult); + [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info.get()); // 9. Perform ! AsyncGeneratorResumeNext(generator). JSAsyncGeneratorObject::AsyncGeneratorResumeNext(thread, generator); @@ -140,10 +141,11 @@ JSHandle JSAsyncGeneratorObject::AsyncGeneratorReject(JSThread *t // 7. Perform ! Call(promiseCapability.[[Reject]], undefined, « exception »). JSHandle thisArg = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(exception); + JSHandle reject(thread, promiseCapability->GetReject()); - [[maybe_unused]] JSTaggedValue res = JSFunction::Call(thread, reject, thisArg, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, reject, thisArg, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(exception); + [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info.get()); // 9. Perform ! AsyncGeneratorResumeNext(generator). JSAsyncGeneratorObject::AsyncGeneratorResumeNext(thread, generator); @@ -320,7 +322,7 @@ JSHandle JSAsyncGeneratorObject::AsyncGeneratorEnqueue(JSThread * [[maybe_unused]] JSTaggedValue check = AsyncGeneratorValidate(thread, generator); // 3. If check is an abrupt completion, then - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { // a. Let badGeneratorError be a newly created TypeError object. JSTaggedValue badGeneratorError = thread->GetException(); thread->ClearException(); @@ -328,11 +330,10 @@ JSHandle JSAsyncGeneratorObject::AsyncGeneratorEnqueue(JSThread * // b. Perform ! Call(promiseCapability.[[Reject]], undefined, « badGeneratorError »). const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle thisArg = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(badGeneratorError); JSHandle reject(thread, promiseCapability->GetReject()); - [[maybe_unused]] JSTaggedValue res = JSFunction::Call(thread, reject, thisArg, 1, arguments->GetArgv()); - + auto info = NewRuntimeCallInfo(thread, reject, thisArg, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(badGeneratorError); + [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info.get()); // c. Return promiseCapability.[[Promise]]. return JSHandle(thread, promiseCapability->GetPromise()); } diff --git a/runtime/js_eval.cpp b/runtime/js_eval.cpp index 5b2817a90..9db28f3fa 100644 --- a/runtime/js_eval.cpp +++ b/runtime/js_eval.cpp @@ -91,12 +91,11 @@ JSTaggedValue EvalUtils::DirectEval(JSThread *thread, uint32_t parserStatus, JST JSHandle thisValue = JSArray::FastGetPropertyByValue(thread, evalBindingsHandle, index++); JSHandle lexicalContext = JSArray::FastGetPropertyByValue(thread, evalBindingsHandle, index++); - constexpr auto paramsCount = NUM_MANDATORY_JSFUNC_ARGS + 1; - ASSERT(paramsCount == index); - std::array params = {paramFunc.GetTaggedType(), newTarget.GetTaggedType(), - thisValue.GetTaggedType(), lexicalContext.GetTaggedType()}; + ASSERT(1 == index - JSMethodArgs::NUM_MANDATORY_ARGS); + auto info = NewRuntimeCallInfo(thread, paramFunc, thisValue, newTarget, 1); + info->SetCallArgs(lexicalContext); - auto res = EcmaInterpreter::Execute(thread, JSHandle::Cast(func), params.size(), params.data()); + auto res = EcmaInterpreter::ExecuteInEnv(info.get(), func.GetTaggedValue()); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); return res; } @@ -114,11 +113,8 @@ JSTaggedValue EvalUtils::Eval(JSThread *thread, const JSHandle &a RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, func.GetTaggedValue()); JSHandle thisValue(thread, thread->GetGlobalObject()); - - std::array params = { - func.GetTaggedType(), JSTaggedValue::Undefined().GetRawData(), thisValue.GetTaggedType()}; - - return EcmaInterpreter::Execute(thread, JSHandle::Cast(func), params.size(), params.data()); + auto info = NewRuntimeCallInfo(thread, func, thisValue, JSTaggedValue::Undefined(), 0); + return EcmaInterpreter::Execute(info.get()); } JSTaggedValue EvalUtils::CreateDynamicFunction(EcmaRuntimeCallInfo *argv, DynamicFunctionKind kind) @@ -204,11 +200,8 @@ JSTaggedValue EvalUtils::CreateDynamicFunction(EcmaRuntimeCallInfo *argv, Dynami JSHandle thisValue(thread, thread->GetGlobalObject()); - std::array params = { - func.GetTaggedType(), JSTaggedValue::Undefined().GetRawData(), thisValue.GetTaggedType()}; - - JSHandle res( - thread, EcmaInterpreter::Execute(thread, JSHandle::Cast(func), params.size(), params.data())); + auto info = NewRuntimeCallInfo(thread, func, thisValue, JSTaggedValue::Undefined(), 0); + JSHandle res(thread, EcmaInterpreter::Execute(info.get())); ASSERT(res->IsCallable()); diff --git a/runtime/js_finalization_registry.cpp b/runtime/js_finalization_registry.cpp index 3f6c186a9..8221b6dc0 100644 --- a/runtime/js_finalization_registry.cpp +++ b/runtime/js_finalization_registry.cpp @@ -128,10 +128,12 @@ void JSFinalizationRegistry::CallCleanupCallback(JSThread *thread, JSHandleSetToken(thread, i, JSTaggedValue::Hole()); if (arg->IsHole()) { - JSFunction::Call(thread, JSHandle(callback), global, 0U, nullptr); + auto info = NewRuntimeCallInfo(thread, callback, global, JSTaggedValue::Undefined(), 0); + JSFunction::Call(info.get()); } else { - JSTaggedType raw_arg = arg.GetTaggedValue().GetRawData(); - JSFunction::Call(thread, JSHandle(callback), global, 1U, &raw_arg); + auto info = NewRuntimeCallInfo(thread, callback, global, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(arg); + JSFunction::Call(info.get()); } } } diff --git a/runtime/js_function.cpp b/runtime/js_function.cpp index 2d6b0c125..d9cfaf6f2 100644 --- a/runtime/js_function.cpp +++ b/runtime/js_function.cpp @@ -253,136 +253,86 @@ bool JSFunction::MakeConstructor(JSThread *thread, const JSHandle &f return status; } -JSTaggedValue JSFunction::Call(JSThread *thread, const JSHandle &func, - const JSHandle &this_arg, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) -) +JSTaggedValue JSFunction::Call(EcmaRuntimeCallInfo *info) { + JSThread *thread = info->GetThread(); // 1. ReturnIfAbrupt(F). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + JSHandle func = info->GetFunction(); // 2. If argumentsList was not passed, let argumentsList be a new empty List. // 3. If IsCallable(F) is false, throw a TypeError exception. if (!func->IsCallable()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Callable is false", JSTaggedValue::Exception()); } - if (func->IsJSFunction()) { - return JSFunction::CallInternal(thread, JSHandle(func), this_arg, argc, argv); - } - - if (func->IsBoundFunction()) { - return JSBoundFunction::CallInternal(thread, JSHandle(func)); - } - - if (func->IsJSProxy()) { - return JSProxy::CallInternal(thread, JSHandle(func), this_arg, argc, argv); + auto *jshclass = func->GetTaggedObject()->GetClass(); + if (jshclass->IsClassConstructor()) { + THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception()); } - - THROW_TYPE_ERROR_AND_RETURN(thread, "Call NonCallable", JSTaggedValue::Exception()); + return EcmaInterpreter::Execute(info); } -JSTaggedValue JSFunction::Construct(JSThread *thread, const JSHandle &func, uint32_t argc, - const JSTaggedType argv[], // NOLINT(modernize-avoid-c-arrays) - const JSHandle &new_target) +JSTaggedValue JSFunction::Construct(EcmaRuntimeCallInfo *info) { - JSMutableHandle target(thread, new_target.GetTaggedValue()); + JSThread *thread = info->GetThread(); + JSHandle func(info->GetFunction()); + JSMutableHandle target(info->GetNewTarget()); + if (target->IsUndefined()) { target.Update(func.GetTaggedValue()); + info->SetNewTarget(target.GetTaggedValue()); } if (!(func->IsConstructor() && target->IsConstructor())) { THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception()); } if (func->IsJSFunction()) { - return JSFunction::ConstructInternal(thread, JSHandle(func), argc, argv, target); - } - if (func->IsBoundFunction()) { - return JSBoundFunction::ConstructInternal(thread, JSHandle(func), target); + return JSFunction::ConstructInternal(info); } if (func->IsJSProxy()) { - return JSProxy::ConstructInternal(thread, JSHandle(func), argc, argv, target); + return JSProxy::ConstructInternal(info); } - THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor NonConstructor", JSTaggedValue::Exception()); + ASSERT(func->IsBoundFunction()); + return JSBoundFunction::ConstructInternal(info); } -JSTaggedValue JSFunction::Invoke(JSThread *thread, const JSHandle &this_arg, - const JSHandle &key, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) -) +JSTaggedValue JSFunction::Invoke(EcmaRuntimeCallInfo *info, const JSHandle &key) { ASSERT(JSTaggedValue::IsPropertyKey(key)); - JSHandle func(JSTaggedValue::GetProperty(thread, this_arg, key).GetValue()); - return JSFunction::Call(thread, func, this_arg, argc, argv); + JSThread *thread = info->GetThread(); + JSHandle thisArg = info->GetThis(); + JSHandle func(JSTaggedValue::GetProperty(thread, thisArg, key).GetValue()); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + info->SetFunction(func.GetTaggedValue()); + return JSFunction::Call(info); } -// [[Call]] -JSTaggedValue JSFunction::CallInternal(JSThread *thread, const JSHandle &func, - const JSHandle &this_arg, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) -) +// [[Construct]] +JSTaggedValue JSFunction::ConstructInternal(EcmaRuntimeCallInfo *info) { - if (!func->IsBuiltinsConstructor() && func->IsClassConstructor()) { - THROW_TYPE_ERROR_AND_RETURN(thread, "class constructor cannot call", JSTaggedValue::Exception()); + if (info == nullptr) { + return JSTaggedValue::Exception(); } - constexpr uint32_t firstArgIndex = 3; - const ArraySizeT size = argc + firstArgIndex; - thread_local std::vector values; - values.reserve(size); - values.clear(); - - [[maybe_unused]] Method *target = func->GetCallTarget(); - ASSERT(target != nullptr); - - values.emplace_back(func.GetTaggedType()); - values.emplace_back(JSTaggedValue::VALUE_UNDEFINED); - values.emplace_back(this_arg.GetTaggedType()); - - for (ArraySizeT i = 0; i < argc; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - values.emplace_back(argv[i]); - } - - return EcmaInterpreter::Execute(thread, JSHandle::Cast(func), values.size(), values.data()); -} - -// [[Construct]] -JSTaggedValue JSFunction::ConstructInternal(JSThread *thread, const JSHandle &func, uint32_t argc, - const JSTaggedType argv[], // NOLINT(modernize-avoid-c-arrays) - const JSHandle &new_target) -{ - ASSERT(new_target->IsECMAObject()); + JSThread *thread = info->GetThread(); + JSHandle func(info->GetFunction()); + JSHandle newTarget(info->GetNewTarget()); + ASSERT(newTarget->IsECMAObject()); if (!func->IsConstructor()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor is false", JSTaggedValue::Exception()); } JSHandle obj(thread, JSTaggedValue::Undefined()); - if (!func->IsBuiltinsConstructor() && func->IsBase()) { + if (func->IsBase()) { ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); - obj = JSHandle(factory->NewJSObjectByConstructor(func, new_target)); - } - - constexpr uint32_t firstArgIndex = 3; - const ArraySizeT size = argc + firstArgIndex; - thread_local std::vector values; - values.reserve(size); - values.clear(); - - ASSERT(func->GetCallTarget() != nullptr); - - values.emplace_back(func.GetTaggedType()); - values.emplace_back(new_target.GetTaggedType()); - values.emplace_back(obj.GetTaggedType()); - - for (ArraySizeT i = 0; i < argc; ++i) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - values.emplace_back(argv[i]); + obj = JSHandle(factory->NewJSObjectByConstructor(func, newTarget)); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); } - JSTaggedValue resultValue = - EcmaInterpreter::Execute(thread, JSHandle::Cast(func), values.size(), values.data()); + info->SetThis(obj.GetTaggedValue()); + JSTaggedValue resultValue = EcmaInterpreter::Execute(info); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); - // 9.3.2 [[Construct]] (argumentsList, new_target) - if (func->IsBuiltinsConstructor() || resultValue.IsECMAObject()) { + // 9.3.2 [[Construct]] (argumentsList, newTarget) + if (resultValue.IsECMAObject()) { return resultValue; } @@ -467,29 +417,34 @@ bool JSFunction::SetFunctionLength(JSThread *thread, const JSHandle return JSTaggedValue::DefinePropertyOrThrow(thread, funcHandle, lengthKeyHandle, lengthDesc); } -JSTaggedValue JSBoundFunction::CallInternal(JSThread *thread, const JSHandle &func) -{ - JSHandle target(thread, func->GetBoundTarget()); - JSHandle bound_this(thread, func->GetBoundThis()); - - InternalCallParams *params = thread->GetInternalCallParams(); - params->MakeBoundArgv(thread, func); - return JSFunction::Call(thread, target, bound_this, params->GetLength(), params->GetArgv()); -} - // 9.4.1.2[[Construct]](argumentsList, new_target) -JSTaggedValue JSBoundFunction::ConstructInternal(JSThread *thread, const JSHandle &func, - const JSHandle &new_target) +JSTaggedValue JSBoundFunction::ConstructInternal(EcmaRuntimeCallInfo *info) { + JSThread *thread = info->GetThread(); + JSHandle func(info->GetFunction()); JSHandle target(thread, func->GetBoundTarget()); ASSERT(target->IsConstructor()); + JSHandle new_target = info->GetNewTarget(); JSMutableHandle newTargetMutable(thread, new_target.GetTaggedValue()); if (JSTaggedValue::SameValue(func.GetTaggedValue(), new_target.GetTaggedValue())) { newTargetMutable.Update(target.GetTaggedValue()); } - InternalCallParams *params = thread->GetInternalCallParams(); - params->MakeBoundArgv(thread, func); - return JSFunction::Construct(thread, target, params->GetLength(), params->GetArgv(), newTargetMutable); + + JSHandle boundArgs(thread, func->GetBoundArguments()); + const uint32_t boundLength = boundArgs->GetLength(); + const uint32_t argsLength = info->GetArgsNumber(); + JSHandle undefined = thread->GlobalConstants()->GetHandledUndefined(); + auto runtime_info = NewRuntimeCallInfo(thread, target, undefined, newTargetMutable, boundLength + argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (boundLength != 0) { + runtime_info->SetCallArg(boundLength, boundArgs->GetData()); + } + if (argsLength != 0) { + runtime_info->SetCallArg( + argsLength, reinterpret_cast(info->GetArgAddress(JSMethodArgs::NUM_MANDATORY_ARGS)), + boundLength); + } + return JSFunction::Construct(runtime_info.get()); } void JSProxyRevocFunction::ProxyRevocFunctions(const JSThread *thread, const JSHandle &revoker) diff --git a/runtime/js_function.h b/runtime/js_function.h index 2ad1d11c3..eb977f082 100644 --- a/runtime/js_function.h +++ b/runtime/js_function.h @@ -74,29 +74,11 @@ public: // ecma6 9.2 // 7.3.12 Call(F, V, argumentsList) - static JSTaggedValue Call(JSThread *thread, const JSHandle &func, - const JSHandle &this_arg, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) - ); - - static JSTaggedValue Construct(JSThread *thread, const JSHandle &func, uint32_t argc, - const JSTaggedType argv[], // NOLINT(modernize-avoid-c-arrays) - const JSHandle &new_target); - static JSTaggedValue Invoke(JSThread *thread, const JSHandle &this_arg, - const JSHandle &key, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) - ); - // 9.2.1[[Call]](thisArgument, argumentsList) - // 9.3.1[[Call]](thisArgument, argumentsList) - static JSTaggedValue CallInternal(JSThread *thread, const JSHandle &func, - const JSHandle &this_arg, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) - ); - // 9.2.2[[Construct]](argumentsList, new_target) - // 9.3.2[[Construct]](argumentsList, new_target) - static JSTaggedValue ConstructInternal(JSThread *thread, const JSHandle &func, uint32_t argc, - const JSTaggedType argv[], // NOLINT(modernize-avoid-c-arrays) - const JSHandle &new_target); + static JSTaggedValue Call(EcmaRuntimeCallInfo *info); + static JSTaggedValue Invoke(EcmaRuntimeCallInfo *info, const JSHandle &key); + + static JSTaggedValue Construct(EcmaRuntimeCallInfo *info); + static JSTaggedValue ConstructInternal(EcmaRuntimeCallInfo *info); static bool AddRestrictedFunctionProperties(const JSHandle &func, const JSHandle &realm); static bool MakeConstructor(JSThread *thread, const JSHandle &func, @@ -241,22 +223,27 @@ public: inline static bool IsConstructorKind(FunctionKind kind) { - return (kind >= BUILTIN_PROXY_CONSTRUCTOR) && (kind <= DERIVED_CONSTRUCTOR); + return (kind >= FunctionKind::BASE_CONSTRUCTOR) && (kind <= FunctionKind::DERIVED_CONSTRUCTOR); } - inline static bool IsBuiltinConstructor(FunctionKind kind) + inline bool IsBuiltinConstructor() { - return kind >= BUILTIN_PROXY_CONSTRUCTOR && kind <= BUILTIN_CONSTRUCTOR; + FunctionKind kind = GetFunctionKind(); + return kind >= FunctionKind::BUILTIN_PROXY_CONSTRUCTOR && kind <= FunctionKind::BUILTIN_CONSTRUCTOR; } inline static bool HasPrototype(FunctionKind kind) { - return kind >= BUILTIN_CONSTRUCTOR && kind <= ASYNC_GENERATOR_FUNCTION; + return (kind >= FunctionKind::BASE_CONSTRUCTOR) && (kind <= FunctionKind::ASYNC_GENERATOR_FUNCTION) && + (kind != FunctionKind::BUILTIN_PROXY_CONSTRUCTOR); } inline static bool HasAccessor(FunctionKind kind) { - return kind <= ASYNC_FUNCTION; +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wtype-limits" + return kind >= FunctionKind::NORMAL_FUNCTION && kind <= FunctionKind::ASYNC_FUNCTION; +#pragma GCC diagnostic pop } inline bool IsClassConstructor() const @@ -345,12 +332,8 @@ class JSBoundFunction : public JSFunctionBase { public: CAST_CHECK(JSBoundFunction, IsBoundFunction); - // 9.4.1.1[[Call]](thisArgument, argumentsList) - static JSTaggedValue CallInternal(JSThread *thread, const JSHandle &func); - // 9.4.1.2[[Construct]](argumentsList, new_target) - static JSTaggedValue ConstructInternal(JSThread *thread, const JSHandle &func, - const JSHandle &new_target); + static JSTaggedValue ConstructInternal(EcmaRuntimeCallInfo *info); ACCESSORS_BASE(JSFunctionBase) ACCESSORS(0, BoundTarget) diff --git a/runtime/js_function_kind.h b/runtime/js_function_kind.h index dc34067e2..b1eae5cb5 100644 --- a/runtime/js_function_kind.h +++ b/runtime/js_function_kind.h @@ -21,6 +21,10 @@ namespace panda::ecmascript { enum FunctionKind : uint8_t { NORMAL_FUNCTION = 0, + // BEGIN accessors + GETTER_FUNCTION, + SETTER_FUNCTION, + // END accessors // BEGIN arrow functions ARROW_FUNCTION, // BEGIN async functions @@ -28,28 +32,23 @@ enum FunctionKind : uint8_t { // END arrow functions ASYNC_FUNCTION, // END async functions - // BEGIN constructable functions - BUILTIN_PROXY_CONSTRUCTOR, - BUILTIN_CONSTRUCTOR, // BEGIN base constructors BASE_CONSTRUCTOR, // BEGIN default constructors DEFAULT_BASE_CONSTRUCTOR, - // END base constructors // BEGIN class constructors CLASS_CONSTRUCTOR, + // END base constructors + // BEGIN constructable functions + BUILTIN_PROXY_CONSTRUCTOR, + BUILTIN_CONSTRUCTOR, // END default constructors DERIVED_CONSTRUCTOR, // END class constructors GENERATOR_FUNCTION, - ASYNC_GENERATOR_FUNCTION, // END generators // END constructable functions. - - // BEGIN accessors - GETTER_FUNCTION, - SETTER_FUNCTION, - // END accessors + ASYNC_GENERATOR_FUNCTION, LAST_FUNCTION_KIND, }; diff --git a/runtime/js_hclass.h b/runtime/js_hclass.h index 46fc33e0d..016c1a064 100644 --- a/runtime/js_hclass.h +++ b/runtime/js_hclass.h @@ -788,11 +788,6 @@ public: return ConstructorBit::Decode(bits); } - inline bool IsBuiltinsCtor() const - { - return hclass_.IsBuiltinsConstructor(); - } - inline bool IsExtensible() const { uint32_t bits = GetBitField(); diff --git a/runtime/js_invoker.cpp b/runtime/js_invoker.cpp index b2cf6f196..8dac2ff89 100644 --- a/runtime/js_invoker.cpp +++ b/runtime/js_invoker.cpp @@ -53,35 +53,23 @@ extern "C" uint64_t InvokeBuiltin(JSThread *thread, Method *method, uint32_t num ASSERT(method->GetNativePointer() != nullptr); + if (UNLIKELY((!thread->StackOverflowCheck()))) { + return JSTaggedValue::Exception().GetRawData(); + } + JSTaggedValue retValue = reinterpret_cast(const_cast(method->GetNativePointer()))(&ecmaRuntimeCallInfo); - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return InvokeBuiltinHandleException(thread, retValue); } return retValue.GetRawData(); } -JSTaggedValue InvokeJsFunction(JSThread *thread, const JSHandle &func, const JSHandle &obj, - const JSHandle &newTgt, InternalCallParams *arguments) +JSTaggedValue InvokeJsFunction(EcmaRuntimeCallInfo *info) { - ASSERT(func->GetCallTarget() != nullptr); - - constexpr uint32_t extraSize = 3; // Include func newtarget and this - auto length = arguments->GetLength(); - PandaVector argArray; - argArray.reserve(length + extraSize); - - argArray.emplace_back(func.GetTaggedType()); - argArray.emplace_back(newTgt.GetTaggedType()); - argArray.emplace_back(obj.GetTaggedType()); - - for (ArraySizeT i = 0; i < length; ++i) { - // // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - argArray.emplace_back(arguments->GetArgv()[i]); - } - - return EcmaInterpreter::Execute(thread, JSHandle::Cast(func), argArray.size(), argArray.data()); + return EcmaInterpreter::Execute(info); } + } // namespace panda::ecmascript diff --git a/runtime/js_invoker.h b/runtime/js_invoker.h index 1af88acf0..1db795f79 100644 --- a/runtime/js_invoker.h +++ b/runtime/js_invoker.h @@ -58,8 +58,8 @@ private: PandaVector> args_ {}; }; -JSTaggedValue InvokeJsFunction(JSThread *thread, const JSHandle &func, const JSHandle &obj, - const JSHandle &newTgt, InternalCallParams *arguments); +// Wraps around interpreter execute +JSTaggedValue InvokeJsFunction(EcmaRuntimeCallInfo *info); } // namespace panda::ecmascript #endif // ECMASCRIPT_INVOKE_H diff --git a/runtime/js_iterator.cpp b/runtime/js_iterator.cpp index e480b1314..8d35e6901 100644 --- a/runtime/js_iterator.cpp +++ b/runtime/js_iterator.cpp @@ -63,7 +63,8 @@ JSHandle JSIterator::GetIterator(JSThread *thread, const JSHandle // 1.ReturnIfAbrupt(obj). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, obj); // 3.Let iterator be Call(method,obj). - JSTaggedValue ret = JSFunction::Call(thread, method, obj, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, method, obj, JSTaggedValue::Undefined(), 0); + JSTaggedValue ret = JSFunction::Call(info.get()); JSHandle iter(thread, ret); // 4.ReturnIfAbrupt(iterator). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, iter); @@ -81,7 +82,8 @@ JSHandle JSIterator::IteratorNextOld(JSThread *thread, const JSHandle< // 1.If value was not passed, then Let result be Invoke(iterator, "next", «‍ »). JSHandle key(thread->GlobalConstants()->GetHandledNextString()); JSHandle next(JSObject::GetMethod(thread, iter, key)); - JSTaggedValue ret = JSFunction::Call(thread, next, iter, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, next, iter, JSTaggedValue::Undefined(), 0); + JSTaggedValue ret = JSFunction::Call(info.get()); JSHandle result(thread, ret); // 3.ReturnIfAbrupt(result) RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, result); @@ -97,7 +99,8 @@ JSHandle JSIterator::IteratorNext(JSThread *thread, const JSHandl const JSHandle &nextMethod) { // 1.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]]). - JSTaggedValue ret = JSFunction::Call(thread, nextMethod, iter, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, nextMethod, iter, JSTaggedValue::Undefined(), 0); + JSTaggedValue ret = JSFunction::Call(info.get()); JSHandle result(thread, ret); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, result); @@ -115,9 +118,10 @@ JSHandle JSIterator::IteratorNext(JSThread *thread, const JSHandl const JSHandle &value) { // 2.a. Let result be ? Call(iteratorRecord.[[NextMethod]], iteratorRecord.[[Iterator]], « value »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(value); - JSTaggedValue ret = JSFunction::Call(thread, nextMethod, iter, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, nextMethod, iter, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(value); + JSTaggedValue ret = JSFunction::Call(info.get()); JSHandle result(thread, ret); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, result); @@ -177,7 +181,7 @@ JSHandle JSIterator::IteratorClose(JSThread *thread, const JSHand ASSERT_PRINT(iter->IsECMAObject(), "iter must be JSObject"); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle exceptionOnThread; - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { exceptionOnThread = JSHandle(thread, thread->GetException()); thread->ClearException(); } @@ -194,7 +198,8 @@ JSHandle JSIterator::IteratorClose(JSThread *thread, const JSHand return completion; } // 6.Let innerResult be Call(return, iterator, «‍ »). - JSTaggedValue ret = JSFunction::Call(thread, returnFunc, iter, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, returnFunc, iter, JSTaggedValue::Undefined(), 0); + JSTaggedValue ret = JSFunction::Call(info.get()); if (!exceptionOnThread.IsEmpty()) { thread->SetException(exceptionOnThread.GetTaggedValue()); } @@ -211,7 +216,7 @@ JSHandle JSIterator::IteratorClose(JSThread *thread, const JSHand return completion; } // 8.If innerResult.[[type]] is throw, return Completion(innerResult). - if (thread->HasPendingException()) { + if (UNLIKELY(thread->HasPendingException())) { return innerResult; } // 9.If Type(innerResult.[[value]]) is not Object, throw a TypeError exception. diff --git a/runtime/js_object-inl.h b/runtime/js_object-inl.h index 88e283ea1..6bfced703 100644 --- a/runtime/js_object-inl.h +++ b/runtime/js_object-inl.h @@ -23,10 +23,6 @@ #include "plugins/ecmascript/runtime/tagged_array-inl.h" namespace panda::ecmascript { -inline bool ECMAObject::IsBuiltinsConstructor() const -{ - return GetClass()->IsBuiltinsCtor(); -} inline bool ECMAObject::IsCallable() const { diff --git a/runtime/js_object.cpp b/runtime/js_object.cpp index 38964067e..4527c4b34 100644 --- a/runtime/js_object.cpp +++ b/runtime/js_object.cpp @@ -638,9 +638,10 @@ bool JSObject::CallSetter(JSThread *thread, const AccessorData &accessor, const } JSHandle func(thread, setter); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(value); - JSFunction::Call(thread, func, receiver, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, func, receiver, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(value); + JSFunction::Call(info.get()); // 10. ReturnIfAbrupt(setterResult). RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, false); @@ -658,7 +659,8 @@ JSTaggedValue JSObject::CallGetter(JSThread *thread, const AccessorData *accesso } JSHandle func(thread, getter); - JSTaggedValue res = JSFunction::Call(thread, func, receiver, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, func, receiver, JSTaggedValue::Undefined(), 0); + JSTaggedValue res = JSFunction::Call(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); return res; } @@ -1457,9 +1459,10 @@ bool JSObject::InstanceOf(JSThread *thread, const JSHandle &objec // 4. If instOfHandler is not undefined, then if (!instOfHandler->IsUndefined()) { // a. Return ! ToBoolean(? Call(instOfHandler, target, «object»)). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(object); - JSTaggedValue tagged = JSFunction::Call(thread, instOfHandler, target, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, instOfHandler, target, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(object); + JSTaggedValue tagged = JSFunction::Call(info.get()); return tagged.ToBoolean(); } diff --git a/runtime/js_object.h b/runtime/js_object.h index 72e7d63cc..c71c283fd 100644 --- a/runtime/js_object.h +++ b/runtime/js_object.h @@ -333,7 +333,6 @@ public: CAST_CHECK(ECMAObject, IsECMAObject); void SetBuiltinsCtorMode(); - bool IsBuiltinsConstructor() const; void SetCallable(bool flag); bool IsCallable() const; JSMethod *GetCallTarget() const; diff --git a/runtime/js_promise.cpp b/runtime/js_promise.cpp index dd7ea6827..66e9ea3c5 100644 --- a/runtime/js_promise.cpp +++ b/runtime/js_promise.cpp @@ -103,9 +103,10 @@ JSHandle JSPromise::NewPromiseCapability(JSThread *thread, co // 6. Let promise be Construct(C, «executor»). // 7. ReturnIfAbrupt(promise). JSHandle new_target(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(executor); - JSTaggedValue result = JSFunction::Construct(thread, obj, 1, arguments->GetArgv(), new_target); + + auto info = NewRuntimeCallInfo(thread, obj, JSTaggedValue::Undefined(), new_target, 1); + info->SetCallArgs(executor); + JSTaggedValue result = JSFunction::Construct(info.get()); JSHandle promise(thread, result); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, factory->NewPromiseCapability()); // 8. If IsCallable(promiseCapability.[[Resolve]]) is false, throw a TypeError exception. @@ -167,11 +168,11 @@ JSTaggedValue JSPromise::PromiseResolve(JSThread *thread, const JSHandle thisArg = globalConst->GetHandledUndefined(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(xValue); JSHandle resolve(thread, promiseCapability->GetResolve()); - [[maybe_unused]] JSTaggedValue res = JSFunction::Call(thread, resolve, thisArg, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, resolve, thisArg, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(xValue); + [[maybe_unused]] JSTaggedValue res = JSFunction::Call(info.get()); RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 5. Return promiseCapability.[[Promise]]. diff --git a/runtime/js_proxy.cpp b/runtime/js_proxy.cpp index f70d83b25..1356a17ff 100644 --- a/runtime/js_proxy.cpp +++ b/runtime/js_proxy.cpp @@ -78,9 +78,9 @@ JSTaggedValue JSProxy::GetPrototype(JSThread *thread, const JSHandle &p return JSHandle(targetHandle)->GetPrototype(thread); } // 8. Let handlerProto be Call(trap, handler, «target»). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle); - JSHandle handlerProto(thread, JSFunction::Call(thread, trap, handler, 1, arguments->GetArgv())); + auto info = NewRuntimeCallInfo(thread, trap, handler, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(targetHandle.GetTaggedValue()); + JSHandle handlerProto(thread, JSFunction::Call(info.get())); // 9. ReturnIfAbrupt(handlerProto). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); @@ -136,10 +136,10 @@ bool JSProxy::SetPrototype(JSThread *thread, const JSHandle &proxy, con return JSTaggedValue::SetPrototype(thread, targetHandle, proto); }; JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle, proto); - JSTaggedValue trapResult = - JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv()); // 2: target and proto + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(targetHandle.GetTaggedValue(), proto.GetTaggedValue()); + JSTaggedValue trapResult = JSFunction::Call(info.get()); // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, V»)). // If booleanTrapResult is false, return false @@ -195,9 +195,10 @@ bool JSProxy::IsExtensible(JSThread *thread, const JSHandle &proxy) // 8. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target»)). JSHandle newTgt(thread, JSTaggedValue::Undefined()); JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle); - JSTaggedValue trapResult = JSFunction::Call(thread, trap, handlerTag, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(targetHandle); + JSTaggedValue trapResult = JSFunction::Call(info.get()); bool booleanTrapResult = trapResult.ToBoolean(); // 9. ReturnIfAbrupt(booleanTrapResult). @@ -242,9 +243,10 @@ bool JSProxy::PreventExtensions(JSThread *thread, const JSHandle &proxy return JSTaggedValue::PreventExtensions(thread, targetHandle); } JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle); - JSTaggedValue trapResult = JSFunction::Call(thread, trap, handlerTag, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(targetHandle); + JSTaggedValue trapResult = JSFunction::Call(info.get()); bool booleanTrapResult = trapResult.ToBoolean(); // 9. ReturnIfAbrupt(booleanTrapResult). @@ -293,10 +295,10 @@ bool JSProxy::GetOwnProperty(JSThread *thread, const JSHandle &proxy, c return JSTaggedValue::GetOwnProperty(thread, targetHandle, propKey, desc); } JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle, propKey); - JSTaggedValue trapResultObj = - JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv()); // 2: target and key + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(targetHandle, propKey); + JSTaggedValue trapResultObj = JSFunction::Call(info.get()); // 2: target and key JSHandle resultHandle(thread, trapResultObj); @@ -389,10 +391,10 @@ bool JSProxy::DefineOwnProperty(JSThread *thread, const JSHandle &proxy // 9. Let descObj be FromPropertyDescriptor(Desc). JSHandle descObj = JSObject::FromPropertyDescriptor(thread, desc); JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle, propKey, descObj); - JSTaggedValue trapResult = - JSFunction::Call(thread, trap, handlerTag, 3, arguments->GetArgv()); // 3: target, key and desc + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(targetHandle, propKey, descObj); + JSTaggedValue trapResult = JSFunction::Call(info.get()); // 3: target, key and desc bool booleanTrapResult = trapResult.ToBoolean(); // 11. ReturnIfAbrupt(booleanTrapResult). @@ -475,10 +477,9 @@ bool JSProxy::HasProperty(JSThread *thread, const JSHandle &proxy, cons // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P»)). JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle, propKey); - JSTaggedValue trapResult = - JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv()); // 2: target and key + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(targetHandle, propKey); + JSTaggedValue trapResult = JSFunction::Call(info.get()); // 2: target and key bool booleanTrapResult = trapResult.ToBoolean(); // 10. ReturnIfAbrupt(booleanTrapResult). @@ -534,10 +535,10 @@ OperationResult JSProxy::GetProperty(JSThread *thread, const JSHandle & } // 9. Let trapResult be Call(trap, handler, «target, P, Receiver»). JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle, propKey, receiver); - JSTaggedValue trapResult = - JSFunction::Call(thread, trap, handlerTag, 3, arguments->GetArgv()); // 3: «target, P, Receiver» + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 3); + info->SetCallArgs(targetHandle, propKey, receiver); + JSTaggedValue trapResult = JSFunction::Call(info.get()); // 3: «target, P, Receiver» JSHandle resultHandle(thread, trapResult); // 10. ReturnIfAbrupt(trapResult). @@ -602,10 +603,10 @@ bool JSProxy::SetProperty(JSThread *thread, const JSHandle &proxy, cons // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P, V, Receiver»)) JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle, propKey, value, receiver); - JSTaggedValue trapResult = - JSFunction::Call(thread, trap, handlerTag, 4, arguments->GetArgv()); // 4: «target, P, V, Receiver» + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 4); + info->SetCallArgs(targetHandle, propKey, value, receiver); + JSTaggedValue trapResult = JSFunction::Call(info.get()); // 4: «target, P, V, Receiver» bool booleanTrapResult = trapResult.ToBoolean(); // 11. ReturnIfAbrupt(booleanTrapResult). @@ -658,10 +659,10 @@ bool JSProxy::DeleteProperty(JSThread *thread, const JSHandle &proxy, c // 9. Let booleanTrapResult be ToBoolean(Call(trap, handler, «target, P»)). JSHandle newTgt(thread, JSTaggedValue::Undefined()); JSHandle handlerTag(thread, proxy->GetHandler()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle, key); - JSTaggedValue trapResult = - JSFunction::Call(thread, trap, handlerTag, 2, arguments->GetArgv()); // 2: target and key + + auto info = NewRuntimeCallInfo(thread, trap, handlerTag, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(targetHandle, key); + JSTaggedValue trapResult = JSFunction::Call(info.get()); // 2: target and key bool booleanTrapResult = trapResult.ToBoolean(); // 11. ReturnIfAbrupt(booleanTrapResult). @@ -719,9 +720,10 @@ JSHandle JSProxy::OwnPropertyKeys(JSThread *thread, const JSHandle< // 8.Let trapResultArray be Call(trap, handler, «target»). JSHandle tagFunc(targetHandle); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(targetHandle); - JSTaggedValue res = JSFunction::Call(thread, trap, handlerHandle, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, trap, handlerHandle, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(targetHandle); + JSTaggedValue res = JSFunction::Call(info.get()); JSHandle trap_res_arr(thread, res); // 9.Let trapResult be CreateListFromArrayLike(trapResultArray, «String, Symbol»). @@ -834,11 +836,11 @@ JSHandle JSProxy::OwnPropertyKeys(JSThread *thread, const JSHandle< } // ES6 9.5.13 [[Call]] (thisArgument, argumentsList) -JSTaggedValue JSProxy::CallInternal(JSThread *thread, const JSHandle &proxy, - const JSHandle &this_arg, uint32_t argc, - const JSTaggedType argv[] // NOLINT(modernize-avoid-c-arrays) -) +JSTaggedValue JSProxy::CallInternal(EcmaRuntimeCallInfo *info) { + JSThread *thread = info->GetThread(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle proxy(info->GetFunction()); // step 1 ~ 4 get ProxyHandler and ProxyTarget JSHandle handler(thread, proxy->GetHandler()); if (handler->IsNull()) { @@ -848,37 +850,48 @@ JSTaggedValue JSProxy::CallInternal(JSThread *thread, const JSHandle &p JSHandle target(thread, proxy->GetTarget()); // 5.Let trap be GetMethod(handler, "apply"). - JSHandle key(thread->GlobalConstants()->GetHandledApplyString()); + JSHandle key(globalConst->GetHandledApplyString()); JSHandle method = JSObject::GetMethod(thread, handler, key); // 6.ReturnIfAbrupt(trap). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + uint32_t argc = info->GetArgsNumber(); + JSHandle thisArg = info->GetThis(); + JSHandle undefined = globalConst->GetHandledUndefined(); // 7.If trap is undefined, then // a.Return Call(target, thisArgument, argumentsList). if (method->IsUndefined()) { - return JSFunction::Call(thread, target, this_arg, argc, argv); + auto runtimeInfo = NewRuntimeCallInfo(thread, target, thisArg, undefined, argc); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + if (argc > 0) { + runtimeInfo->SetCallArg( + argc, reinterpret_cast(info->GetArgAddress(JSMethodArgs::NUM_MANDATORY_ARGS))); + } + return JSFunction::Call(runtimeInfo.get()); } // 8.Let argArray be CreateArrayFromList(argumentsList). ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); JSHandle taggedArray = factory->NewTaggedArray(argc); for (uint32_t index = 0; index < argc; ++index) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - taggedArray->Set(thread, index, JSTaggedValue(argv[index])); + taggedArray->Set(thread, index, info->GetCallArg(index)); } JSHandle arrHandle = JSArray::CreateArrayFromList(thread, taggedArray); // 9.Return Call(trap, handler, «target, thisArgument, argArray»). - InternalCallParams *proxyArgv = thread->GetInternalCallParams(); - proxyArgv->MakeArgv(target, this_arg, arrHandle); - return JSFunction::Call(thread, method, handler, 3, proxyArgv->GetArgv()); // 3: «target, thisArgument, argArray» + const uint32_t argsLength = 3; // 3: «target, thisArgument, argArray» + auto runtimeInfo = NewRuntimeCallInfo(thread, method, handler, undefined, argsLength); + RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); + runtimeInfo->SetCallArgs(target.GetTaggedValue(), thisArg.GetTaggedValue(), arrHandle.GetTaggedValue()); + return JSFunction::Call(runtimeInfo.get()); } // ES6 9.5.14 [[Construct]] ( argumentsList, new_target) -JSTaggedValue JSProxy::ConstructInternal(JSThread *thread, const JSHandle &proxy, uint32_t argc, - const JSTaggedType argv[], // NOLINT(modernize-avoid-c-arrays) - const JSHandle &new_target) +JSTaggedValue JSProxy::ConstructInternal(EcmaRuntimeCallInfo *info) { + JSThread *thread = info->GetThread(); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); // step 1 ~ 4 get ProxyHandler and ProxyTarget + JSHandle proxy(info->GetFunction()); JSHandle handler(thread, proxy->GetHandler()); if (handler->IsNull()) { THROW_TYPE_ERROR_AND_RETURN(thread, "Constructor: handler is null", JSTaggedValue::Exception()); @@ -887,37 +900,41 @@ JSTaggedValue JSProxy::ConstructInternal(JSThread *thread, const JSHandle target(thread, proxy->GetTarget()); // 5.Let trap be GetMethod(handler, "construct"). - JSHandle key(thread->GlobalConstants()->GetHandledProxyConstructString()); + JSHandle key(globalConst->GetHandledProxyConstructString()); JSHandle method = JSObject::GetMethod(thread, handler, key); // 6.ReturnIfAbrupt(trap). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 7.If trap is undefined, then // a.Assert: target has a [[Construct]] internal method. - // b.Return Construct(target, argumentsList, new_target). + // b.Return Construct(target, argumentsList, newTarget). if (method->IsUndefined()) { ASSERT(target->IsConstructor()); - return JSFunction::Construct(thread, target, argc, argv, new_target); + info->SetFunction(target.GetTaggedValue()); + return JSFunction::Construct(info); } // 8.Let argArray be CreateArrayFromList(argumentsList). ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); + uint32_t argc = info->GetArgsNumber(); JSHandle taggedArray = factory->NewTaggedArray(argc); for (uint32_t index = 0; index < argc; ++index) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - taggedArray->Set(thread, index, JSTaggedValue(argv[index])); + taggedArray->Set(thread, index, info->GetCallArg(index)); } JSHandle arrHandle = JSArray::CreateArrayFromList(thread, taggedArray); - // step 8 ~ 9 Call(trap, handler, «target, argArray, new_target »). - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(target, arrHandle, new_target); - JSTaggedValue newObj = - JSFunction::Call(thread, method, handler, 3, arguments->GetArgv()); // 3: «target, argArray, new_target » + // step 8 ~ 9 Call(trap, handler, «target, argArray, newTarget »). + JSHandle newTarget(info->GetNewTarget()); + const int32_t argsLength = 3; // 3: «target, argArray, newTarget » + JSHandle undefined = globalConst->GetHandledUndefined(); + auto runtimeInfo = NewRuntimeCallInfo(thread, method, handler, undefined, argsLength); + runtimeInfo->SetCallArgs(target.GetTaggedValue(), arrHandle.GetTaggedValue(), newTarget.GetTaggedValue()); + JSTaggedValue newObj = JSFunction::Call(runtimeInfo.get()); + // 10.ReturnIfAbrupt(newObj). RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); // 11.If Type(newObj) is not Object, throw a TypeError exception. - if (!newObj.IsObject()) { + if (!newObj.IsECMAObject()) { THROW_TYPE_ERROR_AND_RETURN(thread, "new object is not object", JSTaggedValue::Exception()); } // 12.Return newObj. diff --git a/runtime/js_proxy.h b/runtime/js_proxy.h index c793ecf16..632fdc7df 100644 --- a/runtime/js_proxy.h +++ b/runtime/js_proxy.h @@ -79,14 +79,9 @@ public: JSHandle GetSourceTarget(JSThread *thread) const; // ES6 9.5.13 [[Call]] (thisArgument, argumentsList) - static JSTaggedValue CallInternal(JSThread *thread, const JSHandle &proxy, - const JSHandle &this_arg, uint32_t argc, - const JSTaggedType argv[]); // NOLINT(modernize-avoid-c-arrays) + static JSTaggedValue CallInternal(EcmaRuntimeCallInfo *info); // ES6 9.5.14 [[Construct]] ( argumentsList, new_target) - static JSTaggedValue ConstructInternal( - // NOLINTNEXTLINE(modernize-avoid-c-arrays) - JSThread *thread, const JSHandle &proxy, uint32_t argc, const JSTaggedType argv[], - const JSHandle &new_target); + static JSTaggedValue ConstructInternal(EcmaRuntimeCallInfo *info); ACCESSORS_BASE(ECMAObject) ACCESSORS(0, Target) diff --git a/runtime/js_tagged_value.cpp b/runtime/js_tagged_value.cpp index 42f4d168e..6ae233dab 100644 --- a/runtime/js_tagged_value.cpp +++ b/runtime/js_tagged_value.cpp @@ -335,9 +335,10 @@ JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandleIsUndefined()) { JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue(); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(value); - JSTaggedValue valueResult = JSFunction::Call(thread, exoticToprim, tagged, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, exoticToprim, tagged, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(value); + JSTaggedValue valueResult = JSFunction::Call(info.get()); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); if (!valueResult.IsECMAObject()) { return valueResult; @@ -366,7 +367,8 @@ JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandl } JSHandle entryfunc = GetProperty(thread, tagged, keyString).GetValue(); if (entryfunc->IsCallable()) { - JSTaggedValue valueResult = JSFunction::Call(thread, entryfunc, tagged, 0, nullptr); + auto info = NewRuntimeCallInfo(thread, entryfunc, tagged, JSTaggedValue::Undefined(), 0); + JSTaggedValue valueResult = JSFunction::Call(info.get()); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); if (!valueResult.IsECMAObject()) { return valueResult; diff --git a/runtime/js_thread.cpp b/runtime/js_thread.cpp index e3c4dc4d5..d0d8454a6 100644 --- a/runtime/js_thread.cpp +++ b/runtime/js_thread.cpp @@ -123,6 +123,7 @@ void JSThread::Iterate(const RootVisitor &v0, const RootRangeVisitor &v1) }); JSSpanHandle::IterateChain(this, v1); + ScopedCallInfo::IterateChain(this, v1); } void JSThread::IterateEcmascriptEnvironment(const RootVisitor &v0, const RootRangeVisitor &v1) diff --git a/runtime/js_thread.h b/runtime/js_thread.h index d71c60a89..bc573d037 100644 --- a/runtime/js_thread.h +++ b/runtime/js_thread.h @@ -30,6 +30,7 @@ class EcmascriptEnvironment; class InternalCallParams; class PropertiesCache; class JSSpanHandle; +class ScopedCallInfo; class JSThread : public ManagedThread { public: @@ -267,6 +268,7 @@ private: int32_t current_handle_storage_index_ {-1}; int32_t handle_scope_count_ {0}; JSSpanHandle *span_handle_ {nullptr}; + ScopedCallInfo *scoped_call_info_ {nullptr}; // Run-time state bool stable_array_elements_guardians_ {true}; @@ -285,6 +287,7 @@ private: friend class EcmaHandleScope; friend class JSSpanHandle; + friend class ScopedCallInfo; friend class GlobalHandleCollection; }; } // namespace panda::ecmascript diff --git a/runtime/napi/jsnapi.cpp b/runtime/napi/jsnapi.cpp index eb0d4e9bb..fe493cc44 100644 --- a/runtime/napi/jsnapi.cpp +++ b/runtime/napi/jsnapi.cpp @@ -32,6 +32,7 @@ #include "plugins/ecmascript/runtime/ecma_vm.h" #include "plugins/ecmascript/runtime/global_env.h" #include "plugins/ecmascript/runtime/internal_call_params.h" +#include "plugins/ecmascript/runtime/ecma_runtime_call_info.h" #include "plugins/ecmascript/runtime/interpreter/fast_runtime_stub-inl.h" #include "plugins/ecmascript/runtime/jobs/micro_job_queue.h" #include "plugins/ecmascript/runtime/js_array.h" @@ -62,7 +63,6 @@ using ecmascript::ErrorType; using ecmascript::FastRuntimeStub; using ecmascript::GlobalEnv; using ecmascript::GlobalEnvConstants; -using ecmascript::InternalCallParams; using ecmascript::JSArray; using ecmascript::JSArrayBuffer; using ecmascript::JSDataView; @@ -939,15 +939,14 @@ Local FunctionRef::Call(const EcmaVM *vm, Local thisObj, } else { thisValue = JSHandle(thread, thread->GlobalConstants()->GetUndefined()); } - ObjectFactory *factory = vm->GetFactory(); - JSHandle arguments = factory->NewTaggedArray(length); - Span> sp(argv, length); - for (int i = 0; i < length; ++i) { - arguments->Set(thread, i, JSNApiHelper::ToJSHandle(sp[i])); - } - InternalCallParams *args = thread->GetInternalCallParams(); - args->MakeArgList(*arguments); - JSTaggedValue result = JSFunction::Call(thread, func, thisValue, arguments->GetLength(), args->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, func, thisValue, JSTaggedValue::Undefined(), length); + for (int32_t i = 0; i < length; ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + info->SetCallArg(i, JSNApiHelper::ToJSHandle(argv[i]).GetTaggedValue()); + } + JSTaggedValue result = JSFunction::Call(info.get()); + RETURN_VALUE_IF_ABRUPT_NOT_CLEAR_EXCEPTION(thread, JSValueRef::Exception(vm)); JSHandle resultValue(thread, result); @@ -968,15 +967,12 @@ Local FunctionRef::Constructor(const EcmaVM *vm, ScopedManagedCodeThread s(thread); JSHandle func = JSNApiHelper::ToJSHandle(this); JSHandle new_target = func; - ObjectFactory *factory = vm->GetFactory(); - JSHandle arguments = factory->NewTaggedArray(length); - Span> sp(argv, length); - for (int i = 0; i < length; ++i) { - arguments->Set(thread, i, JSNApiHelper::ToJSHandle(sp[i])); - } - ecmascript::InternalCallParams *params = thread->GetInternalCallParams(); - params->MakeArgList(*arguments); - JSTaggedValue result = JSFunction::Construct(thread, func, length, params->GetArgv(), new_target); + auto info = NewRuntimeCallInfo(thread, func, JSTaggedValue::Undefined(), new_target, length); + for (int32_t i = 0; i < length; ++i) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + info->SetCallArg(i, JSNApiHelper::ToJSHandle(argv[i]).GetTaggedValue()); + } + JSTaggedValue result = JSFunction::Construct(info.get()); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); JSHandle resultValue(vm->GetJSThread(), result); return JSNApiHelper::ToLocal(resultValue); @@ -1094,9 +1090,10 @@ bool PromiseCapabilityRef::Resolve(const EcmaVM *vm, Local value) JSHandle capacity(JSNApiHelper::ToJSHandle(this)); JSHandle resolve(thread, capacity->GetResolve()); JSHandle undefined(thread, constants->GetUndefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(arg); - JSFunction::Call(thread, resolve, undefined, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, resolve, undefined, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(arg); + JSFunction::Call(info.get()); RETURN_VALUE_IF_ABRUPT(thread, false); vm->ExecutePromisePendingJob(); @@ -1114,9 +1111,10 @@ bool PromiseCapabilityRef::Reject(const EcmaVM *vm, Local reason) JSHandle capacity(JSNApiHelper::ToJSHandle(this)); JSHandle reject(thread, capacity->GetReject()); JSHandle undefined(thread, constants->GetUndefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(arg); - JSFunction::Call(thread, reject, undefined, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, reject, undefined, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(arg); + JSFunction::Call(info.get()); RETURN_VALUE_IF_ABRUPT(thread, false); vm->ExecutePromisePendingJob(); @@ -1133,9 +1131,10 @@ Local PromiseRef::Catch(const EcmaVM *vm, Local handler JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle catchKey(thread, constants->GetPromiseCatchString()); JSHandle reject = JSNApiHelper::ToJSHandle(handler); - ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(reject); - JSTaggedValue result = JSFunction::Invoke(thread, promise, catchKey, 1, arguments->GetArgv()); + auto info = + ecmascript::NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), promise, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(reject); + JSTaggedValue result = JSFunction::Invoke(info.get(), catchKey); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); @@ -1150,9 +1149,10 @@ Local PromiseRef::Then(const EcmaVM *vm, Local handler) JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle thenKey(thread, constants->GetPromiseThenString()); JSHandle resolver = JSNApiHelper::ToJSHandle(handler); - ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(resolver.GetTaggedValue(), constants->GetUndefined()); - JSTaggedValue result = JSFunction::Invoke(thread, promise, thenKey, 2, arguments->GetArgv()); // 2: two args + auto info = + ecmascript::NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), promise, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(resolver, JSTaggedValue::Undefined()); + JSTaggedValue result = JSFunction::Invoke(info.get(), thenKey); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); @@ -1166,11 +1166,12 @@ Local PromiseRef::Then(const EcmaVM *vm, Local onFulfil JSHandle promise = JSNApiHelper::ToJSHandle(this); JSHandle thenKey(thread, constants->GetPromiseThenString()); - JSHandle resolver = JSNApiHelper::ToJSHandle(onFulfilled); + JSHandle resolve = JSNApiHelper::ToJSHandle(onFulfilled); JSHandle reject = JSNApiHelper::ToJSHandle(onRejected); - ecmascript::InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(resolver, reject); - JSTaggedValue result = JSFunction::Invoke(thread, promise, thenKey, 2, arguments->GetArgv()); // 2: two args + auto info = + ecmascript::NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), promise, JSTaggedValue::Undefined(), 2); + info->SetCallArgs(resolve, reject); + JSTaggedValue result = JSFunction::Invoke(info.get(), thenKey); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); return JSNApiHelper::ToLocal(JSHandle(thread, result)); @@ -1317,10 +1318,10 @@ Local TypedArrayRef::GetArrayBuffer(const EcmaVM *vm) \ JSHandle func = env->Get##Type##Function(); \ JSHandle arrayBuffer(JSNApiHelper::ToJSHandle(buffer)); \ - ecmascript::InternalCallParams *argv = thread->GetInternalCallParams(); \ - argv->MakeArgv(arrayBuffer.GetTaggedValue(), JSTaggedValue(byteOffset), JSTaggedValue(length)); \ uint32_t argc = 3; \ - JSTaggedValue result = JSFunction::Construct(thread, func, argc, argv->GetArgv(), func); \ + auto info = NewRuntimeCallInfo(thread, func, JSTaggedValue::Undefined(), func, argc); \ + info->SetCallArgs(arrayBuffer, JSTaggedValue(byteOffset), JSTaggedValue(length)); \ + JSTaggedValue result = JSFunction::Construct(info.get()); \ RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); \ JSHandle resultHandle(thread, result); \ return JSNApiHelper::ToLocal(resultHandle); \ diff --git a/runtime/napi/jsnapi_helper.h b/runtime/napi/jsnapi_helper.h index b063b113a..283d2546c 100644 --- a/runtime/napi/jsnapi_helper.h +++ b/runtime/napi/jsnapi_helper.h @@ -22,18 +22,18 @@ #include "plugins/ecmascript/runtime/napi/include/jsnapi.h" // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define RETURN_VALUE_IF_ABRUPT(thread, value) \ - do { \ - if (thread->HasPendingException()) { \ - thread->ClearException(); \ - return value; \ - } \ +#define RETURN_VALUE_IF_ABRUPT(thread, value) \ + do { \ + if (UNLIKELY(thread->HasPendingException())) { \ + thread->ClearException(); \ + return value; \ + } \ } while (false) // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define RETURN_VALUE_IF_ABRUPT_NOT_CLEAR_EXCEPTION(thread, value) \ do { \ - if (thread->HasPendingException()) { \ + if (UNLIKELY(thread->HasPendingException())) { \ return value; \ } \ } while (false) diff --git a/runtime/object_factory.cpp b/runtime/object_factory.cpp index 4d822f553..fbb32dd2f 100644 --- a/runtime/object_factory.cpp +++ b/runtime/object_factory.cpp @@ -722,9 +722,10 @@ JSHandle ObjectFactory::NewJSError(const ErrorType &error_type, const JSHandle nativePrototype(thread_, native_func->GetFunctionPrototype()); JSHandle ctorKey = globalConst->GetHandledConstructorString(); - InternalCallParams *arguments = thread_->GetInternalCallParams(); - arguments->MakeArgv(message.GetTaggedValue()); - JSTaggedValue obj = JSFunction::Invoke(thread_, nativePrototype, ctorKey, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread_, JSTaggedValue::Undefined(), nativePrototype, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(message); + JSTaggedValue obj = JSFunction::Invoke(info.get(), ctorKey); + JSHandle handleNativeInstanceObj(thread_, obj); return handleNativeInstanceObj; } @@ -777,6 +778,7 @@ JSHandle ObjectFactory::NewJSObjectByConstructor(const JSHandleSetTimeValue(thread_, JSTaggedValue(0.0)); JSDate::Cast(*obj)->SetLocalOffset(thread_, JSTaggedValue(JSDate::MAX_DOUBLE)); break; + case JSType::JS_TYPED_ARRAY: case JSType::JS_INT8_ARRAY: case JSType::JS_UINT8_ARRAY: case JSType::JS_UINT8_CLAMPED_ARRAY: @@ -860,6 +862,48 @@ JSHandle ObjectFactory::NewJSObjectByConstructor(const JSHandle(obj)); + break; + case JSType::JS_ASYNC_GENERATOR_FUNCTION: + JSFunction::InitializeJSFunction(thread_, JSHandle(obj)); + break; + case JSType::JS_PROXY_REVOC_FUNCTION: + JSFunction::InitializeJSFunction(thread_, JSHandle(obj)); + JSProxyRevocFunction::Cast(*obj)->SetRevocableProxy(thread_, JSTaggedValue::Undefined()); + break; + case JSType::JS_PROMISE_REACTIONS_FUNCTION: + JSFunction::InitializeJSFunction(thread_, JSHandle(obj)); + JSPromiseReactionsFunction::Cast(*obj)->SetPromise(thread_, JSTaggedValue::Undefined()); + JSPromiseReactionsFunction::Cast(*obj)->SetAlreadyResolved(thread_, JSTaggedValue::Undefined()); + break; + case JSType::JS_PROMISE_EXECUTOR_FUNCTION: + JSFunction::InitializeJSFunction(thread_, JSHandle(obj)); + JSPromiseExecutorFunction::Cast(*obj)->SetCapability(thread_, JSTaggedValue::Undefined()); + break; + case JSType::JS_PROMISE_ALL_RESOLVE_ELEMENT_FUNCTION: + JSFunction::InitializeJSFunction(thread_, JSHandle(obj)); + JSPromiseAllResolveElementFunction::Cast(*obj)->SetIndex(thread_, JSTaggedValue::Undefined()); + JSPromiseAllResolveElementFunction::Cast(*obj)->SetValues(thread_, JSTaggedValue::Undefined()); + JSPromiseAllResolveElementFunction::Cast(*obj)->SetCapabilities(thread_, JSTaggedValue::Undefined()); + JSPromiseAllResolveElementFunction::Cast(*obj)->SetRemainingElements(thread_, + JSTaggedValue::Undefined()); + JSPromiseAllResolveElementFunction::Cast(*obj)->SetAlreadyCalled(thread_, JSTaggedValue::Undefined()); + break; + case JSType::JS_INTL_BOUND_FUNCTION: + JSFunction::InitializeJSFunction(thread_, JSHandle(obj)); + JSIntlBoundFunction::Cast(*obj)->SetNumberFormat(thread_, JSTaggedValue::Undefined()); + JSIntlBoundFunction::Cast(*obj)->SetDateTimeFormat(thread_, JSTaggedValue::Undefined()); + JSIntlBoundFunction::Cast(*obj)->SetCollator(thread_, JSTaggedValue::Undefined()); + break; + case JSType::JS_BOUND_FUNCTION: { + JSMethod *method = vm_->GetMethodForNativeFunction( + reinterpret_cast(builtins::BuiltinsGlobal::CallJsBoundFunction)); + JSBoundFunction::Cast(*obj)->SetMethod(method); + JSBoundFunction::Cast(*obj)->SetBoundTarget(thread_, JSTaggedValue::Undefined()); + JSBoundFunction::Cast(*obj)->SetBoundThis(thread_, JSTaggedValue::Undefined()); + JSBoundFunction::Cast(*obj)->SetBoundArguments(thread_, JSTaggedValue::Undefined()); + break; + } case JSType::JS_FORIN_ITERATOR: case JSType::JS_MAP_ITERATOR: case JSType::JS_REG_EXP_ITERATOR: @@ -1995,8 +2039,6 @@ JSHandle ObjectFactory::NewJSRegExpIterator(const JSHandle env = vm_->GetGlobalEnv(); JSHandle protoValue = env->GetRegExpIteratorPrototype(); - // JSHandle dynHandle(thread_->GlobalConstants()->GetHandledJSRegExpIteratorClass()); - // dynHandle->SetPrototype(thread_, protoValue); // TODO(vpukhov): set prototype once JSHandle dynHandle = CreateDynClass(JSType::JS_REG_EXP_ITERATOR, protoValue); JSHandle iter(NewJSObject(dynHandle)); iter->GetJSHClass()->SetExtensible(true); diff --git a/tests/runtime/builtins/builtins_promise_test.cpp b/tests/runtime/builtins/builtins_promise_test.cpp index b924f244a..04263ed23 100644 --- a/tests/runtime/builtins/builtins_promise_test.cpp +++ b/tests/runtime/builtins/builtins_promise_test.cpp @@ -448,7 +448,7 @@ TEST_F(BuiltinsPromiseTest, Race2) * @tc.steps: step6. execute promise queue */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -549,7 +549,7 @@ TEST_F(BuiltinsPromiseTest, All) * @tc.steps: step6. execute promise queue */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -605,7 +605,7 @@ TEST_F(BuiltinsPromiseTest, Catch) * @tc.steps: step3. execute promise queue */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -663,7 +663,7 @@ TEST_F(BuiltinsPromiseTest, ThenResolve) * @tc.steps: step3. execute promise queue */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } @@ -720,7 +720,7 @@ TEST_F(BuiltinsPromiseTest, ThenReject) * @tc.steps: step3. execute promise queue */ auto microJobQueue = EcmaVM::Cast(instance)->GetMicroJobQueue(); - if (!thread->HasPendingException()) { + if (LIKELY(!thread->HasPendingException())) { job::MicroJobQueue::ExecutePendingJob(thread, microJobQueue); } } diff --git a/tests/runtime/common/js_function_test.cpp b/tests/runtime/common/js_function_test.cpp index a9115e0ec..4bc0f4310 100644 --- a/tests/runtime/common/js_function_test.cpp +++ b/tests/runtime/common/js_function_test.cpp @@ -137,9 +137,9 @@ TEST_F(JSFunctionTest, Invoke) JSHandle calleeValue(calleeFunc); JSObject::SetProperty(thread, JSHandle(callee), calleeKey, calleeValue); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(1)); - JSTaggedValue res = JSFunction::Invoke(thread, callee, calleeKey, 1, arguments->GetArgv()); + auto info = NewRuntimeCallInfo(thread, JSTaggedValue::Undefined(), callee, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(JSTaggedValue(1)); + JSTaggedValue res = JSFunction::Invoke(info.get(), calleeKey); JSTaggedValue ruler = BuiltinsBase::GetTaggedBoolean(true); EXPECT_EQ(res.GetRawData(), ruler.GetRawData()); diff --git a/tests/runtime/common/js_promise_test.cpp b/tests/runtime/common/js_promise_test.cpp index 0387dbd71..cc5730cbb 100644 --- a/tests/runtime/common/js_promise_test.cpp +++ b/tests/runtime/common/js_promise_test.cpp @@ -100,9 +100,10 @@ TEST_F(JSPromiseTest, FullFillPromise) JSHandle resolve(thread, capbility->GetResolve()); JSHandle undefined(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(33)); - JSFunction::Call(thread, resolve, undefined, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, resolve, undefined, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(JSTaggedValue(33)); + JSFunction::Call(info.get()); EXPECT_EQ(static_cast(newPromise->GetPromiseState().GetInt()), PromiseStatus::FULFILLED); EXPECT_EQ(JSTaggedValue::SameValue(newPromise->GetPromiseResult(), JSTaggedValue(33)), true); } @@ -119,9 +120,10 @@ TEST_F(JSPromiseTest, RejectPromise) JSHandle reject(thread, capbility->GetReject()); JSHandle undefined(thread, JSTaggedValue::Undefined()); - InternalCallParams *arguments = thread->GetInternalCallParams(); - arguments->MakeArgv(JSTaggedValue(44)); - JSFunction::Call(thread, reject, undefined, 1, arguments->GetArgv()); + + auto info = NewRuntimeCallInfo(thread, reject, undefined, JSTaggedValue::Undefined(), 1); + info->SetCallArgs(JSTaggedValue(44)); + JSFunction::Call(info.get()); EXPECT_EQ(static_cast(newPromise->GetPromiseState().GetInt()), PromiseStatus::REJECTED); EXPECT_EQ(JSTaggedValue::SameValue(newPromise->GetPromiseResult(), JSTaggedValue(44)), true); } diff --git a/tests/runtime/common/js_proxy_test.cpp b/tests/runtime/common/js_proxy_test.cpp index 53e832ebb..5c38ee998 100644 --- a/tests/runtime/common/js_proxy_test.cpp +++ b/tests/runtime/common/js_proxy_test.cpp @@ -553,9 +553,13 @@ TEST_F(JSProxyTest, Call) EXPECT_TRUE(handlerHandle->IsECMAObject()); JSHandle proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle); + JSTaggedValue res; EXPECT_TRUE(*proxyHandle != nullptr); - JSTaggedValue res = - JSProxy::CallInternal(thread, proxyHandle, JSHandle::Cast(proxyHandle), 0, nullptr); + { + auto info = NewRuntimeCallInfo(thread, proxyHandle, JSHandle::Cast(proxyHandle), + JSTaggedValue::Undefined(), 0); + res = JSProxy::CallInternal(info.get()); + } JSHandle taggedRes(thread, res); EXPECT_TRUE(JSTaggedValue::SameValue(taggedRes.GetTaggedValue(), JSTaggedValue::True())); @@ -567,8 +571,12 @@ TEST_F(JSProxyTest, Call) JSHandle proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle); EXPECT_TRUE(*proxyHandle2 != nullptr); - JSTaggedValue res2 = - JSProxy::CallInternal(thread, proxyHandle2, JSHandle::Cast(proxyHandle2), 0, nullptr); + JSTaggedValue res2; + { + auto info = NewRuntimeCallInfo(thread, proxyHandle2, JSHandle::Cast(proxyHandle2), + JSTaggedValue::Undefined(), 0); + res2 = JSProxy::CallInternal(info.get()); + } JSHandle taggedRes2(thread, res2); EXPECT_TRUE(JSTaggedValue::SameValue(taggedRes2.GetTaggedValue(), JSTaggedValue::False())); @@ -615,7 +623,11 @@ TEST_F(JSProxyTest, Construct) JSHandle proxyHandle = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle); EXPECT_TRUE(*proxyHandle != nullptr); - JSTaggedValue res = JSProxy::ConstructInternal(thread, proxyHandle, 0, nullptr, targetHandle); + JSTaggedValue res; + { + auto info = NewRuntimeCallInfo(thread, proxyHandle, JSTaggedValue::Undefined(), targetHandle, 0); + res = JSProxy::ConstructInternal(info.get()); + } JSHandle taggedRes(thread, res); JSHandle key(factory->NewFromCanBeCompressString("x")); EXPECT_EQ(JSObject::GetProperty(thread, taggedRes, key).GetValue()->GetInt(), 1); @@ -627,7 +639,11 @@ TEST_F(JSProxyTest, Construct) JSHandle proxyHandle2 = JSProxy::ProxyCreate(thread, targetHandle, handlerHandle); EXPECT_TRUE(*proxyHandle2 != nullptr); - JSTaggedValue res2 = JSProxy::ConstructInternal(thread, proxyHandle2, 0, nullptr, targetHandle); + JSTaggedValue res2; + { + auto info = NewRuntimeCallInfo(thread, proxyHandle2, JSTaggedValue::Undefined(), targetHandle, 0); + res2 = JSProxy::ConstructInternal(info.get()); + } JSHandle taggedRes2(thread, res2); EXPECT_EQ(JSObject::GetProperty(thread, taggedRes2, key).GetValue()->GetInt(), 2); } -- Gitee From 7c0af182f6efef413ae5ec2c9c02351ee1fe0ea5 Mon Sep 17 00:00:00 2001 From: Vsevolod Pukhov Date: Tue, 1 Nov 2022 16:28:24 +0300 Subject: [PATCH 4/4] Stackless NewObjDynRange and return, i2c and Native fastpath Signed-off-by: Vsevolod Pukhov --- .../ir_builder/ecmascript_inst_builder.cpp | 2 +- ecmastdlib/ecmastdlib.pa | 1 - irtoc_scripts/interpreter_main_loop.irt | 7 +- isa/isa.yaml | 2 +- ..._callithisrangedyn_pref_imm16_v8_aarch64.S | 2 +- ...cma_newobjdynrange_pref_imm16_v8_aarch64.S | 62 +++++ ...ma_callithisrangedyn_pref_imm16_v8_amd64.S | 2 +- ..._ecma_newobjdynrange_pref_imm16_v8_amd64.S | 63 +++++ ...ll_ecma_newobjdynrange_pref_imm16_v8_arm.S | 16 ++ runtime/common.h | 2 - runtime/ecma_runtime.yaml | 9 +- runtime/interpreter/ecma-interpreter-inl.h | 238 +++++++++++++++--- runtime/interpreter/js_decode_call_instr.h | 120 +++++---- runtime/intrinsics-inl.h | 15 +- runtime/js_thread.h | 2 +- 15 files changed, 442 insertions(+), 101 deletions(-) create mode 100644 runtime/bridge/arch/aarch64/handle_call_ecma_newobjdynrange_pref_imm16_v8_aarch64.S create mode 100644 runtime/bridge/arch/amd64/handle_call_ecma_newobjdynrange_pref_imm16_v8_amd64.S create mode 100644 runtime/bridge/arch/arm/handle_call_ecma_newobjdynrange_pref_imm16_v8_arm.S diff --git a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp index 45fa29ebe..e4682c70a 100644 --- a/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp +++ b/compiler/optimizer/ir_builder/ecmascript_inst_builder.cpp @@ -134,7 +134,7 @@ void InstBuilder::BuildEcmaNewobjdynrange(const BytecodeInstruction *bc_inst) auto start_reg = bc_inst->GetVReg(0); auto inst = graph->CreateInstIntrinsic(DataType::ANY, bc_pc); - inst->SetIntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE); + inst->SetIntrinsicId(RuntimeInterface::IntrinsicId::INTRINSIC_NEWOBJ_DYNRANGE_HANDLED); AdjustFlags(inst->GetIntrinsicId(), inst); inst->SetFlag(inst_flags::CAN_THROW); diff --git a/ecmastdlib/ecmastdlib.pa b/ecmastdlib/ecmastdlib.pa index 4ca7e12c6..6e07af2ce 100644 --- a/ecmastdlib/ecmastdlib.pa +++ b/ecmastdlib/ecmastdlib.pa @@ -64,7 +64,6 @@ .function any Ecmascript.Intrinsics.definefuncexpr(any a0, any a1) .function any Ecmascript.Intrinsics.definefuncDyn(u32 a0, any a1) .function any Ecmascript.Intrinsics.defineNCFuncDyn(u32 a0, any a1, any a2) -.function any Ecmascript.Intrinsics.newobjDynrangeInterp(u16 a0, any a1) .function any Ecmascript.Intrinsics.refeqDyn(any a0, any a1) .function any Ecmascript.Intrinsics.expDyn(any a0, any a1) .function any Ecmascript.Intrinsics.typeofDyn(any a0) diff --git a/irtoc_scripts/interpreter_main_loop.irt b/irtoc_scripts/interpreter_main_loop.irt index 2ce5142a5..41013d230 100644 --- a/irtoc_scripts/interpreter_main_loop.irt +++ b/irtoc_scripts/interpreter_main_loop.irt @@ -299,7 +299,12 @@ when "ECMA_CALLIRANGEDYN_PREF_IMM16_V8" ecma_intrinsic_check_setacc("CalliRangeDynInterp", i.format.size, i8tou16(as_imm(op[0])), vreg_ptr(op[1])) when "ECMA_NEWOBJDYNRANGE_PREF_IMM16_V8" - ecma_intrinsic_setacc("NewobjDynrangeInterp", i8tou16(as_imm(op[0])), vreg_ptr(op[1])) + num_args := SubI(i8tou16(as_imm(op[0]))).Imm(2).u16 + range := vreg_ptr(op[1]) + ctor := LoadI(range).Imm(0 * 8).any + new_target := LoadI(range).Imm(1 * 8).any + args := AddI(range).Imm(2 * 8).ptr + ecma_intrinsic_check_setacc("NewobjDynrangeHandled", i.format.size, num_args, ctor, new_target, args) when "ECMA_SUPERCALL_PREF_IMM16_V8" method_ptr := LoadI(%frame).Imm(Constants::FRAME_METHOD_OFFSET).ptr num_vregs := u32toword(read_uleb(method_file_data(method_ptr))) diff --git a/isa/isa.yaml b/isa/isa.yaml index 5e3719358..84642c901 100644 --- a/isa/isa.yaml +++ b/isa/isa.yaml @@ -804,7 +804,7 @@ groups: acc: out:top prefix: ecma format: [pref_op_imm_16_v_8] - properties: [not_compilable] + properties: [call, not_compilable] intrinsic_name: INTRINSIC_NEWOBJ_DYNRANGE - sig: ecma.supercall imm, v:in:top diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S index ac2849dce..57b3c5174 100644 --- a/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_aarch64.S @@ -19,7 +19,7 @@ // w15 <- num_args ldrh w15, [x10, 0] - add w15, w15, 2 // func + new.target + add w15, w15, (3 - 1) // described in js_decode_call_instr.h // x9 <- range in frame.vregs ldrb w13, [x10, 2] diff --git a/runtime/bridge/arch/aarch64/handle_call_ecma_newobjdynrange_pref_imm16_v8_aarch64.S b/runtime/bridge/arch/aarch64/handle_call_ecma_newobjdynrange_pref_imm16_v8_aarch64.S new file mode 100644 index 000000000..5e5977a65 --- /dev/null +++ b/runtime/bridge/arch/aarch64/handle_call_ecma_newobjdynrange_pref_imm16_v8_aarch64.S @@ -0,0 +1,62 @@ +/** + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// handle ecma.newobjdynrange +// regs set as follow +// x9 - frame.vregs, x10 - insn_ptr, x12 - method, x15 - acc, x13, x14 - temp + + // x14 <- acc + mov x14, x15 + // w15 <- num_args + ldrh w15, [x10, 0] + add w15, w15, (3 - 2) // described in js_decode_call_instr.h + + // x9 <- range in frame.vregs + ldrb w13, [x10, 2] + add x9, x9, x13, lsl 3 + + // ABI arg reg 0 <- panda::Method* + // ABI arg reg 1 <- num_args + mov x0, x12 + mov w1, w15 + + // Reserve stack args + // x12 <- stack pointer + sub x12, sp, x15, lsl 3 + and x12, x12, -16 + mov sp, x12 + + // stack arg0 <- func (range0) + // stack arg1 <- new_target (range1) + // stack arg3 <- this (passed in acc) + ldr x13, [x9, 0 * FRAME_VREGISTER_SIZE] + str x13, [x12, 0 * 8] + ldr x13, [x9, 1 * FRAME_VREGISTER_SIZE] + str x13, [x12, 1 * 8] + str x14, [x12, 2 * 8] + + subs w15, w15, 3 + beq .Linvoke + + add x9, x9, 1 * FRAME_VREGISTER_SIZE + add x12, x12, 2 * 8 + lsl w15, w15, 3 +1: + ldr x13, [x9, x15] + str x13, [x12, x15] + subs w15, w15, FRAME_VREGISTER_SIZE + bhi 1b + + b .Linvoke diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S index cd42ddedf..6e6b95e5f 100644 --- a/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S +++ b/runtime/bridge/arch/amd64/handle_call_ecma_callithisrangedyn_pref_imm16_v8_amd64.S @@ -19,7 +19,7 @@ // r15d <- num_args movzwl (%rax), %r15d - addl $2, %r15d // func + new.target + addl $(3 - 1), %r15d // described in js_decode_call_instr.h // rbx <- range in frame.vregs movzbl 2(%rax), %r13d diff --git a/runtime/bridge/arch/amd64/handle_call_ecma_newobjdynrange_pref_imm16_v8_amd64.S b/runtime/bridge/arch/amd64/handle_call_ecma_newobjdynrange_pref_imm16_v8_amd64.S new file mode 100644 index 000000000..5db760947 --- /dev/null +++ b/runtime/bridge/arch/amd64/handle_call_ecma_newobjdynrange_pref_imm16_v8_amd64.S @@ -0,0 +1,63 @@ +/** + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// handle ecma.newobjdynrange +// regs set as follow +// %rax - insn_ptr, %rbx - frame.vregs, %r12 - method, %r15 - acc, %r13, %r14 - temp + + // r14 <- acc + movq %r15, %r14 + // r15d <- num_args + movzwl (%rax), %r15d + addl $(3 - 2), %r15d // described in js_decode_call_instr.h + + // rbx <- range in frame.vregs + movzbl 2(%rax), %r13d + leaq (%rbx, %r13, FRAME_VREGISTER_SIZE), %rbx + + // ABI arg reg 0 (rdi) <- panda::Method* + // ABI arg reg 1 (rsi) <- num_args + movq %r12, %rdi + movq %r15, %rsi + + // Reserve stack args + // r12 <- stack pointer + leal (, %r15d, 8), %r12d + subq %r12, %rsp + andq $-16, %rsp + movq %rsp, %r12 + + // stack arg0 <- func (range0) + // stack arg1 <- new_target (range1) + // stack arg3 <- this (passed in acc) + movq (0 * FRAME_VREGISTER_SIZE)(%rbx), %r13 + movq %r13, (0 * 8)(%r12) + movq (1 * FRAME_VREGISTER_SIZE)(%rbx), %r13 + movq %r13, (1 * 8)(%r12) + movq %r14, (2 * 8)(%r12) + + subl $3, %r15d + jz .Linvoke + + addq $(1 * FRAME_VREGISTER_SIZE), %rbx + addq $(2 * 8), %r12 + shll $3, %r15d +1: + movq (%rbx, %r15), %r13 + movq %r13, (%r12, %r15) + subl $FRAME_VREGISTER_SIZE, %r15d + ja 1b + + jmp .Linvoke diff --git a/runtime/bridge/arch/arm/handle_call_ecma_newobjdynrange_pref_imm16_v8_arm.S b/runtime/bridge/arch/arm/handle_call_ecma_newobjdynrange_pref_imm16_v8_arm.S new file mode 100644 index 000000000..93b017e51 --- /dev/null +++ b/runtime/bridge/arch/arm/handle_call_ecma_newobjdynrange_pref_imm16_v8_arm.S @@ -0,0 +1,16 @@ +/** + * Copyright (c) 2022 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// The bridge is not supported currently diff --git a/runtime/common.h b/runtime/common.h index 36e4b9cd0..c001b36d1 100644 --- a/runtime/common.h +++ b/runtime/common.h @@ -22,8 +22,6 @@ namespace panda::ecmascript { enum BarrierMode { SKIP_BARRIER, WRITE_BARRIER, READ_BARRIER }; -static constexpr size_t NUM_MANDATORY_JSFUNC_ARGS = 3; - // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define PUBLIC_API PANDA_PUBLIC_API diff --git a/runtime/ecma_runtime.yaml b/runtime/ecma_runtime.yaml index 2dc97348f..afaab46c4 100644 --- a/runtime/ecma_runtime.yaml +++ b/runtime/ecma_runtime.yaml @@ -594,16 +594,17 @@ intrinsics: impl: panda::ecmascript::intrinsics::NewobjDynrange set_flags: [heap_inv] -- name: NewobjDynrangeInterp +- name: NewobjDynrangeHandled space: ecmascript class_name: Ecmascript.Intrinsics - method_name: newobjDynrangeInterp + method_name: newobjDynrangeHandled static: true exception: true signature: ret: any - args: [u16, any] - impl: panda::ecmascript::intrinsics::NewobjDynrangeInterp + args: [u16, any, any] + stackrange: true + impl: panda::ecmascript::intrinsics::NewobjDynrangeHandled set_flags: [heap_inv] - name: RefeqDyn diff --git a/runtime/interpreter/ecma-interpreter-inl.h b/runtime/interpreter/ecma-interpreter-inl.h index 83ca56121..823f23581 100644 --- a/runtime/interpreter/ecma-interpreter-inl.h +++ b/runtime/interpreter/ecma-interpreter-inl.h @@ -147,11 +147,25 @@ public: return reinterpret_cast(&thread->GetCurrentFrame()->GetVReg(first_arg_idx)); } - JSTaggedValue GetThisFunction() + JSTaggedValue GetCurrentFunction() { // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) auto num_vregs = this->GetFrame()->GetMethod()->GetNumVregs(); - return GetRegAsTaggedValue(num_vregs); + return GetRegAsTaggedValue(num_vregs + JSMethodArgs::FUNC_IDX); + } + + JSTaggedValue GetCurrentNewTarget() + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto num_vregs = this->GetFrame()->GetMethod()->GetNumVregs(); + return GetRegAsTaggedValue(num_vregs + JSMethodArgs::NEW_TARGET_IDX); + } + + JSTaggedValue GetCurrentThis() + { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto num_vregs = this->GetFrame()->GetMethod()->GetNumVregs(); + return GetRegAsTaggedValue(num_vregs + JSMethodArgs::THIS_IDX); } JSTaggedValue GetGlobalObject() @@ -198,6 +212,51 @@ public: ALWAYS_INLINE void HandleEcmaReturnDyn() { LOG_INST() << "ecma.return.dyn"; + + auto frame = this->GetFrame(); + + if (UNLIKELY(frame->IsInitobj() && frame->IsStackless())) { + auto acc_in = GetAccAsTaggedValue(); + JSFunction *func = JSFunction::Cast(GetCurrentFunction().GetTaggedObject()); + if (LIKELY(acc_in.IsECMAObject())) { + // preserve current value + } else if (LIKELY(func->IsBase() || acc_in.IsUndefined())) { + SetAccFromTaggedValue(GetCurrentThis()); + } else { + ASSERT(func->IsDerivedConstructor()); + JSHandle error = GetFactory()->GetJSError( + ErrorType::TYPE_ERROR, "Derived constructor must return object or undefined"); + this->GetJSThread()->SetException(error.GetTaggedValue()); + this->MoveToExceptionHandler(); + return; + } + } + this->template DoReturnDyn(); + } + + template + ALWAYS_INLINE void HandleEcmaReturnundefined() + { + LOG_INST() << "return.undefined"; + + auto frame = this->GetFrame(); + + if (UNLIKELY(frame->IsInitobj() && frame->IsStackless())) { + auto acc_in = GetAccAsTaggedValue(); + JSFunction *func = JSFunction::Cast(GetCurrentFunction().GetTaggedObject()); + if (LIKELY(func->IsBase() || acc_in.IsUndefined())) { + SetAccFromTaggedValue(GetCurrentThis()); + } else { + ASSERT(func->IsDerivedConstructor()); + JSHandle error = GetFactory()->GetJSError( + ErrorType::TYPE_ERROR, "Derived constructor must return object or undefined"); + this->GetJSThread()->SetException(error.GetTaggedValue()); + this->MoveToExceptionHandler(); + return; + } + } else { + SetAccFromTaggedValue(JSTaggedValue::Undefined()); + } this->template DoReturnDyn(); } @@ -234,9 +293,8 @@ public: // Native ASSERT(method->GetNumVregs() == 0); - uint32_t num_declared_args = method->GetNumArgs(); uint32_t num_actual_args = JSGetNumberActualArgsDyn(this->GetInst()); - uint32_t num_args = std::max(num_declared_args, num_actual_args); + uint32_t num_args = std::max(method->GetNumArgs(), num_actual_args); Frame *prev_frame = this->GetFrame(); BytecodeInstruction prev_inst = this->GetInst(); @@ -267,22 +325,21 @@ public: JSFunction *js_function = JSFunction::Cast(this_func); if (UNLIKELY(js_function->IsClassConstructor())) { JSHandle error = - GetFactory()->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot called without 'new'"); + GetFactory()->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot be called without 'new'"); js_thread->SetException(error.GetTaggedValue()); this->MoveToExceptionHandler(); return; } + EcmascriptEnvironment *prev_env = js_thread->GetEcmascriptEnv(); + if (method->HasCompiledCode()) { // AOT, JIT - EcmascriptEnvironment *prev_env = js_thread->GetEcmascriptEnv(); this->template CallCompiledCode(method); // Restore EcmascriptEnvironment if epilogue was not executed if (UNLIKELY(js_thread->HasPendingException())) { js_thread->SetEcmascriptEnv(prev_env); } } else { // Interpreter - EcmascriptEnvironment *prev_env = js_thread->GetEcmascriptEnv(); - method->IncrementHotnessCounter(0, nullptr); // Call stackless interpreter @@ -306,6 +363,147 @@ public: } } + template + ALWAYS_INLINE void HandleEcmaNewobjdynrange() + { + auto constexpr OPCODE = BytecodeInstruction::Opcode::ECMA_NEWOBJDYNRANGE_PREF_IMM16_V8; + + auto first_arg_reg_idx = this->GetInst().template GetVReg(); + auto num_range_args = this->GetInst().template GetImm(); + + LOG_INST() << "newobjDynrange " << num_range_args << " v" << first_arg_reg_idx; + + this->UpdateBytecodeOffset(); + // acc: out, thus dead + + auto range_args = GetStkArgs(first_arg_reg_idx); + auto ctor_handle = JSHandle(ToUintPtr(&range_args[0])); + auto new_target_handle = JSHandle(ToUintPtr(&range_args[1])); + + auto ctor = ctor_handle.GetTaggedValue(); + auto new_target = new_target_handle.GetTaggedValue(); + + auto thread = this->GetJSThread(); + + if (LIKELY(ctor.IsJSFunction() && ctor.IsConstructor())) { + auto ctor_func = JSFunction::Cast(ctor.GetTaggedObject()); + auto method = ctor_func->GetMethod(); + if (LIKELY(!method->IsNative() && (ctor_func->IsBase() || ctor_func->IsDerivedConstructor()))) { + JSTaggedValue this_obj; + if (ctor_func->IsBase()) { + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + this_obj = GetFactory() + ->NewJSObjectByConstructor(JSHandle(ctor_handle), new_target_handle) + .GetTaggedValue(); + INTERPRETER_RETURN_IF_ABRUPT(this_obj); + // gc may fire + ctor = ctor_handle.GetTaggedValue(); + ctor_func = JSFunction::Cast(ctor.GetTaggedObject()); + new_target = new_target_handle.GetTaggedValue(); + } else { + this_obj = JSTaggedValue::Undefined(); + } + SetAccFromTaggedValue(this_obj); + + EcmascriptEnvironment *prev_env = thread->GetEcmascriptEnv(); + + if (UNLIKELY(method->HasCompiledCode())) { + [[maybe_unused]] EcmaHandleScope handle_scope(thread); + JSHandle this_handle(thread, this_obj); + + // 'this' object to be set from acc in i2c + this->template CallCompiledCode(method); + // Restore EcmascriptEnvironment if epilogue was not executed + if (UNLIKELY(thread->HasPendingException())) { + thread->SetEcmascriptEnv(prev_env); + return; + } + + auto acc_in = GetAccAsTaggedValue(); + // gc may fire + ctor = ctor_handle.GetTaggedValue(); + ctor_func = JSFunction::Cast(ctor.GetTaggedObject()); + if (LIKELY(acc_in.IsECMAObject())) { + // preserve current value + } else if (LIKELY(ctor_func->IsBase() || acc_in.IsUndefined())) { + SetAccFromTaggedValue(this_handle.GetTaggedValue()); + } else { + ASSERT(ctor_func->IsDerivedConstructor()); + JSHandle error = GetFactory()->GetJSError( + ErrorType::TYPE_ERROR, "Derived constructor must return object or undefined"); + this->GetJSThread()->SetException(error.GetTaggedValue()); + this->MoveToExceptionHandler(); + return; + } + } else { + method->IncrementHotnessCounter(0, nullptr); + + // Call stackless interpreter + this->template CallInterpreterStackless, FORMAT, + /* is_dynamic = */ true, + /* is_range= */ false, /* accept_acc= */ false, + /* initobj= */ true>(method); + if (UNLIKELY(thread->HasPendingException())) { + return; + } + this->GetFrame() + ->GetVReg(method->GetNumVregs() + JSMethodArgs::THIS_IDX) + .SetValue(this_obj.GetRawData()); + + // Init EcmascriptEnvironment + ConstantPool *constant_pool = ConstantPool::Cast(ctor_func->GetConstantPool().GetHeapObject()); + JSTaggedValue lexical_env = ctor_func->GetLexicalEnv(); + EcmascriptEnvironment *new_env = JSFrame::GetJSEnv(this->GetFrame()); + new (new_env) + EcmascriptEnvironment(prev_env, constant_pool, lexical_env.GetHeapObject(), ctor_func); + + // Update EcmascriptEnvironment + thread->SetEcmascriptEnv(new_env); + } + + return; + } + + if (LIKELY(ctor_func->IsBuiltinConstructor())) { + ASSERT(method->IsNative() && method->GetNumVregs() == 0); + + uint32_t num_actual_args = JSGetNumberActualArgsDyn(this->GetInst()); + uint32_t num_args = std::max(method->GetNumArgs(), num_actual_args); + + Frame *prev_frame = this->GetFrame(); + BytecodeInstruction prev_inst = this->GetInst(); + Frame *frame = + JSFrame::CreateNativeFrame(thread, method, thread->GetCurrentFrame(), num_args, num_actual_args); + + JSCopyArgumets(this->GetJSThread(), prev_frame, ctor.GetRawData(), + prev_inst, frame, 0, num_actual_args); + frame->GetVReg(0 + JSMethodArgs::THIS_IDX).SetValue(JSTaggedValue::VALUE_UNDEFINED); + + // Call native method + thread->SetCurrentFrame(frame); + JSTaggedValue ret_value = JSFrame::ExecuteNativeMethod(thread, frame, method, num_actual_args); + ASSERT(thread->GetCurrentFrame() == frame); + thread->SetCurrentFrameIsCompiled(false); + thread->SetCurrentFrame(prev_frame); + + JSFrame::DestroyNativeFrame(thread, frame); + if (UNLIKELY(thread->HasPendingException())) { + this->MoveToExceptionHandler(); + return; + } + ASSERT(JSTaggedValue(ret_value).IsException() == false); + SetAccFromTaggedValue(ret_value); + this->template MoveToNextInst(); + return; + } + } + + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + INTRINSIC_CALL_CHECK_SETACC(intrinsics::NewobjDynrange(thread, num_range_args - 2U, ctor.GetRawData(), + new_target.GetRawData(), range_args + 2U)); + this->template MoveToNextInst(); + } + template ALWAYS_INLINE void HandleEcmaCall0dyn() { @@ -1273,21 +1471,6 @@ public: this->template MoveToNextInst(); } - template - ALWAYS_INLINE void HandleEcmaNewobjdynrange() - { - auto first_arg_reg_idx = this->GetInst().template GetVReg(); - auto num_args = this->GetInst().template GetImm(); - - LOG_INST() << "newobjDynrange " << num_args << " v" << first_arg_reg_idx; - - auto range_args = GetStkArgs(first_arg_reg_idx); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - INTRINSIC_CALL_CHECK_SETACC(intrinsics::NewobjDynrange(this->GetJSThread(), num_args - 2U, range_args[0], - range_args[1], range_args + 2U)); - this->template MoveToNextInst(); - } - template ALWAYS_INLINE void HandleEcmaRefeqdyn() { @@ -2428,15 +2611,6 @@ public: this->template MoveToNextInst(); } - template - ALWAYS_INLINE void HandleEcmaReturnundefined() - { - LOG_INST() << "return.undefined"; - SetAccFromTaggedValue(JSTaggedValue::Undefined()); - this->GetFrame()->GetAcc().Set(JSTaggedValue::Undefined().GetRawData()); - this->template MoveToNextInst(); - } - template ALWAYS_INLINE void HandleEcmaLdnan() { diff --git a/runtime/interpreter/js_decode_call_instr.h b/runtime/interpreter/js_decode_call_instr.h index 79670d648..5964669c1 100644 --- a/runtime/interpreter/js_decode_call_instr.h +++ b/runtime/interpreter/js_decode_call_instr.h @@ -18,37 +18,42 @@ ALWAYS_INLINE inline uint32_t JSGetNumberActualArgsDyn([[maybe_unused]] Bytecode constexpr auto OP = R::template Get(); if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS + 0; + return JSMethodArgs::FIRST_ARG_IDX + 0; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS + 1; + return JSMethodArgs::FIRST_ARG_IDX + 1; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS + 2; + return JSMethodArgs::FIRST_ARG_IDX + 2; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS + 3; + return JSMethodArgs::FIRST_ARG_IDX + 3; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); auto imm = inst.GetImm(); - return NUM_MANDATORY_JSFUNC_ARGS + imm; + return JSMethodArgs::FIRST_ARG_IDX + imm; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS; + return JSMethodArgs::FIRST_ARG_IDX; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS + 1; + return JSMethodArgs::FIRST_ARG_IDX + 1; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS + 2; + return JSMethodArgs::FIRST_ARG_IDX + 2; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); - return NUM_MANDATORY_JSFUNC_ARGS + 3; + return JSMethodArgs::FIRST_ARG_IDX + 3; } else if constexpr (OP == R::template Get()) { static_assert(FORMAT == R::template Get()); auto imm = inst.GetImm(); - ASSERT(imm >= 1); // 'this' is always passed to the function - return NUM_MANDATORY_JSFUNC_ARGS - 1 + imm; + ASSERT(imm >= 1); // magic, 'this' is counted in range, 'func' - not + return JSMethodArgs::FIRST_ARG_IDX + (imm - 1); + } else if constexpr (OP == R::template Get()) { + static_assert(FORMAT == R::template Get()); + auto imm = inst.GetImm(); + ASSERT(imm >= 2); // magic, 'func' and 'new_target' are counted in range + return JSMethodArgs::FIRST_ARG_IDX + (imm - 2); } else { enum { IMPOSSIBLE_CASE = false }; static_assert(IMPOSSIBLE_CASE, "Impossible case"); @@ -81,10 +86,12 @@ ALWAYS_INLINE inline uint16_t JSGetCalleRangeStartDyn([[maybe_unused]] BytecodeI constexpr auto op = R::template Get(); if constexpr (op == R::template Get() || - op == R::template Get()) { + op == R::template Get() || + op == R::template Get()) { return inst.GetVReg(); } + UNREACHABLE_CONSTEXPR(); return 0; } @@ -122,12 +129,23 @@ ALWAYS_INLINE inline static void JSCopyArgumets(JSThread *thread, Frame *prev_fr // Where vreg[N-1] is accumulator + // ecma.newobjdynrange + // dyn_arg[0] - vreg[ 0] [functional object] + // dyn_arg[1] - vreg[ 1] [ new.target ] + // dyn_arg[2] - allocated this, untouched + // dyn_arg[3] - vreg[ 2] [ args[ 0] ] + // dyn_arg[4] - vreg[ 3] [ args[ 1] ] + // ... + // dyn_arg[N] - vreg[N-1] [ args[N-3] ] + using R = BytecodeInstructionResolver; constexpr auto op = R::template Get(); - ASSERT(num_actual_args >= NUM_MANDATORY_JSFUNC_ARGS); - new_frame->GetVReg(num_vregs + 0).SetValue(raw_fn_object); - new_frame->GetVReg(num_vregs + 1).SetValue(JSTaggedValue::VALUE_UNDEFINED); + ASSERT(num_actual_args >= JSMethodArgs::FIRST_ARG_IDX); + new_frame->GetVReg(num_vregs + JSMethodArgs::FUNC_IDX).SetValue(raw_fn_object); + if constexpr (op != R::template Get()) { + new_frame->GetVReg(num_vregs + JSMethodArgs::NEW_TARGET_IDX).SetValue(JSTaggedValue::VALUE_UNDEFINED); + } if constexpr (op == R::template Get() || op == R::template Get() || @@ -135,68 +153,74 @@ ALWAYS_INLINE inline static void JSCopyArgumets(JSThread *thread, Frame *prev_fr op == R::template Get() || op == R::template Get()) { JSTaggedValue fn_object(raw_fn_object); - uint64_t dyn_arg2 = JSTaggedValue::VALUE_UNDEFINED; + uint64_t this_arg = JSTaggedValue::VALUE_UNDEFINED; if (fn_object.IsJSFunction() && !JSFunction::Cast(fn_object.GetHeapObject())->IsStrict()) { - dyn_arg2 = thread->GetGlobalObject().GetRawData(); + this_arg = thread->GetGlobalObject().GetRawData(); } - new_frame->GetVReg(num_vregs + 2).SetValue(dyn_arg2); + new_frame->GetVReg(num_vregs + JSMethodArgs::THIS_IDX).SetValue(this_arg); } if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX); // Do nothing } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 1); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0).SetValue(prev_frame->GetAccAsVReg().GetValue()); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX + 1); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 0).SetValue(prev_frame->GetAccAsVReg().GetValue()); } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 2); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1).SetValue(prev_frame->GetAccAsVReg().GetValue()); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX + 2); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 1).SetValue(prev_frame->GetAccAsVReg().GetValue()); } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 3); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1) = prev_frame->GetVReg(prev_inst.GetVReg(2)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX + 3); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 0) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 1) = prev_frame->GetVReg(prev_inst.GetVReg(2)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); uint16_t prev_v0 = JSGetCalleRangeStartDyn(prev_inst); - for (uint16_t i = 1; i < (num_actual_args - 2); ++i) { - new_frame->GetVReg(num_vregs + 2 + i) = prev_frame->GetVReg(prev_v0 + i); + for (uint16_t i = 0; i < (num_actual_args - JSMethodArgs::FIRST_ARG_IDX); ++i) { + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + i) = prev_frame->GetVReg(prev_v0 + 1 + i); } } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS); - new_frame->GetVReg(num_vregs + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX); + new_frame->GetVReg(num_vregs + JSMethodArgs::THIS_IDX).SetValue(prev_frame->GetAccAsVReg().GetValue()); } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 1); - new_frame->GetVReg(num_vregs + 2) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0).SetValue(prev_frame->GetAccAsVReg().GetValue()); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX + 1); + new_frame->GetVReg(num_vregs + JSMethodArgs::THIS_IDX) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 0).SetValue(prev_frame->GetAccAsVReg().GetValue()); } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 2); - new_frame->GetVReg(num_vregs + 2) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(2)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1).SetValue(prev_frame->GetAccAsVReg().GetValue()); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX + 2); + new_frame->GetVReg(num_vregs + JSMethodArgs::THIS_IDX) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 0) = prev_frame->GetVReg(prev_inst.GetVReg(2)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 1).SetValue(prev_frame->GetAccAsVReg().GetValue()); } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); - ASSERT(num_actual_args == NUM_MANDATORY_JSFUNC_ARGS + 3); - new_frame->GetVReg(num_vregs + 2) = prev_frame->GetVReg(prev_inst.GetVReg(1)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 0) = prev_frame->GetVReg(prev_inst.GetVReg(2)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 1) = prev_frame->GetVReg(prev_inst.GetVReg(3)); - new_frame->GetVReg(num_vregs + NUM_MANDATORY_JSFUNC_ARGS + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); + ASSERT(num_actual_args == JSMethodArgs::FIRST_ARG_IDX + 3); + new_frame->GetVReg(num_vregs + JSMethodArgs::THIS_IDX) = prev_frame->GetVReg(prev_inst.GetVReg(1)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 0) = prev_frame->GetVReg(prev_inst.GetVReg(2)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 1) = prev_frame->GetVReg(prev_inst.GetVReg(3)); + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + 2).SetValue(prev_frame->GetAccAsVReg().GetValue()); } else if constexpr (op == R::template Get()) { static_assert(FORMAT == R::template Get()); uint16_t prev_v0 = JSGetCalleRangeStartDyn(prev_inst); - for (uint16_t i = 0; i < (num_actual_args - 2); ++i) { - new_frame->GetVReg(num_vregs + 2 + i) = prev_frame->GetVReg(prev_v0 + 1 + i); + new_frame->GetVReg(num_vregs + JSMethodArgs::THIS_IDX) = prev_frame->GetVReg(prev_v0 + 1); + for (uint16_t i = 0; i < (num_actual_args - JSMethodArgs::FIRST_ARG_IDX); ++i) { + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + i) = prev_frame->GetVReg(prev_v0 + 2 + i); + } + } else if constexpr (op == R::template Get()) { + static_assert(FORMAT == R::template Get()); + uint16_t prev_v0 = JSGetCalleRangeStartDyn(prev_inst); + new_frame->GetVReg(num_vregs + JSMethodArgs::NEW_TARGET_IDX) = prev_frame->GetVReg(prev_v0 + 1); + for (uint16_t i = 0; i < (num_actual_args - JSMethodArgs::FIRST_ARG_IDX); ++i) { + new_frame->GetVReg(num_vregs + JSMethodArgs::FIRST_ARG_IDX + i) = prev_frame->GetVReg(prev_v0 + 2 + i); } - // Check 'this' value - ASSERT(new_frame->GetVReg(num_vregs + 2).GetValue() != JSTaggedValue::VALUE_UNDEFINED); } else { enum { IMPOSSIBLE_CASE = false }; static_assert(IMPOSSIBLE_CASE, "Impossible case"); diff --git a/runtime/intrinsics-inl.h b/runtime/intrinsics-inl.h index d4d6364b2..5a7fcbd64 100644 --- a/runtime/intrinsics-inl.h +++ b/runtime/intrinsics-inl.h @@ -561,20 +561,19 @@ INLINE_ECMA_INTRINSICS uint64_t DefinefuncDyn(JSThread *thread, uint32_t method_ INLINE_ECMA_INTRINSICS uint64_t NewobjDynrange(JSThread *thread, uint16_t num_args, uint64_t func, uint64_t new_target, void *stkargs_raw) { - JSSpanHandle args_handle(thread, Span(reinterpret_cast(stkargs_raw), num_args)); - return SlowRuntimeStub::NewObjDynRange(thread, num_args, JSTaggedValue(func), JSTaggedValue(new_target), - args_handle.DataTaggedType()) + reinterpret_cast(stkargs_raw)) .GetRawData(); } // NOLINTNEXTLINE(misc-definitions-in-headers) -INLINE_ECMA_INTRINSICS uint64_t NewobjDynrangeInterp(JSThread *thread, uint16_t num_args, uint64_t args_raw) +INLINE_ECMA_INTRINSICS uint64_t NewobjDynrangeHandled(JSThread *thread, uint16_t num_args, uint64_t func, + uint64_t new_target, void *stkargs_raw) { - auto args = reinterpret_cast(args_raw); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - return SlowRuntimeStub::NewObjDynRange(thread, num_args - 2, JSTaggedValue(args[0]), JSTaggedValue(args[1]), - &args[2]) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSSpanHandle args_handle(thread, Span(reinterpret_cast(stkargs_raw), num_args)); + + return SlowRuntimeStub::NewObjDynRange(thread, num_args, JSTaggedValue(func), JSTaggedValue(new_target), + args_handle.DataTaggedType()) .GetRawData(); } diff --git a/runtime/js_thread.h b/runtime/js_thread.h index bc573d037..62bf9bfb0 100644 --- a/runtime/js_thread.h +++ b/runtime/js_thread.h @@ -264,7 +264,7 @@ private: int nested_level_ = 0; JSTaggedType *handle_scope_storage_next_ {nullptr}; JSTaggedType *handle_scope_storage_end_ {nullptr}; - std::vector *> handle_storage_nodes_ {}; + PandaVector *> handle_storage_nodes_ {}; int32_t current_handle_storage_index_ {-1}; int32_t handle_scope_count_ {0}; JSSpanHandle *span_handle_ {nullptr}; -- Gitee