From 20d477a1b089c4fc6f38a7786b06fd967126295e Mon Sep 17 00:00:00 2001 From: lifansheng Date: Mon, 13 Sep 2021 19:59:04 +0800 Subject: [PATCH 01/11] modify globalrecord test Signed-off-by: lifansheng --- test/moduletest/globalrecord/expect_output.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/test/moduletest/globalrecord/expect_output.txt b/test/moduletest/globalrecord/expect_output.txt index 3ac28232d9..1f244cde9d 100755 --- a/test/moduletest/globalrecord/expect_output.txt +++ b/test/moduletest/globalrecord/expect_output.txt @@ -11,6 +11,7 @@ # See the License for the specific language governing permissions and # limitations under the License. + View extends String a -- Gitee From 392a688ad7d92e30b6dbbccac06b90911bbff502 Mon Sep 17 00:00:00 2001 From: lifansheng Date: Mon, 13 Sep 2021 20:06:54 +0800 Subject: [PATCH 02/11] delete space Signed-off-by: lifansheng --- test/moduletest/globalrecord/expect_output.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/test/moduletest/globalrecord/expect_output.txt b/test/moduletest/globalrecord/expect_output.txt index 1f244cde9d..3ac28232d9 100755 --- a/test/moduletest/globalrecord/expect_output.txt +++ b/test/moduletest/globalrecord/expect_output.txt @@ -11,7 +11,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - View extends String a -- Gitee From 3595cb62c953e9f77bbe16fd0c5b1da99a5a9a07 Mon Sep 17 00:00:00 2001 From: DaiHN Date: Fri, 17 Sep 2021 15:30:24 +0800 Subject: [PATCH 03/11] fix for function's name setting Signed-off-by: DaiHN --- "\\" | 13 + ecmascript/ecma_isa.yaml | 9 + ecmascript/interpreter/interpreter-inl.h | 70 +- ecmascript/interpreter/interpreter-inl.h.orig | 3269 +++++++++++++++++ ecmascript/interpreter/interpreter.h | 2 + ecmascript/interpreter/slow_runtime_stub.cpp | 54 + ecmascript/interpreter/slow_runtime_stub.h | 4 + .../debugger_instruction_dispatch.inl | 6 +- .../debugger_instruction_handler.inl | 10 + .../templates/instruction_dispatch.inl | 5 +- 10 files changed, 3434 insertions(+), 8 deletions(-) create mode 100644 "\\" create mode 100644 ecmascript/interpreter/interpreter-inl.h.orig diff --git "a/\\" "b/\\" new file mode 100644 index 0000000000..fa5bc0bd9a --- /dev/null +++ "b/\\" @@ -0,0 +1,13 @@ +fix function's name setting + +Signed-off-by: DaiHN + +# Please enter the commit message for your changes. Lines starting +# with '#' will be ignored, and an empty message aborts the commit. +# +# On branch master +# Your branch is up to date with 'origin/master'. +# +# Changes to be committed: +# modified: ecmascript/interpreter/slow_runtime_stub.cpp +# diff --git a/ecmascript/ecma_isa.yaml b/ecmascript/ecma_isa.yaml index 3a59436ab3..26a06b0b2f 100644 --- a/ecmascript/ecma_isa.yaml +++ b/ecmascript/ecma_isa.yaml @@ -577,3 +577,12 @@ groups: prefix: ecma format: [pref_op_id_32] properties: [string_id] + - sig: ecma.stownbyvaluewithnameset v1:in:top, v2:in:top + acc: in:top + prefix: ecma + format: [pref_op_v1_8_v2_8] + - sig: ecma.stownbynamewithnameset string_id, v:in:top + acc: in:top + prefix: ecma + format: [pref_op_id_32_v_8] + properties: [string_id] diff --git a/ecmascript/interpreter/interpreter-inl.h b/ecmascript/interpreter/interpreter-inl.h index 99efe62c89..f70d136fca 100644 --- a/ecmascript/interpreter/interpreter-inl.h +++ b/ecmascript/interpreter/interpreter-inl.h @@ -2303,9 +2303,6 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool value = GET_ACC(); if (!res.IsHole()) { INTERPRETER_RETURN_IF_ABRUPT(res); - if (value.IsJSFunction()) { - JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); - } RESTORE_ACC(); DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); } @@ -2745,6 +2742,73 @@ NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool DISPATCH(BytecodeInstruction::Format::PREF_ID32); } + HANDLE_OPCODE(HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8) { + uint32_t v0 = READ_INST_8_1(); + uint32_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::stownbyvaluewithnameset" + << " v" << v0 << " v" << v1; + JSTaggedValue receiver = GET_VREG_VALUE(v0); + if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { + SAVE_ACC(); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + JSTaggedValue value = GET_ACC(); + // fast path + JSTaggedValue res = FastRuntimeStub::SetPropertyByValue(thread, receiver, propKey, value); + + // SetPropertyByValue maybe gc need update the value + RESTORE_ACC(); + propKey = GET_VREG_VALUE(v1); + value = GET_ACC(); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + } + + // slow path + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto propKey = GET_VREG_VALUE(v1); // Maybe moved by GC + auto value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StOwnByValueWithNameSet(thread, receiver, propKey, value); + RESTORE_ACC(); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8) { + uint32_t stringId = READ_INST_32_1(); + uint32_t v0 = READ_INST_8_5(); + LOG_INST() << "intrinsics::stownbynamewithnameset " + << "v" << v0 << " stringId:" << stringId; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + if (receiver.IsJSObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + JSTaggedValue value = GET_ACC(); + // fast path + SAVE_ACC(); + JSTaggedValue res = FastRuntimeStub::SetPropertyByName(thread, receiver, propKey, value); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + RESTORE_ACC(); + } + + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto propKey = constpool->GetObjectFromCache(stringId); // Maybe moved by GC + auto value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StOwnByNameWithNameSet(thread, receiver, propKey, value); + RESTORE_ACC(); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_LDGLOBALVAR_PREF_ID32) { uint32_t stringId = READ_INST_32_1(); JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); diff --git a/ecmascript/interpreter/interpreter-inl.h.orig b/ecmascript/interpreter/interpreter-inl.h.orig new file mode 100644 index 0000000000..99efe62c89 --- /dev/null +++ b/ecmascript/interpreter/interpreter-inl.h.orig @@ -0,0 +1,3269 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H +#define ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H + +#include "ecmascript/class_linker/program_object-inl.h" +#include "ecmascript/ecma_string.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/ic/ic_runtime_stub-inl.h" +#include "ecmascript/interpreter/fast_runtime_stub-inl.h" +#include "ecmascript/interpreter/interpreter.h" +#include "ecmascript/interpreter/slow_runtime_stub.h" +#include "ecmascript/js_generator_object.h" +#include "ecmascript/js_tagged_value.h" +#include "ecmascript/literal_data_extractor.h" +#include "ecmascript/runtime_call_id.h" +#include "ecmascript/template_string.h" +#include "ecmascript/vmstat/runtime_stat.h" +#include "include/runtime_notification.h" +#include "libpandafile/code_data_accessor.h" +#include "libpandafile/file.h" +#include "libpandafile/method_data_accessor.h" + +namespace panda::ecmascript { +#if defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wvoid-ptr-dereference" +#pragma clang diagnostic ignored "-Wgnu-label-as-value" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wpedantic" +#endif + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define LOG_INST() LOG(DEBUG, INTERPRETER) << ": " + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define HANDLE_OPCODE(handle_opcode) \ + handle_opcode: // NOLINT(clang-diagnostic-gnu-label-as-value, cppcoreguidelines-macro-usage) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define ADVANCE_PC(offset) \ + pc += (offset); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-macro-usage) + +#define GOTO_NEXT() // NOLINT(clang-diagnostic-gnu-label-as-value, cppcoreguidelines-macro-usage) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DISPATCH(format) \ + do { \ + ADVANCE_PC(BytecodeInstruction::Size(format)) \ + opcode = READ_INST_OP(); goto * dispatchTable[opcode]; \ + } while (false) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define DISPATCH_OFFSET(offset) \ + do { \ + ADVANCE_PC(offset) \ + opcode = READ_INST_OP(); goto * dispatchTable[opcode]; \ + } while (false) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define GET_FRAME(CurrentSp) \ + (reinterpret_cast(CurrentSp) - 1) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SAVE_PC() (GET_FRAME(sp)->pc = pc) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SAVE_ACC() (GET_FRAME(sp)->acc = acc) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define RESTORE_ACC() (acc = GET_FRAME(sp)->acc) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define INTERPRETER_GOTO_EXCEPTION_HANDLER() \ + do { \ + SAVE_PC(); \ + goto *dispatchTable[EcmaOpcode::LAST_OPCODE]; \ + } while (false) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define CHECK_SWITCH_TO_DEBUGGER_TABLE() \ + if (Runtime::GetCurrent()->IsDebugMode()) { \ + dispatchTable = debugDispatchTable; \ + } + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define REAL_GOTO_DISPATCH_OPCODE(opcode) \ + do { \ + goto *instDispatchTable[opcode]; \ + } while (false) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define REAL_GOTO_EXCEPTION_HANDLER() \ + do { \ + SAVE_PC(); \ + goto *instDispatchTable[EcmaOpcode::LAST_OPCODE]; \ + } while (false) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define INTERPRETER_RETURN_IF_ABRUPT(result) \ + do { \ + if (result.IsException()) { \ + INTERPRETER_GOTO_EXCEPTION_HANDLER(); \ + } \ + } while (false) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define NOTIFY_DEBUGGER_EVENT() \ + do { \ + SAVE_ACC(); \ + SAVE_PC(); \ + NotifyBytecodePcChanged(thread); \ + RESTORE_ACC(); \ + } while (false) + +#if ECMASCRIPT_ENABLE_IC +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define UPDATE_HOTNESS_COUNTER_NON_ACC(offset) (UpdateHotnessCounter(thread, sp, acc, offset)) + +#define UPDATE_HOTNESS_COUNTER(offset) \ + do { \ + if (UpdateHotnessCounter(thread, sp, acc, offset)) { \ + RESTORE_ACC(); \ + } \ + } while (false) +#else +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define UPDATE_HOTNESS_COUNTER(offset) static_cast(0) +#define UPDATE_HOTNESS_COUNTER_NON_ACC(offset) static_cast(0) +#endif + +#define READ_INST_OP() READ_INST_8(0) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_4_0() (READ_INST_8(1) & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_4_1() (READ_INST_8(1) >> 4 & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_4_2() (READ_INST_8(2) & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_4_3() (READ_INST_8(2) >> 4 & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_0() READ_INST_8(1) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_1() READ_INST_8(2) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_2() READ_INST_8(3) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_3() READ_INST_8(4) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_4() READ_INST_8(5) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_5() READ_INST_8(6) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_6() READ_INST_8(7) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_7() READ_INST_8(8) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8_8() READ_INST_8(9) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) +#define READ_INST_8(offset) (*(pc + offset)) +#define MOVE_AND_READ_INST_8(currentInst, offset) \ + currentInst <<= 8; \ + currentInst += READ_INST_8(offset); \ + +#define READ_INST_16_0() READ_INST_16(2) +#define READ_INST_16_1() READ_INST_16(3) +#define READ_INST_16_2() READ_INST_16(4) +#define READ_INST_16_3() READ_INST_16(5) +#define READ_INST_16_5() READ_INST_16(7) +#define READ_INST_16(offset) \ + ({ \ + uint16_t currentInst = READ_INST_8(offset); \ + MOVE_AND_READ_INST_8(currentInst, offset - 1) \ + }) + +#define READ_INST_32_0() READ_INST_32(4) +#define READ_INST_32_1() READ_INST_32(5) +#define READ_INST_32_2() READ_INST_32(6) +#define READ_INST_32(offset) \ + ({ \ + uint32_t currentInst = READ_INST_8(offset); \ + MOVE_AND_READ_INST_8(currentInst, offset - 1) \ + MOVE_AND_READ_INST_8(currentInst, offset - 2) \ + MOVE_AND_READ_INST_8(currentInst, offset - 3) \ + }) + +#define READ_INST_64_0() \ + ({ \ + uint64_t currentInst = READ_INST_8(8); \ + MOVE_AND_READ_INST_8(currentInst, 7) \ + MOVE_AND_READ_INST_8(currentInst, 6) \ + MOVE_AND_READ_INST_8(currentInst, 5) \ + MOVE_AND_READ_INST_8(currentInst, 4) \ + MOVE_AND_READ_INST_8(currentInst, 3) \ + MOVE_AND_READ_INST_8(currentInst, 2) \ + MOVE_AND_READ_INST_8(currentInst, 1) \ + }) + +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define GET_VREG(idx) (sp[idx]) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define GET_VREG_VALUE(idx) (JSTaggedValue(sp[idx])) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) +// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) +#define SET_VREG(idx, val) (sp[idx] = (val)); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) +#define GET_ACC() (acc) // NOLINT(cppcoreguidelines-macro-usage) +#define SET_ACC(val) (acc = val); // NOLINT(cppcoreguidelines-macro-usage) + +JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *thread, const CallParams& params) +{ + JSTaggedType *sp = const_cast(thread->GetCurrentSPFrame()); + JSMethod *methodToCall = params.callTarget->GetCallTarget(); + ASSERT(methodToCall->GetNumVregs() == 0); + uint32_t numActualArgs = params.argc + RESERVED_CALL_ARGCOUNT; + // Tags and values of thread, new_tgt and argv_length are put into frames too for native frames + // NOLINTNEXTLINE(hicpp-signed-bitwise) + size_t frameSize = FRAME_STATE_SIZE + numActualArgs; + JSTaggedType *newSp = sp - frameSize; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) + if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { + return JSTaggedValue::Undefined(); + } + + EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, numActualArgs, reinterpret_cast(newSp)); + newSp[RESERVED_INDEX_CALL_TARGET] = reinterpret_cast(params.callTarget); + newSp[RESERVED_INDEX_NEW_TARGET] = params.newTarget; + newSp[RESERVED_INDEX_THIS] = params.thisArg; + for (size_t i = 0; i < params.argc; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[i + RESERVED_CALL_ARGCOUNT] = params.argv[i]; + } + + FrameState *state = GET_FRAME(newSp); + state->prev = sp; + state->pc = nullptr; + state->sp = newSp; + state->method = methodToCall; + thread->SetCurrentSPFrame(newSp); + LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call."; + JSTaggedValue tagged = + reinterpret_cast(const_cast(methodToCall->GetNativePointer()))(&ecmaRuntimeCallInfo); + LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call."; + thread->SetCurrentSPFrame(sp); + return tagged; +} + +JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, const CallParams& params) +{ + JSMethod *method = params.callTarget->GetCallTarget(); + ASSERT(thread->IsEcmaInterpreter()); + if (method->IsNative()) { + return EcmaInterpreter::ExecuteNative(thread, params); + } + + JSTaggedType *originalPrevSp = const_cast(thread->GetCurrentSPFrame()); + + // push break state + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSTaggedType *newSp = originalPrevSp - FRAME_STATE_SIZE; + if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { + return JSTaggedValue::Undefined(); + } + FrameState *breakState = GET_FRAME(newSp); + breakState->pc = nullptr; + breakState->sp = nullptr; + breakState->prev = originalPrevSp; + breakState->numActualArgs = 0; + JSTaggedType *prevSp = newSp; + + uint32_t numActualArgs = params.argc + RESERVED_CALL_ARGCOUNT; + // push method frame + uint32_t numVregs = method->GetNumVregs(); + uint32_t numDeclaredArgs = method->GetNumArgs(); + size_t frameSize = FRAME_STATE_SIZE + numVregs + std::max(numDeclaredArgs, numActualArgs); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp = prevSp - frameSize; + if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { + return JSTaggedValue::Undefined(); + } + // push args + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + RESERVED_INDEX_CALL_TARGET] = reinterpret_cast(params.callTarget); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + RESERVED_INDEX_NEW_TARGET] = params.newTarget; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + RESERVED_INDEX_THIS] = params.thisArg; + for (size_t i = 0; i < params.argc; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + i + RESERVED_CALL_ARGCOUNT] = params.argv[i]; + } + InterpreterFrameCopyArgs(newSp, numVregs, numActualArgs, numDeclaredArgs); + + const uint8_t *pc = JSMethod::Cast(method)->GetBytecodeArray(); + FrameState *state = GET_FRAME(newSp); + state->pc = pc; + state->sp = newSp; + state->method = method; + state->acc = JSTaggedValue::Hole(); + JSHandle callTargetHandle(thread, params.callTarget); + ASSERT(callTargetHandle->IsJSFunction()); + JSHandle thisFunc = JSHandle::Cast(callTargetHandle); + ConstantPool *constpool = ConstantPool::Cast(thisFunc->GetConstantPool().GetTaggedObject()); + state->constpool = constpool; + state->profileTypeInfo = thisFunc->GetProfileTypeInfo(); + state->prev = prevSp; + state->numActualArgs = numActualArgs; + + JSTaggedValue env = thisFunc->GetLexicalEnv(); + state->env = env; + + thread->SetCurrentSPFrame(newSp); + + LOG(DEBUG, INTERPRETER) << "break Entry: Runtime Call " << std::hex << reinterpret_cast(newSp) << " " + << std::hex << reinterpret_cast(pc); + + EcmaInterpreter::RunInternal(thread, constpool, pc, newSp); + + // NOLINTNEXTLINE(readability-identifier-naming) + const JSTaggedValue resAcc = state->acc; + // pop frame + thread->SetCurrentSPFrame(originalPrevSp); + + return resAcc; +} + +JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSHandle context) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle func = JSHandle::Cast(JSHandle(thread, context->GetMethod())); + JSMethod *method = func->GetCallTarget(); + + JSTaggedType *currentSp = const_cast(thread->GetCurrentSPFrame()); + + // push break frame + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSTaggedType *breakSp = currentSp - FRAME_STATE_SIZE; + if (thread->DoStackOverflowCheck(breakSp) || thread->HasPendingException()) { + return JSTaggedValue::Exception(); + } + FrameState *breakState = GET_FRAME(breakSp); + breakState->pc = nullptr; + breakState->sp = nullptr; + breakState->prev = currentSp; + breakState->numActualArgs = 0; + + // create new frame and resume sp and pc + uint32_t nregs = context->GetNRegs().GetInt(); + size_t newFrameSize = FRAME_STATE_SIZE + nregs; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic + JSTaggedType *newSp = breakSp - newFrameSize; + if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { + return JSTaggedValue::Exception(); + } + JSHandle regsArray(thread, context->GetRegsArray()); + for (size_t i = 0; i < nregs; i++) { + newSp[i] = regsArray->Get(i).GetRawData(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + } + ConstantPool *constpool = ConstantPool::Cast(func->GetConstantPool().GetTaggedObject()); + JSTaggedValue pcOffset = context->GetBCOffset(); + // pc = first_inst + offset + size(Opcode::SUSPENDGENERATOR_IMM8_V8_V8) + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + const uint8_t *resumePc = JSMethod::Cast(method)->GetBytecodeArray() + static_cast(pcOffset.GetInt()) + + BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8); + + FrameState *state = GET_FRAME(newSp); + state->pc = resumePc; + state->sp = newSp; + state->method = method; + state->constpool = constpool; + state->profileTypeInfo = func->GetProfileTypeInfo(); + state->acc = context->GetAcc(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + state->prev = breakSp; + JSTaggedValue env = context->GetLexicalEnv(); + state->env = env; + // execute interpreter + thread->SetCurrentSPFrame(newSp); + EcmaInterpreter::RunInternal(thread, constpool, resumePc, newSp); + + JSTaggedValue res = state->acc; + // pop frame + thread->SetCurrentSPFrame(currentSp); + + return res; +} + +void EcmaInterpreter::ChangeGenContext(JSThread *thread, JSHandle context) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle func = JSHandle::Cast(JSHandle(thread, context->GetMethod())); + JSMethod *method = func->GetCallTarget(); + + JSTaggedType *currentSp = const_cast(thread->GetCurrentSPFrame()); + + // push break frame + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSTaggedType *breakSp = currentSp - FRAME_STATE_SIZE; + if (thread->DoStackOverflowCheck(breakSp) || thread->HasPendingException()) { + return; + } + FrameState *breakState = GET_FRAME(breakSp); + breakState->pc = nullptr; + breakState->sp = nullptr; + breakState->prev = currentSp; + + // create new frame and resume sp and pc + uint32_t nregs = context->GetNRegs().GetInt(); + size_t newFrameSize = FRAME_STATE_SIZE + nregs; + + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic + JSTaggedType *newSp = breakSp - newFrameSize; + if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { + return; + } + JSHandle regsArray(thread, context->GetRegsArray()); + for (size_t i = 0; i < nregs; i++) { + newSp[i] = regsArray->Get(i).GetRawData(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + } + ConstantPool *constpool = ConstantPool::Cast(func->GetConstantPool().GetTaggedObject()); + JSTaggedValue pcOffset = context->GetBCOffset(); + // pc = first_inst + offset + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + const uint8_t *pc = JSMethod::Cast(method)->GetBytecodeArray() + static_cast(pcOffset.GetInt()); + + FrameState *state = GET_FRAME(newSp); + state->pc = pc; + state->sp = newSp; + state->method = method; + state->constpool = constpool; + state->profileTypeInfo = func->GetProfileTypeInfo(); + state->acc = context->GetAcc(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + state->prev = breakSp; + state->env = context->GetLexicalEnv(); + + thread->SetCurrentSPFrame(newSp); +} + +void EcmaInterpreter::ResumeContext(JSThread *thread) +{ + JSTaggedType *sp = const_cast(thread->GetCurrentSPFrame()); + FrameState *state = GET_FRAME(sp); + thread->SetCurrentSPFrame(state->prev); +} + +void EcmaInterpreter::NotifyBytecodePcChanged(JSThread *thread) +{ + EcmaFrameHandler frameHandler(thread); + for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + if (frameHandler.IsBreakFrame()) { + continue; + } + JSMethod *method = frameHandler.GetMethod(); + // Skip builtins method + if (method->IsNative()) { + continue; + } + auto bcOffset = frameHandler.GetBytecodeOffset(); + Runtime::GetCurrent()->GetNotificationManager()->BytecodePcChangedEvent(thread, method, bcOffset); + return; + } +} + +// NOLINTNEXTLINE(readability-function-size) +NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool *constpool, const uint8_t *pc, + JSTaggedType *sp) +{ + INTERPRETER_TRACE(thread, RunInternal); + uint8_t opcode = READ_INST_OP(); + JSTaggedValue acc = JSTaggedValue::Hole(); + EcmaVM *ecmaVm = thread->GetEcmaVM(); + JSHandle globalEnv = ecmaVm->GetGlobalEnv(); + JSTaggedValue globalObj = globalEnv->GetGlobalObject(); + ObjectFactory *factory = ecmaVm->GetFactory(); + + constexpr size_t numOps = 0x100; + + static std::array instDispatchTable{ +#include "templates/instruction_dispatch.inl" + }; + + static std::array debugDispatchTable{ +#include "templates/debugger_instruction_dispatch.inl" + }; + + std::array dispatchTable = instDispatchTable; + CHECK_SWITCH_TO_DEBUGGER_TABLE(); + goto *dispatchTable[opcode]; + + HANDLE_OPCODE(HANDLE_MOV_V4_V4) { + uint16_t vdst = READ_INST_4_0(); + uint16_t vsrc = READ_INST_4_1(); + LOG_INST() << "mov v" << vdst << ", v" << vsrc; + uint64_t value = GET_VREG(vsrc); + SET_VREG(vdst, value) + DISPATCH(BytecodeInstruction::Format::V4_V4); + } + + HANDLE_OPCODE(HANDLE_MOV_DYN_V8_V8) { + uint16_t vdst = READ_INST_8_0(); + uint16_t vsrc = READ_INST_8_1(); + LOG_INST() << "mov.dyn v" << vdst << ", v" << vsrc; + uint64_t value = GET_VREG(vsrc); + SET_VREG(vdst, value) + DISPATCH(BytecodeInstruction::Format::V8_V8); + } + HANDLE_OPCODE(HANDLE_MOV_DYN_V16_V16) { + uint16_t vdst = READ_INST_16_0(); + uint16_t vsrc = READ_INST_16_2(); + LOG_INST() << "mov.dyn v" << vdst << ", v" << vsrc; + uint64_t value = GET_VREG(vsrc); + SET_VREG(vdst, value) + DISPATCH(BytecodeInstruction::Format::V16_V16); + } + HANDLE_OPCODE(HANDLE_LDA_STR_ID32) { + uint32_t stringId = READ_INST_32_0(); + LOG_INST() << "lda.str " << std::hex << stringId; + SET_ACC(constpool->GetObjectFromCache(stringId)); + DISPATCH(BytecodeInstruction::Format::ID32); + } + HANDLE_OPCODE(HANDLE_JMP_IMM8) { + int8_t offset = READ_INST_8_0(); + UPDATE_HOTNESS_COUNTER(offset); + LOG_INST() << "jmp " << std::hex << static_cast(offset); + DISPATCH_OFFSET(offset); + } + HANDLE_OPCODE(HANDLE_JMP_IMM16) { + int16_t offset = READ_INST_16_0(); + UPDATE_HOTNESS_COUNTER(offset); + LOG_INST() << "jmp " << std::hex << static_cast(offset); + DISPATCH_OFFSET(offset); + } + HANDLE_OPCODE(HANDLE_JMP_IMM32) { + int32_t offset = READ_INST_32_0(); + UPDATE_HOTNESS_COUNTER(offset); + LOG_INST() << "jmp " << std::hex << offset; + DISPATCH_OFFSET(offset); + } + HANDLE_OPCODE(HANDLE_JEQZ_IMM8) { + int8_t offset = READ_INST_8_0(); + LOG_INST() << "jeqz ->\t" + << "cond jmpz " << std::hex << static_cast(offset); + if (GET_ACC() == JSTaggedValue::False() || (GET_ACC().IsInt() && GET_ACC().GetInt() == 0) || + (GET_ACC().IsDouble() && GET_ACC().GetDouble() == 0)) { + UPDATE_HOTNESS_COUNTER(offset); + DISPATCH_OFFSET(offset); + } else { + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + } + HANDLE_OPCODE(HANDLE_JEQZ_IMM16) { + int16_t offset = READ_INST_16_0(); + LOG_INST() << "jeqz ->\t" + << "cond jmpz " << std::hex << static_cast(offset); + if (GET_ACC() == JSTaggedValue::False() || (GET_ACC().IsInt() && GET_ACC().GetInt() == 0) || + (GET_ACC().IsDouble() && GET_ACC().GetDouble() == 0)) { + UPDATE_HOTNESS_COUNTER(offset); + DISPATCH_OFFSET(offset); + } else { + DISPATCH(BytecodeInstruction::Format::IMM16); + } + } + HANDLE_OPCODE(HANDLE_JNEZ_IMM8) { + int8_t offset = READ_INST_8_0(); + LOG_INST() << "jnez ->\t" + << "cond jmpz " << std::hex << static_cast(offset); + if (GET_ACC() == JSTaggedValue::True() || (GET_ACC().IsInt() && GET_ACC().GetInt() != 0) || + (GET_ACC().IsDouble() && GET_ACC().GetDouble() != 0)) { + UPDATE_HOTNESS_COUNTER(offset); + DISPATCH_OFFSET(offset); + } else { + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + } + HANDLE_OPCODE(HANDLE_JNEZ_IMM16) { + int16_t offset = READ_INST_16_0(); + LOG_INST() << "jnez ->\t" + << "cond jmpz " << std::hex << static_cast(offset); + if (GET_ACC() == JSTaggedValue::True() || (GET_ACC().IsInt() && GET_ACC().GetInt() != 0) || + (GET_ACC().IsDouble() && GET_ACC().GetDouble() != 0)) { + UPDATE_HOTNESS_COUNTER(offset); + DISPATCH_OFFSET(offset); + } else { + DISPATCH(BytecodeInstruction::Format::IMM16); + } + } + HANDLE_OPCODE(HANDLE_LDA_DYN_V8) { + uint16_t vsrc = READ_INST_8_0(); + LOG_INST() << "lda.dyn v" << vsrc; + uint64_t value = GET_VREG(vsrc); + SET_ACC(JSTaggedValue(value)) + DISPATCH(BytecodeInstruction::Format::V8); + } + HANDLE_OPCODE(HANDLE_STA_DYN_V8) { + uint16_t vdst = READ_INST_8_0(); + LOG_INST() << "sta.dyn v" << vdst; + SET_VREG(vdst, GET_ACC().GetRawData()) + DISPATCH(BytecodeInstruction::Format::V8); + } + HANDLE_OPCODE(HANDLE_LDAI_DYN_IMM32) { + int32_t imm = READ_INST_32_0(); + LOG_INST() << "ldai.dyn " << std::hex << imm; + SET_ACC(JSTaggedValue(imm)) + DISPATCH(BytecodeInstruction::Format::IMM32); + } + + HANDLE_OPCODE(HANDLE_FLDAI_DYN_IMM64) { + auto imm = bit_cast(READ_INST_64_0()); + LOG_INST() << "fldai.dyn " << imm; + SET_ACC(JSTaggedValue(imm)) + DISPATCH(BytecodeInstruction::Format::IMM64); + } + { + uint32_t actualNumArgs; + uint32_t funcReg; + bool callThis; + bool callRange; + + HANDLE_OPCODE(HANDLE_CALLARG0DYN_PREF_V8) { + funcReg = READ_INST_8_1(); + actualNumArgs = ActualNumArgsOfCall::CALLARG0; + + LOG_INST() << "callarg0.dyn " + << "v" << funcReg; + callRange = false; + callThis = false; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) + goto handlerCall; + } + HANDLE_OPCODE(HANDLE_CALLARG1DYN_PREF_V8_V8) { + funcReg = READ_INST_8_1(); + actualNumArgs = ActualNumArgsOfCall::CALLARG1; + + LOG_INST() << "callarg1.dyn " + << "v" << funcReg << ", v" << READ_INST_8_2(); + callRange = false; + callThis = false; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) + goto handlerCall; + } + HANDLE_OPCODE(HANDLE_CALLARGS2DYN_PREF_V8_V8_V8) { + funcReg = READ_INST_8_1(); + actualNumArgs = ActualNumArgsOfCall::CALLARGS2; + + LOG_INST() << "callargs2.dyn " + << "v" << funcReg << ", v" << READ_INST_8_2() << ", v" << READ_INST_8_3(); + callRange = false; + callThis = false; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) + goto handlerCall; + } + HANDLE_OPCODE(HANDLE_CALLARGS3DYN_PREF_V8_V8_V8_V8) { + funcReg = READ_INST_8_1(); + actualNumArgs = ActualNumArgsOfCall::CALLARGS3; + + LOG_INST() << "callargs3.dyn " + << "v" << funcReg << ", v" << READ_INST_8_2() << ", v" << READ_INST_8_3() + << ", v" << READ_INST_8_4(); + callRange = false; + callThis = false; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) + goto handlerCall; + } + HANDLE_OPCODE(HANDLE_CALLITHISRANGEDYN_PREF_IMM16_V8) { + actualNumArgs = READ_INST_16_1() + 2; // 2: func and newTarget + funcReg = READ_INST_8_3(); + + LOG_INST() << "calli.dyn.this.range " << actualNumArgs << ", v" << funcReg; + callRange = true; + callThis = true; + // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) + goto handlerCall; + } + HANDLE_OPCODE(HANDLE_CALLSPREADDYN_PREF_V8_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + uint16_t v2 = READ_INST_8_3(); + LOG_INST() << "intrinsics::callspreaddyn" + << " v" << v0 << " v" << v1 << " v" << v2; + JSTaggedValue func = GET_VREG_VALUE(v0); + JSTaggedValue obj = GET_VREG_VALUE(v1); + JSTaggedValue array = GET_VREG_VALUE(v2); + + JSTaggedValue res = SlowRuntimeStub::CallSpreadDyn(thread, func, obj, array); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8); + } + HANDLE_OPCODE(HANDLE_CALLIRANGEDYN_PREF_IMM16_V8) { + actualNumArgs = READ_INST_16_1() + NUM_MANDATORY_JSFUNC_ARGS; + funcReg = READ_INST_8_3(); + callRange = true; + callThis = false; + LOG_INST() << "calli.rangedyn " << actualNumArgs << ", v" << funcReg; + + handlerCall: + JSTaggedValue func = GET_VREG_VALUE(funcReg); + if (!func.IsCallable()) { + { + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle error = factory->GetJSError(ErrorType::TYPE_ERROR, "is not callable"); + thread->SetException(error.GetTaggedValue()); + } + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + ECMAObject *thisFunc = ECMAObject::Cast(func.GetTaggedObject()); + JSMethod *methodToCall = thisFunc->GetCallTarget(); + if (methodToCall->IsNative()) { + ASSERT(methodToCall->GetNumVregs() == 0); + // Tags and values of thread, new_tgt and argv_length are put into frames too for native frames + // NOLINTNEXTLINE(hicpp-signed-bitwise) + size_t frameSize = FRAME_STATE_SIZE + actualNumArgs; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSTaggedType *newSp = sp - frameSize; + if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, actualNumArgs, + reinterpret_cast(newSp)); + uint32_t startIdx = 0; + // func + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = static_cast(ToUintPtr(thisFunc)); + // new target + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; + + if (callRange) { + size_t copyArgs = actualNumArgs - 2; // 2: skip func and new target + if (!callThis) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; + // skip this + copyArgs--; + } + for (size_t i = 1; i <= copyArgs; i++) { + JSTaggedValue arg = GET_VREG_VALUE(funcReg + i); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = arg.GetRawData(); + } + } else { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx] = JSTaggedValue::VALUE_UNDEFINED; + switch (actualNumArgs) { + case ActualNumArgsOfCall::CALLARGS3: { + uint32_t reg = READ_INST_8_4(); + JSTaggedValue arg = GET_VREG_VALUE(reg); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[ActualNumArgsOfCall::CALLARGS3 - 1] = arg.GetRawData(); + [[fallthrough]]; + } + case ActualNumArgsOfCall::CALLARGS2: { + uint32_t reg = READ_INST_8_3(); + JSTaggedValue arg = GET_VREG_VALUE(reg); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[ActualNumArgsOfCall::CALLARGS2 - 1] = arg.GetRawData(); + [[fallthrough]]; + } + case ActualNumArgsOfCall::CALLARG1: { + uint32_t reg = READ_INST_8_2(); + JSTaggedValue arg = GET_VREG_VALUE(reg); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[ActualNumArgsOfCall::CALLARG1 - 1] = arg.GetRawData(); + break; + } + case ActualNumArgsOfCall::CALLARG0: { + break; + } + default: + UNREACHABLE(); + } + } + + FrameState *state = GET_FRAME(newSp); + state->prev = sp; + state->pc = nullptr; + state->sp = newSp; + state->method = methodToCall; + thread->SetCurrentSPFrame(newSp); + LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call."; + JSTaggedValue retValue = reinterpret_cast( + const_cast(methodToCall->GetNativePointer()))(&ecmaRuntimeCallInfo); + if (UNLIKELY(thread->HasPendingException())) { + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call."; + thread->SetCurrentSPFrame(sp); + SET_ACC(retValue); + size_t jumpSize = GetJumpSizeAfterCall(pc); + DISPATCH_OFFSET(jumpSize); + } else { + if (JSFunction::Cast(thisFunc)->IsClassConstructor()) { + { + [[maybe_unused]] EcmaHandleScope handleScope(thread); + JSHandle error = + factory->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot called without 'new'"); + thread->SetException(error.GetTaggedValue()); + } + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + SAVE_PC(); + uint32_t numVregs = methodToCall->GetNumVregs(); + uint32_t numDeclaredArgs = methodToCall->GetNumArgs(); + size_t frameSize = FRAME_STATE_SIZE + numVregs + std::max(numDeclaredArgs, actualNumArgs); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + JSTaggedType *newSp = sp - frameSize; + if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + + // copy args + uint32_t startIdx = numVregs; + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = static_cast(ToUintPtr(thisFunc)); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; + if (callRange) { + size_t copyArgs = actualNumArgs - 2; // 2: skip func and new target + if (!callThis) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; + // skip this + copyArgs--; + } + for (size_t i = 1; i <= copyArgs; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx++] = sp[funcReg + i]; + } + } else { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[startIdx] = JSTaggedValue::VALUE_UNDEFINED; + switch (actualNumArgs) { + case ActualNumArgsOfCall::CALLARGS3: { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + ActualNumArgsOfCall::CALLARGS3 - 1] = sp[READ_INST_8_4()]; + [[fallthrough]]; + } + case ActualNumArgsOfCall::CALLARGS2: { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + ActualNumArgsOfCall::CALLARGS2 - 1] = sp[READ_INST_8_3()]; + [[fallthrough]]; + } + case ActualNumArgsOfCall::CALLARG1: { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + ActualNumArgsOfCall::CALLARG1 - 1] = sp[READ_INST_8_2()]; + break; + } + case ActualNumArgsOfCall::CALLARG0: { + break; + } + default: + UNREACHABLE(); + } + } + InterpreterFrameCopyArgs(newSp, numVregs, actualNumArgs, numDeclaredArgs); + + FrameState *state = GET_FRAME(newSp); + state->prev = sp; + state->pc = pc = JSMethod::Cast(methodToCall)->GetBytecodeArray(); + state->sp = sp = newSp; + state->method = methodToCall; + state->acc = JSTaggedValue::Hole(); + state->constpool = constpool = + ConstantPool::Cast(JSFunction::Cast(thisFunc)->GetConstantPool().GetTaggedObject()); + state->profileTypeInfo = JSFunction::Cast(thisFunc)->GetProfileTypeInfo(); + state->numActualArgs = actualNumArgs; + JSTaggedValue env = JSFunction::Cast(thisFunc)->GetLexicalEnv(); + state->env = env; + + thread->SetCurrentSPFrame(newSp); + LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call " << std::hex << reinterpret_cast(sp) << " " + << std::hex << reinterpret_cast(pc); + DISPATCH_OFFSET(0); + } + } + } + HANDLE_OPCODE(HANDLE_RETURN_DYN) { + LOG_INST() << "return.dyn"; + FrameState *state = GET_FRAME(sp); + LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call " << std::hex << reinterpret_cast(state->sp) << " " + << std::hex << reinterpret_cast(state->pc); + [[maybe_unused]] auto fistPC = state->method->GetInstructions(); + UPDATE_HOTNESS_COUNTER(-(pc - fistPC)); + sp = state->prev; + ASSERT(sp != nullptr); + FrameState *prevState = GET_FRAME(sp); + pc = prevState->pc; + + // break frame + if (pc == nullptr) { + state->acc = acc; + return; + } + thread->SetCurrentSPFrame(sp); + + constpool = prevState->constpool; + + size_t jumpSize = GetJumpSizeAfterCall(pc); + DISPATCH_OFFSET(jumpSize); + } + HANDLE_OPCODE(HANDLE_RETURNUNDEFINED_PREF) { + LOG_INST() << "return.undefined"; + FrameState *state = GET_FRAME(sp); + LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call " << std::hex << reinterpret_cast(sp) << " " + << std::hex << reinterpret_cast(state->pc); + [[maybe_unused]] auto fistPC = state->method->GetInstructions(); + UPDATE_HOTNESS_COUNTER_NON_ACC(-(pc - fistPC)); + sp = state->prev; + ASSERT(sp != nullptr); + FrameState *prevState = GET_FRAME(sp); + pc = prevState->pc; + + // break frame + if (pc == nullptr) { + state->acc = JSTaggedValue::Undefined(); + return; + } + thread->SetCurrentSPFrame(sp); + + constpool = prevState->constpool; + + acc = JSTaggedValue::Undefined(); + size_t jumpSize = GetJumpSizeAfterCall(pc); + DISPATCH_OFFSET(jumpSize); + } + HANDLE_OPCODE(HANDLE_LDNAN_PREF) { + LOG_INST() << "intrinsics::ldnan"; + SET_ACC(JSTaggedValue(base::NAN_VALUE)); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDINFINITY_PREF) { + LOG_INST() << "intrinsics::ldinfinity"; + SET_ACC(JSTaggedValue(base::POSITIVE_INFINITY)); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDGLOBALTHIS_PREF) { + LOG_INST() << "intrinsics::ldglobalthis"; + SET_ACC(globalObj) + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDUNDEFINED_PREF) { + LOG_INST() << "intrinsics::ldundefined"; + SET_ACC(JSTaggedValue::Undefined()) + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDNULL_PREF) { + LOG_INST() << "intrinsics::ldnull"; + SET_ACC(JSTaggedValue::Null()) + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDSYMBOL_PREF) { + LOG_INST() << "intrinsics::ldsymbol"; + SET_ACC(globalEnv->GetSymbolFunction().GetTaggedValue()); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDGLOBAL_PREF) { + LOG_INST() << "intrinsics::ldglobal"; + SET_ACC(globalObj) + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDTRUE_PREF) { + LOG_INST() << "intrinsics::ldtrue"; + SET_ACC(JSTaggedValue::True()) + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDFALSE_PREF) { + LOG_INST() << "intrinsics::ldfalse"; + SET_ACC(JSTaggedValue::False()) + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_LDLEXENVDYN_PREF) { + LOG_INST() << "intrinsics::ldlexenvDyn "; + FrameState *state = GET_FRAME(sp); + JSTaggedValue currentLexenv = state->env; + SET_ACC(currentLexenv); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_GETUNMAPPEDARGS_PREF) { + LOG_INST() << "intrinsics::getunmappedargs"; + + FrameState *state = GET_FRAME(sp); + uint32_t numVregs = state->method->GetNumVregs(); + // Exclude func, newTarget and "this" + uint32_t actualNumArgs = state->numActualArgs - NUM_MANDATORY_JSFUNC_ARGS; + uint32_t startIdx = numVregs + NUM_MANDATORY_JSFUNC_ARGS; + + JSTaggedValue res = SlowRuntimeStub::GetUnmapedArgs(thread, sp, actualNumArgs, startIdx); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONENTER_PREF) { + LOG_INST() << "intrinsics::asyncfunctionenter"; + JSTaggedValue res = SlowRuntimeStub::AsyncFunctionEnter(thread); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_TONUMBER_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::tonumber" + << " v" << v0; + JSTaggedValue value = GET_VREG_VALUE(v0); + if (value.IsNumber()) { + // fast path + SET_ACC(value); + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::ToNumber(thread, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_NEGDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::negdyn" + << " v" << v0; + JSTaggedValue value = GET_VREG_VALUE(v0); + // fast path + if (value.IsInt()) { + if (value.GetInt() == 0) { + SET_ACC(JSTaggedValue(-0.0)); + } else { + SET_ACC(JSTaggedValue(-value.GetInt())); + } + } else if (value.IsDouble()) { + SET_ACC(JSTaggedValue(-value.GetDouble())); + } else { // slow path + JSTaggedValue res = SlowRuntimeStub::NegDyn(thread, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_NOTDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::notdyn" + << " v" << v0; + JSTaggedValue value = GET_VREG_VALUE(v0); + int32_t number; + // number, fast path + if (value.IsInt()) { + number = static_cast(value.GetInt()); + SET_ACC(JSTaggedValue(~number)); // NOLINT(hicpp-signed-bitwise) + } else if (value.IsDouble()) { + number = base::NumberHelper::DoubleToInt(value.GetDouble(), base::INT32_BITS); + SET_ACC(JSTaggedValue(~number)); // NOLINT(hicpp-signed-bitwise) + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::NotDyn(thread, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_INCDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::incdyn" + << " v" << v0; + + JSTaggedValue value = GET_VREG_VALUE(v0); + // number fast path + if (value.IsInt()) { + int32_t a0 = value.GetInt(); + if (UNLIKELY(a0 == INT32_MAX)) { + auto ret = static_cast(a0) + 1.0; + SET_ACC(JSTaggedValue(ret)) + } else { + SET_ACC(JSTaggedValue(a0 + 1)) + } + } else if (value.IsDouble()) { + SET_ACC(JSTaggedValue(value.GetDouble() + 1.0)) + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::IncDyn(thread, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_DECDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::decdyn" + << " v" << v0; + + JSTaggedValue value = GET_VREG_VALUE(v0); + // number, fast path + if (value.IsInt()) { + int32_t a0 = value.GetInt(); + if (UNLIKELY(a0 == INT32_MIN)) { + auto ret = static_cast(a0) - 1.0; + SET_ACC(JSTaggedValue(ret)) + } else { + SET_ACC(JSTaggedValue(a0 - 1)) + } + } else if (value.IsDouble()) { + SET_ACC(JSTaggedValue(value.GetDouble() - 1.0)) + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::DecDyn(thread, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_THROWDYN_PREF) { + LOG_INST() << "intrinsics::throwdyn"; + SlowRuntimeStub::ThrowDyn(thread, GET_ACC()); + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + HANDLE_OPCODE(HANDLE_TYPEOFDYN_PREF) { + LOG_INST() << "intrinsics::typeofdyn"; + JSTaggedValue res = FastRuntimeStub::FastTypeOf(thread, GET_ACC()); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_GETPROPITERATOR_PREF) { + LOG_INST() << "intrinsics::getpropiterator"; + JSTaggedValue res = SlowRuntimeStub::GetPropIterator(thread, GET_ACC()); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_RESUMEGENERATOR_PREF_V8) { + LOG_INST() << "intrinsics::resumegenerator"; + uint16_t vs = READ_INST_8_1(); + JSGeneratorObject *obj = JSGeneratorObject::Cast(GET_VREG_VALUE(vs).GetTaggedObject()); + SET_ACC(obj->GetResumeResult()); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_GETRESUMEMODE_PREF_V8) { + LOG_INST() << "intrinsics::getresumemode"; + uint16_t vs = READ_INST_8_1(); + JSGeneratorObject *obj = JSGeneratorObject::Cast(GET_VREG_VALUE(vs).GetTaggedObject()); + SET_ACC(obj->GetResumeMode()); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_GETITERATOR_PREF) { + LOG_INST() << "intrinsics::getiterator"; + JSTaggedValue obj = GET_ACC(); + + // fast path: Generator obj is already store in acc + if (!obj.IsGeneratorObject()) { + // slow path + JSTaggedValue res = SlowRuntimeStub::GetIterator(thread, obj); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_THROWCONSTASSIGNMENT_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "throwconstassignment" + << " v" << v0; + SlowRuntimeStub::ThrowConstAssignment(thread, GET_VREG_VALUE(v0)); + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + HANDLE_OPCODE(HANDLE_THROWTHROWNOTEXISTS_PREF) { + LOG_INST() << "throwthrownotexists"; + + SlowRuntimeStub::ThrowThrowNotExists(thread); + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + HANDLE_OPCODE(HANDLE_THROWPATTERNNONCOERCIBLE_PREF) { + LOG_INST() << "throwpatternnoncoercible"; + + SlowRuntimeStub::ThrowPatternNonCoercible(thread); + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + HANDLE_OPCODE(HANDLE_THROWIFNOTOBJECT_PREF_V8) { + LOG_INST() << "throwifnotobject"; + uint16_t v0 = READ_INST_8_1(); + + JSTaggedValue value = GET_VREG_VALUE(v0); + // fast path + if (value.IsECMAObject()) { + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + + // slow path + SlowRuntimeStub::ThrowIfNotObject(thread); + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + HANDLE_OPCODE(HANDLE_ITERNEXT_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::iternext" + << " v" << v0; + JSTaggedValue iter = GET_VREG_VALUE(v0); + JSTaggedValue res = SlowRuntimeStub::IterNext(thread, iter); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_CLOSEITERATOR_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::closeiterator" + << " v" << v0; + JSTaggedValue iter = GET_VREG_VALUE(v0); + JSTaggedValue res = SlowRuntimeStub::CloseIterator(thread, iter); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_ADD2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::add2dyn" + << " v" << v0; + int32_t a0; + int32_t a1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + // number, fast path + if (left.IsInt() && right.IsInt()) { + a0 = left.GetInt(); + a1 = right.GetInt(); + if ((a0 > 0 && a1 > INT32_MAX - a0) || (a0 < 0 && a1 < INT32_MIN - a0)) { + auto ret = static_cast(a0) + static_cast(a1); + SET_ACC(JSTaggedValue(ret)) + } else { + SET_ACC(JSTaggedValue(a0 + a1)) + } + } else if (left.IsNumber() && right.IsNumber()) { + double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble(); + double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble(); + double ret = a0Double + a1Double; + SET_ACC(JSTaggedValue(ret)) + } else { + // one or both are not number, slow path + JSTaggedValue res = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_SUB2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::sub2dyn" + << " v" << v0; + int32_t a0; + int32_t a1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + if (left.IsInt() && right.IsInt()) { + a0 = left.GetInt(); + a1 = -right.GetInt(); + if ((a0 > 0 && a1 > INT32_MAX - a0) || (a0 < 0 && a1 < INT32_MIN - a0)) { + auto ret = static_cast(a0) + static_cast(a1); + SET_ACC(JSTaggedValue(ret)) + } else { + SET_ACC(JSTaggedValue(a0 + a1)) + } + } else if (left.IsNumber() && right.IsNumber()) { + double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble(); + double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble(); + double ret = a0Double - a1Double; + SET_ACC(JSTaggedValue(ret)) + } else { + // one or both are not number, slow path + JSTaggedValue res = SlowRuntimeStub::Sub2Dyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_MUL2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::mul2dyn" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = acc; + JSTaggedValue value = FastRuntimeStub::FastMul(left, right); + if (!value.IsHole()) { + SET_ACC(value); + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::Mul2Dyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_DIV2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::div2dyn" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = acc; + // fast path + JSTaggedValue res = FastRuntimeStub::FastDiv(left, right); + if (!res.IsHole()) { + SET_ACC(res); + } else { + // slow path + JSTaggedValue slowRes = SlowRuntimeStub::Div2Dyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(slowRes); + SET_ACC(slowRes); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_MOD2DYN_PREF_V8) { + uint16_t vs = READ_INST_8_1(); + LOG_INST() << "intrinsics::mod2dyn" + << " v" << vs; + JSTaggedValue left = GET_VREG_VALUE(vs); + JSTaggedValue right = GET_ACC(); + // fast path + JSTaggedValue res = FastRuntimeStub::FastMod(left, right); + if (!res.IsHole()) { + SET_ACC(res); + } else { + // slow path + JSTaggedValue slowRes = SlowRuntimeStub::Mod2Dyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(slowRes); + SET_ACC(slowRes); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_EQDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::eqdyn" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = acc; + JSTaggedValue res = FastRuntimeStub::FastEqual(left, right); + if (!res.IsHole()) { + SET_ACC(res); + } else { + // slow path + res = SlowRuntimeStub::EqDyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_NOTEQDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::noteqdyn" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = acc; + + JSTaggedValue res = FastRuntimeStub::FastEqual(left, right); + if (!res.IsHole()) { + res = res.IsTrue() ? JSTaggedValue::False() : JSTaggedValue::True(); + SET_ACC(res); + } else { + // slow path + res = SlowRuntimeStub::NotEqDyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_LESSDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::lessdyn" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + if (left.IsNumber() && right.IsNumber()) { + // fast path + double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); + double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); + bool ret = JSTaggedValue::StrictNumberCompare(valueA, valueB) == ComparisonResult::LESS; + SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::LessDyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_LESSEQDYN_PREF_V8) { + uint16_t vs = READ_INST_8_1(); + LOG_INST() << "intrinsics::lesseqdyn " + << " v" << vs; + JSTaggedValue left = GET_VREG_VALUE(vs); + JSTaggedValue right = GET_ACC(); + if (left.IsNumber() && right.IsNumber()) { + // fast path + double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); + double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); + bool ret = JSTaggedValue::StrictNumberCompare(valueA, valueB) <= ComparisonResult::EQUAL; + SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::LessEqDyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_GREATERDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::greaterdyn" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = acc; + if (left.IsNumber() && right.IsNumber()) { + // fast path + double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); + double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); + bool ret = JSTaggedValue::StrictNumberCompare(valueA, valueB) == ComparisonResult::GREAT; + SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::GreaterDyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_GREATEREQDYN_PREF_V8) { + uint16_t vs = READ_INST_8_1(); + LOG_INST() << "intrinsics::greateqdyn " + << " v" << vs; + JSTaggedValue left = GET_VREG_VALUE(vs); + JSTaggedValue right = GET_ACC(); + if (left.IsNumber() && right.IsNumber()) { + // fast path + double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); + double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); + ComparisonResult comparison = JSTaggedValue::StrictNumberCompare(valueA, valueB); + bool ret = (comparison == ComparisonResult::GREAT) || (comparison == ComparisonResult::EQUAL); + SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::GreaterEqDyn(thread, left, right); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_SHL2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::shl2dyn" + << " v" << v0; + int32_t opNumber0; + int32_t opNumber1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + // both number, fast path + if (left.IsInt() && right.IsInt()) { + opNumber0 = left.GetInt(); + opNumber1 = right.GetInt(); + } else if (left.IsNumber() && right.IsNumber()) { + opNumber0 = + left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); + opNumber1 = + right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); + } else { + // slow path + SAVE_ACC(); + JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); + RESTORE_ACC(); + right = GET_ACC(); // Maybe moved by GC + JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, right); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); + opNumber0 = taggedNumber0.GetInt(); + opNumber1 = taggedNumber1.GetInt(); + } + + uint32_t shift = + static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) + using unsigned_type = std::make_unsigned_t; + auto ret = + static_cast(static_cast(opNumber0) << shift); // NOLINT(hicpp-signed-bitwise) + SET_ACC(JSTaggedValue(ret)) + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_SHR2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::shr2dyn" + << " v" << v0; + int32_t opNumber0; + int32_t opNumber1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + // both number, fast path + if (left.IsInt() && right.IsInt()) { + opNumber0 = left.GetInt(); + opNumber1 = right.GetInt(); + } else if (left.IsNumber() && right.IsNumber()) { + opNumber0 = + left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); + opNumber1 = + right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); + } else { + // slow path + SAVE_ACC(); + JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); + RESTORE_ACC(); + right = GET_ACC(); // Maybe moved by GC + JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, right); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); + opNumber0 = taggedNumber0.GetInt(); + opNumber1 = taggedNumber1.GetInt(); + } + + uint32_t shift = + static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) + auto ret = static_cast(opNumber0 >> shift); // NOLINT(hicpp-signed-bitwise) + SET_ACC(JSTaggedValue(ret)) + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_ASHR2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::ashr2dyn" + << " v" << v0; + int32_t opNumber0; + int32_t opNumber1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + if (left.IsInt() && right.IsInt()) { + opNumber0 = left.GetInt(); + opNumber1 = right.GetInt(); + } else if (left.IsNumber() && right.IsNumber()) { + opNumber0 = + left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); + opNumber1 = + right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); + } else { + // slow path + SAVE_ACC(); + JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, left); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); + RESTORE_ACC(); + right = GET_ACC(); // Maybe moved by GC + JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, right); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); + opNumber0 = taggedNumber0.GetInt(); + opNumber1 = taggedNumber1.GetInt(); + } + + uint32_t shift = + static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) + using unsigned_type = std::make_unsigned_t; + auto ret = + static_cast(static_cast(opNumber0) >> shift); // NOLINT(hicpp-signed-bitwise) + SET_ACC(JSTaggedValue(ret)) + + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_AND2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::and2dyn" + << " v" << v0; + int32_t opNumber0; + int32_t opNumber1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + // both number, fast path + if (left.IsInt() && right.IsInt()) { + opNumber0 = left.GetInt(); + opNumber1 = right.GetInt(); + } else if (left.IsNumber() && right.IsNumber()) { + opNumber0 = + left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); + opNumber1 = + right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); + } else { + // slow path + SAVE_ACC(); + JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); + RESTORE_ACC(); + right = GET_ACC(); // Maybe moved by GC + JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, right); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); + opNumber0 = taggedNumber0.GetInt(); + opNumber1 = taggedNumber1.GetInt(); + } + // NOLINT(hicpp-signed-bitwise) + auto ret = static_cast(opNumber0) & static_cast(opNumber1); + SET_ACC(JSTaggedValue(static_cast(ret))) + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_OR2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::or2dyn" + << " v" << v0; + int32_t opNumber0; + int32_t opNumber1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + // both number, fast path + if (left.IsInt() && right.IsInt()) { + opNumber0 = left.GetInt(); + opNumber1 = right.GetInt(); + } else if (left.IsNumber() && right.IsNumber()) { + opNumber0 = + left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); + opNumber1 = + right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); + } else { + // slow path + SAVE_ACC(); + JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); + RESTORE_ACC(); + right = GET_ACC(); // Maybe moved by GC + JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, right); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); + opNumber0 = taggedNumber0.GetInt(); + opNumber1 = taggedNumber1.GetInt(); + } + // NOLINT(hicpp-signed-bitwise) + auto ret = static_cast(opNumber0) | static_cast(opNumber1); + SET_ACC(JSTaggedValue(static_cast(ret))) + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_XOR2DYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + + LOG_INST() << "intrinsics::xor2dyn" + << " v" << v0; + int32_t opNumber0; + int32_t opNumber1; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + // both number, fast path + if (left.IsInt() && right.IsInt()) { + opNumber0 = left.GetInt(); + opNumber1 = right.GetInt(); + } else if (left.IsNumber() && right.IsNumber()) { + opNumber0 = + left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); + opNumber1 = + right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); + } else { + // slow path + SAVE_ACC(); + JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); + RESTORE_ACC(); + right = GET_ACC(); // Maybe moved by GC + JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, right); + INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); + opNumber0 = taggedNumber0.GetInt(); + opNumber1 = taggedNumber1.GetInt(); + } + // NOLINT(hicpp-signed-bitwise) + auto ret = static_cast(opNumber0) ^ static_cast(opNumber1); + SET_ACC(JSTaggedValue(static_cast(ret))) + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_DELOBJPROP_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::delobjprop" + << " v0" << v0 << " v1" << v1; + + JSTaggedValue obj = GET_VREG_VALUE(v0); + JSTaggedValue prop = GET_VREG_VALUE(v1); + JSTaggedValue res = SlowRuntimeStub::DelObjProp(thread, obj, prop); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_DEFINEFUNCDYN_PREF_ID16_IMM16_V8) { + uint16_t methodId = READ_INST_16_1(); + uint16_t length = READ_INST_16_3(); + uint16_t v0 = READ_INST_8_5(); + LOG_INST() << "intrinsics::definefuncDyn length: " << length + << " v" << v0; + JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); + ASSERT(result != nullptr); + if (result->IsResolved()) { + auto res = SlowRuntimeStub::DefinefuncDyn(thread, result); + INTERPRETER_RETURN_IF_ABRUPT(res); + result = JSFunction::Cast(res.GetTaggedObject()); + result->SetConstantPool(thread, JSTaggedValue(constpool)); + } else { + result->SetResolved(thread); + } + + result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); + JSTaggedValue envHandle = GET_VREG_VALUE(v0); + result->SetLexicalEnv(thread, envHandle); + SET_ACC(JSTaggedValue(result)) + + DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_DEFINENCFUNCDYN_PREF_ID16_IMM16_V8) { + uint16_t methodId = READ_INST_16_1(); + uint16_t length = READ_INST_16_3(); + uint16_t v0 = READ_INST_8_5(); + JSTaggedValue homeObject = GET_ACC(); + LOG_INST() << "intrinsics::definencfuncDyn length: " << length + << " v" << v0; + JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); + ASSERT(result != nullptr); + if (result->IsResolved()) { + auto res = SlowRuntimeStub::DefineNCFuncDyn(thread, result); + INTERPRETER_RETURN_IF_ABRUPT(res); + result = JSFunction::Cast(res.GetTaggedObject()); + result->SetConstantPool(thread, JSTaggedValue(constpool)); + } else { + result->SetResolved(thread); + } + + result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); + JSTaggedValue env = GET_VREG_VALUE(v0); + result->SetLexicalEnv(thread, env); + result->SetHomeObject(thread, homeObject); + SET_ACC(JSTaggedValue(result)); + + DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_DEFINEMETHOD_PREF_ID16_IMM16_V8) { + uint16_t methodId = READ_INST_16_1(); + uint16_t length = READ_INST_16_3(); + uint16_t v0 = READ_INST_8_5(); + JSTaggedValue homeObject = GET_ACC(); + LOG_INST() << "intrinsics::definemethod length: " << length + << " v" << v0; + JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); + ASSERT(result != nullptr); + if (result->IsResolved()) { + auto res = SlowRuntimeStub::DefineMethod(thread, result, homeObject); + INTERPRETER_RETURN_IF_ABRUPT(res); + result = JSFunction::Cast(res.GetTaggedObject()); + result->SetConstantPool(thread, JSTaggedValue(constpool)); + } else { + result->SetHomeObject(thread, homeObject); + result->SetResolved(thread); + } + + result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); + JSTaggedValue taggedCurEnv = GET_VREG_VALUE(v0); + result->SetLexicalEnv(thread, taggedCurEnv); + SET_ACC(JSTaggedValue(result)); + + DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_NEWOBJDYNRANGE_PREF_IMM16_V8) { + uint16_t numArgs = READ_INST_16_1(); + uint16_t firstArgRegIdx = READ_INST_8_3(); + LOG_INST() << "intrinsics::newobjDynrange " << numArgs << " v" << firstArgRegIdx; + + constexpr uint16_t firstArgOffset = 2; + JSTaggedValue func = GET_VREG_VALUE(firstArgRegIdx); + JSTaggedValue newTarget = GET_VREG_VALUE(firstArgRegIdx + 1); + // Exclude func and newTarget + uint16_t firstArgIdx = firstArgRegIdx + firstArgOffset; + uint16_t length = numArgs - firstArgOffset; + + JSTaggedValue res = SlowRuntimeStub::NewObjDynRange(thread, func, newTarget, firstArgIdx, length); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_EXPDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::expdyn" + << " v" << v0; + JSTaggedValue base = GET_VREG_VALUE(v0); + JSTaggedValue exponent = GET_ACC(); + if (base.IsNumber() && exponent.IsNumber()) { + // fast path + double doubleBase = base.IsInt() ? base.GetInt() : base.GetDouble(); + double doubleExponent = exponent.IsInt() ? exponent.GetInt() : exponent.GetDouble(); + if (std::abs(doubleBase) == 1 && std::isinf(doubleExponent)) { + SET_ACC(JSTaggedValue(base::NAN_VALUE)); + } + if ((doubleBase == 0 && + ((bit_cast(doubleBase)) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK) && + std::isfinite(doubleExponent) && base::NumberHelper::TruncateDouble(doubleExponent) == doubleExponent && + base::NumberHelper::TruncateDouble(doubleExponent / 2) + base::HALF == // 2 : half + (doubleExponent / 2)) { // 2 : half + if (doubleExponent > 0) { + SET_ACC(JSTaggedValue(-0.0)); + } + if (doubleExponent < 0) { + SET_ACC(JSTaggedValue(-base::POSITIVE_INFINITY)); + } + } + SET_ACC(JSTaggedValue(std::pow(doubleBase, doubleExponent))); + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::ExpDyn(thread, base, exponent); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_ISINDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::isindyn" + << " v" << v0; + JSTaggedValue prop = GET_VREG_VALUE(v0); + JSTaggedValue obj = GET_ACC(); + JSTaggedValue res = SlowRuntimeStub::IsInDyn(thread, prop, obj); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_INSTANCEOFDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::instanceofdyn" + << " v" << v0; + JSTaggedValue obj = GET_VREG_VALUE(v0); + JSTaggedValue target = GET_ACC(); + JSTaggedValue res = SlowRuntimeStub::InstanceofDyn(thread, obj, target); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_STRICTNOTEQDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::strictnoteq" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + bool res = FastRuntimeStub::FastStrictEqual(left, right); + SET_ACC(JSTaggedValue(!res)); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_STRICTEQDYN_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::stricteq" + << " v" << v0; + JSTaggedValue left = GET_VREG_VALUE(v0); + JSTaggedValue right = GET_ACC(); + bool res = FastRuntimeStub::FastStrictEqual(left, right); + SET_ACC(JSTaggedValue(res)); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_LDLEXVARDYN_PREF_IMM16_IMM16) { + uint16_t level = READ_INST_16_1(); + uint16_t slot = READ_INST_16_3(); + + LOG_INST() << "intrinsics::ldlexvardyn" + << " level:" << level << " slot:" << slot; + FrameState *state = GET_FRAME(sp); + JSTaggedValue currentLexenv = state->env; + JSTaggedValue env(currentLexenv); + for (int i = 0; i < level; i++) { + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); + ASSERT(!taggedParentEnv.IsUndefined()); + env = taggedParentEnv; + } + SET_ACC(LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot)); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16_IMM16); + } + HANDLE_OPCODE(HANDLE_LDLEXVARDYN_PREF_IMM8_IMM8) { + uint16_t level = READ_INST_8_1(); + uint16_t slot = READ_INST_8_2(); + + LOG_INST() << "intrinsics::ldlexvardyn" + << " level:" << level << " slot:" << slot; + FrameState *state = GET_FRAME(sp); + JSTaggedValue currentLexenv = state->env; + JSTaggedValue env(currentLexenv); + for (int i = 0; i < level; i++) { + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); + ASSERT(!taggedParentEnv.IsUndefined()); + env = taggedParentEnv; + } + SET_ACC(LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot)); + DISPATCH(BytecodeInstruction::Format::PREF_IMM8_IMM8); + } + HANDLE_OPCODE(HANDLE_LDLEXVARDYN_PREF_IMM4_IMM4) { + uint16_t level = READ_INST_4_2(); + uint16_t slot = READ_INST_4_3(); + + LOG_INST() << "intrinsics::ldlexvardyn" + << " level:" << level << " slot:" << slot; + FrameState *state = GET_FRAME(sp); + JSTaggedValue currentLexenv = state->env; + JSTaggedValue env(currentLexenv); + for (int i = 0; i < level; i++) { + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); + ASSERT(!taggedParentEnv.IsUndefined()); + env = taggedParentEnv; + } + SET_ACC(LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot)); + DISPATCH(BytecodeInstruction::Format::PREF_IMM4_IMM4); + } + HANDLE_OPCODE(HANDLE_STLEXVARDYN_PREF_IMM16_IMM16_V8) { + uint16_t level = READ_INST_16_1(); + uint16_t slot = READ_INST_16_3(); + uint16_t v0 = READ_INST_8_5(); + LOG_INST() << "intrinsics::stlexvardyn" + << " level:" << level << " slot:" << slot << " v" << v0; + + JSTaggedValue value = GET_VREG_VALUE(v0); + FrameState *state = GET_FRAME(sp); + JSTaggedValue env = state->env; + for (int i = 0; i < level; i++) { + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); + ASSERT(!taggedParentEnv.IsUndefined()); + env = taggedParentEnv; + } + LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(thread, slot, value); + + DISPATCH(BytecodeInstruction::Format::PREF_IMM16_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_STLEXVARDYN_PREF_IMM8_IMM8_V8) { + uint16_t level = READ_INST_8_1(); + uint16_t slot = READ_INST_8_2(); + uint16_t v0 = READ_INST_8_3(); + LOG_INST() << "intrinsics::stlexvardyn" + << " level:" << level << " slot:" << slot << " v" << v0; + + JSTaggedValue value = GET_VREG_VALUE(v0); + FrameState *state = GET_FRAME(sp); + JSTaggedValue env = state->env; + for (int i = 0; i < level; i++) { + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); + ASSERT(!taggedParentEnv.IsUndefined()); + env = taggedParentEnv; + } + LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(thread, slot, value); + + DISPATCH(BytecodeInstruction::Format::PREF_IMM8_IMM8_V8); + } + HANDLE_OPCODE(HANDLE_STLEXVARDYN_PREF_IMM4_IMM4_V8) { + uint16_t level = READ_INST_4_2(); + uint16_t slot = READ_INST_4_3(); + uint16_t v0 = READ_INST_8_2(); + LOG_INST() << "intrinsics::stlexvardyn" + << " level:" << level << " slot:" << slot << " v" << v0; + + JSTaggedValue value = GET_VREG_VALUE(v0); + FrameState *state = GET_FRAME(sp); + JSTaggedValue env = state->env; + for (int i = 0; i < level; i++) { + JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); + ASSERT(!taggedParentEnv.IsUndefined()); + env = taggedParentEnv; + } + LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(thread, slot, value); + + DISPATCH(BytecodeInstruction::Format::PREF_IMM4_IMM4_V8); + } + HANDLE_OPCODE(HANDLE_NEWLEXENVDYN_PREF_IMM16) { + uint16_t numVars = READ_INST_16_1(); + LOG_INST() << "intrinsics::newlexenvdyn" + << " imm " << numVars; + + JSTaggedValue res = FastRuntimeStub::NewLexicalEnvDyn(thread, factory, numVars); + if (res.IsHole()) { + res = SlowRuntimeStub::NewLexicalEnvDyn(thread, numVars); + INTERPRETER_RETURN_IF_ABRUPT(res); + } + SET_ACC(res); + GET_FRAME(sp)->env = res; + DISPATCH(BytecodeInstruction::Format::PREF_IMM16); + } + HANDLE_OPCODE(HANDLE_POPLEXENVDYN_PREF) { + FrameState *state = GET_FRAME(sp); + JSTaggedValue currentLexenv = state->env; + JSTaggedValue parentLexenv = LexicalEnv::Cast(currentLexenv.GetTaggedObject())->GetParentEnv(); + GET_FRAME(sp)->env = parentLexenv; + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_CREATEITERRESULTOBJ_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::createiterresultobj" + << " v" << v0 << " v" << v1; + JSTaggedValue value = GET_VREG_VALUE(v0); + JSTaggedValue flag = GET_VREG_VALUE(v1); + JSTaggedValue res = SlowRuntimeStub::CreateIterResultObj(thread, value, flag); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_SUSPENDGENERATOR_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::suspendgenerator" + << " v" << v0 << " v" << v1; + JSTaggedValue genObj = GET_VREG_VALUE(v0); + JSTaggedValue value = GET_VREG_VALUE(v1); + // suspend will record bytecode offset + SAVE_PC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::SuspendGenerator(thread, genObj, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + + FrameState *state = GET_FRAME(sp); + [[maybe_unused]] auto fistPC = state->method->GetInstructions(); + UPDATE_HOTNESS_COUNTER(-(pc - fistPC)); + LOG(DEBUG, INTERPRETER) << "Exit: SuspendGenerator " << std::hex << reinterpret_cast(sp) << " " + << std::hex << reinterpret_cast(state->pc); + sp = state->prev; + ASSERT(sp != nullptr); + FrameState *prevState = GET_FRAME(sp); + pc = prevState->pc; + + // break frame + if (pc == nullptr) { + state->acc = acc; + return; + } + thread->SetCurrentSPFrame(sp); + constpool = prevState->constpool; + + size_t jumpSize = GetJumpSizeAfterCall(pc); + DISPATCH_OFFSET(jumpSize); + } + HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONAWAITUNCAUGHT_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::asyncfunctionawaituncaught" + << " v" << v0 << " v" << v1; + JSTaggedValue asyncFuncObj = GET_VREG_VALUE(v0); + JSTaggedValue value = GET_VREG_VALUE(v1); + JSTaggedValue res = SlowRuntimeStub::AsyncFunctionAwaitUncaught(thread, asyncFuncObj, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONRESOLVE_PREF_V8_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + [[maybe_unused]] uint16_t v1 = READ_INST_8_2(); + uint16_t v2 = READ_INST_8_3(); + LOG_INST() << "intrinsics::asyncfunctionresolve" + << " v" << v0 << " v" << v1 << " v" << v2; + + JSTaggedValue asyncFuncObj = GET_VREG_VALUE(v0); + JSTaggedValue value = GET_VREG_VALUE(v2); + JSTaggedValue res = SlowRuntimeStub::AsyncFunctionResolveOrReject(thread, asyncFuncObj, value, true); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8); + } + HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONREJECT_PREF_V8_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + [[maybe_unused]] uint16_t v1 = READ_INST_8_2(); + uint16_t v2 = READ_INST_8_3(); + LOG_INST() << "intrinsics::asyncfunctionreject" + << " v" << v0 << " v" << v1 << " v" << v2; + + JSTaggedValue asyncFuncObj = GET_VREG_VALUE(v0); + JSTaggedValue value = GET_VREG_VALUE(v2); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::AsyncFunctionResolveOrReject(thread, asyncFuncObj, value, false); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8); + } + HANDLE_OPCODE(HANDLE_NEWOBJSPREADDYN_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsic::newobjspearddyn" + << " v" << v0 << " v" << v1; + JSTaggedValue func = GET_VREG_VALUE(v0); + JSTaggedValue newTarget = GET_VREG_VALUE(v1); + JSTaggedValue array = GET_ACC(); + JSTaggedValue res = SlowRuntimeStub::NewObjSpreadDyn(thread, func, newTarget, array); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_THROWUNDEFINEDIFHOLE_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsic::throwundefinedifhole" + << " v" << v0 << " v" << v1; + JSTaggedValue hole = GET_VREG_VALUE(v0); + if (!hole.IsHole()) { + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + JSTaggedValue obj = GET_VREG_VALUE(v1); + ASSERT(obj.IsString()); + SlowRuntimeStub::ThrowUndefinedIfHole(thread, obj); + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + HANDLE_OPCODE(HANDLE_STOWNBYNAME_PREF_ID32_V8) { + uint32_t stringId = READ_INST_32_1(); + uint32_t v0 = READ_INST_8_5(); + LOG_INST() << "intrinsics::stownbyname " + << "v" << v0 << " stringId:" << stringId; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + if (receiver.IsJSObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + JSTaggedValue value = GET_ACC(); + // fast path + SAVE_ACC(); + JSTaggedValue res = FastRuntimeStub::SetPropertyByName(thread, receiver, propKey, value); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + RESTORE_ACC(); + } + + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto propKey = constpool->GetObjectFromCache(stringId); // Maybe moved by GC + auto value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StOwnByName(thread, receiver, propKey, value); + RESTORE_ACC(); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_CREATEEMPTYARRAY_PREF) { + LOG_INST() << "intrinsics::createemptyarray"; + JSTaggedValue res = SlowRuntimeStub::CreateEmptyArray(thread, factory, globalEnv); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_CREATEEMPTYOBJECT_PREF) { + LOG_INST() << "intrinsics::createemptyobject"; + JSTaggedValue res = SlowRuntimeStub::CreateEmptyObject(thread, factory, globalEnv); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_CREATEOBJECTWITHBUFFER_PREF_IMM16) { + uint16_t imm = READ_INST_16_1(); + LOG_INST() << "intrinsics::createobjectwithbuffer" + << " imm:" << imm; + JSObject *result = JSObject::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); + + JSTaggedValue res = SlowRuntimeStub::CreateObjectWithBuffer(thread, factory, result); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16); + } + HANDLE_OPCODE(HANDLE_SETOBJECTWITHPROTO_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::setobjectwithproto" + << " v" << v0 << " v" << v1; + JSTaggedValue proto = GET_VREG_VALUE(v0); + JSTaggedValue obj = GET_VREG_VALUE(v1); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::SetObjectWithProto(thread, proto, obj); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_CREATEARRAYWITHBUFFER_PREF_IMM16) { + uint16_t imm = READ_INST_16_1(); + LOG_INST() << "intrinsics::createarraywithbuffer" + << " imm:" << imm; + JSArray *result = JSArray::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); + JSTaggedValue res = SlowRuntimeStub::CreateArrayWithBuffer(thread, factory, result); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16); + } + HANDLE_OPCODE(HANDLE_IMPORTMODULE_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + auto prop = constpool->GetObjectFromCache(stringId); + + LOG_INST() << "intrinsics::importmodule " + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); + + JSTaggedValue moduleRef = SlowRuntimeStub::ImportModule(thread, prop); + SET_ACC(moduleRef); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + HANDLE_OPCODE(HANDLE_STMODULEVAR_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + auto prop = constpool->GetObjectFromCache(stringId); + + LOG_INST() << "intrinsics::stmodulevar " + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); + JSTaggedValue value = GET_ACC(); + + SAVE_ACC(); + SlowRuntimeStub::StModuleVar(thread, prop, value); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + HANDLE_OPCODE(HANDLE_COPYMODULE_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + JSTaggedValue srcModule = GET_VREG_VALUE(v0); + + LOG_INST() << "intrinsics::copymodule "; + + SAVE_ACC(); + SlowRuntimeStub::CopyModule(thread, srcModule); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_LDMODVARBYNAME_PREF_ID32_V8) { + uint32_t stringId = READ_INST_32_1(); + uint32_t v0 = READ_INST_8_5(); + + JSTaggedValue itemName = constpool->GetObjectFromCache(stringId); + JSTaggedValue moduleObj = GET_VREG_VALUE(v0); + LOG_INST() << "intrinsics::ldmodvarbyname " + << "string_id:" << stringId << ", " + << "itemName: " << ConvertToString(EcmaString::Cast(itemName.GetTaggedObject())); + + JSTaggedValue moduleVar = SlowRuntimeStub::LdModvarByName(thread, moduleObj, itemName); + SET_ACC(moduleVar); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue pattern = constpool->GetObjectFromCache(stringId); + uint8_t flags = READ_INST_8_5(); + LOG_INST() << "intrinsics::createregexpwithliteral " + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(pattern.GetTaggedObject())) + << ", flags:" << flags; + JSTaggedValue res = SlowRuntimeStub::CreateRegExpWithLiteral(thread, pattern, flags); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_IMM8); + } + HANDLE_OPCODE(HANDLE_GETTEMPLATEOBJECT_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsic::gettemplateobject" + << " v" << v0; + + JSTaggedValue literal = GET_VREG_VALUE(v0); + JSTaggedValue res = SlowRuntimeStub::GetTemplateObject(thread, literal); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_GETNEXTPROPNAME_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsic::getnextpropname" + << " v" << v0; + JSTaggedValue iter = GET_VREG_VALUE(v0); + JSTaggedValue res = SlowRuntimeStub::GetNextPropName(thread, iter); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_COPYDATAPROPERTIES_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsic::copydataproperties" + << " v" << v0 << " v" << v1; + JSTaggedValue dst = GET_VREG_VALUE(v0); + JSTaggedValue src = GET_VREG_VALUE(v1); + JSTaggedValue res = SlowRuntimeStub::CopyDataProperties(thread, dst, src); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_STOWNBYINDEX_PREF_V8_IMM32) { + uint32_t v0 = READ_INST_8_1(); + uint32_t index = READ_INST_32_2(); + LOG_INST() << "intrinsics::stownbyindex" + << " v" << v0 << " imm" << index; + JSTaggedValue receiver = GET_VREG_VALUE(v0); + // fast path + if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { + SAVE_ACC(); + JSTaggedValue value = GET_ACC(); + // fast path + JSTaggedValue res = + FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); + } + RESTORE_ACC(); + } + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StOwnByIndex(thread, receiver, index, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); + } + HANDLE_OPCODE(HANDLE_STOWNBYVALUE_PREF_V8_V8) { + uint32_t v0 = READ_INST_8_1(); + uint32_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::stownbyvalue" + << " v" << v0 << " v" << v1; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { + SAVE_ACC(); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + JSTaggedValue value = GET_ACC(); + // fast path + JSTaggedValue res = FastRuntimeStub::SetPropertyByValue(thread, receiver, propKey, value); + + // SetPropertyByValue maybe gc need update the value + RESTORE_ACC(); + propKey = GET_VREG_VALUE(v1); + value = GET_ACC(); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + if (value.IsJSFunction()) { + JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); + } + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + } + + // slow path + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto propKey = GET_VREG_VALUE(v1); // Maybe moved by GC + auto value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StOwnByValue(thread, receiver, propKey, value); + RESTORE_ACC(); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8) { + uint16_t numKeys = READ_INST_16_1(); + uint16_t v0 = READ_INST_8_3(); + uint16_t firstArgRegIdx = READ_INST_8_4(); + LOG_INST() << "intrinsics::createobjectwithexcludedkeys " << numKeys << " v" << firstArgRegIdx; + + JSTaggedValue obj = GET_VREG_VALUE(v0); + + JSTaggedValue res = SlowRuntimeStub::CreateObjectWithExcludedKeys(thread, numKeys, obj, firstArgRegIdx); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16_V8_V8); + } + HANDLE_OPCODE(HANDLE_DEFINEGENERATORFUNC_PREF_ID16_IMM16_V8) { + uint16_t methodId = READ_INST_16_1(); + uint16_t length = READ_INST_16_3(); + uint16_t v0 = READ_INST_8_5(); + LOG_INST() << "define gengerator function length: " << length + << " v" << v0; + JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); + ASSERT(result != nullptr); + if (result->IsResolved()) { + auto res = SlowRuntimeStub::DefineGeneratorFunc(thread, result); + INTERPRETER_RETURN_IF_ABRUPT(res); + result = JSFunction::Cast(res.GetTaggedObject()); + result->SetConstantPool(thread, JSTaggedValue(constpool)); + } else { + result->SetResolved(thread); + } + + result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); + JSTaggedValue env = GET_VREG_VALUE(v0); + result->SetLexicalEnv(thread, env); + SET_ACC(JSTaggedValue(result)) + DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_DEFINEASYNCFUNC_PREF_ID16_IMM16_V8) { + uint16_t methodId = READ_INST_16_1(); + uint16_t length = READ_INST_16_3(); + uint16_t v0 = READ_INST_8_5(); + LOG_INST() << "define async function length: " << length + << " v" << v0; + JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); + ASSERT(result != nullptr); + if (result->IsResolved()) { + auto res = SlowRuntimeStub::DefineAsyncFunc(thread, result); + INTERPRETER_RETURN_IF_ABRUPT(res); + result = JSFunction::Cast(res.GetTaggedObject()); + result->SetConstantPool(thread, JSTaggedValue(constpool)); + } else { + result->SetResolved(thread); + } + + result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); + JSTaggedValue env = GET_VREG_VALUE(v0); + result->SetLexicalEnv(thread, env); + SET_ACC(JSTaggedValue(result)) + DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_LDHOLE_PREF) { + LOG_INST() << "intrinsic::ldhole"; + SET_ACC(JSTaggedValue::Hole()); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_COPYRESTARGS_PREF_IMM16) { + uint16_t restIdx = READ_INST_16_1(); + LOG_INST() << "intrinsics::copyrestargs" + << " index: " << restIdx; + + FrameState *state = GET_FRAME(sp); + uint32_t numVregs = state->method->GetNumVregs(); + // Exclude func, newTarget and "this" + int32_t actualNumArgs = state->numActualArgs - NUM_MANDATORY_JSFUNC_ARGS; + int32_t tmp = actualNumArgs - restIdx; + uint32_t restNumArgs = (tmp > 0) ? tmp : 0; + uint32_t startIdx = numVregs + NUM_MANDATORY_JSFUNC_ARGS + restIdx; + + JSTaggedValue res = SlowRuntimeStub::CopyRestArgs(thread, sp, restNumArgs, startIdx); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16); + } + HANDLE_OPCODE(HANDLE_DEFINEGETTERSETTERBYVALUE_PREF_V8_V8_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + uint16_t v2 = READ_INST_8_3(); + uint16_t v3 = READ_INST_8_4(); + LOG_INST() << "intrinsics::definegettersetterbyvalue" + << " v" << v0 << " v" << v1 << " v" << v2 << " v" << v3; + + JSTaggedValue obj = GET_VREG_VALUE(v0); + JSTaggedValue prop = GET_VREG_VALUE(v1); + JSTaggedValue getter = GET_VREG_VALUE(v2); + JSTaggedValue setter = GET_VREG_VALUE(v3); + JSTaggedValue flag = GET_ACC(); + JSTaggedValue res = + SlowRuntimeStub::DefineGetterSetterByValue(thread, obj, prop, getter, setter, flag.ToBoolean()); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8_V8); + } + HANDLE_OPCODE(HANDLE_LDOBJBYINDEX_PREF_V8_IMM32) { + uint16_t v0 = READ_INST_8_1(); + uint32_t idx = READ_INST_32_2(); + LOG_INST() << "intrinsics::ldobjbyindex" + << " v" << v0 << " imm" << idx; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + // fast path + if (LIKELY(receiver.IsHeapObject())) { + JSTaggedValue res = FastRuntimeStub::GetPropertyByIndex(thread, receiver, idx); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); + } + } + // not meet fast condition or fast path return hole, walk slow path + // slow stub not need receiver + JSTaggedValue res = SlowRuntimeStub::LdObjByIndex(thread, receiver, idx, false, JSTaggedValue::Undefined()); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); + } + HANDLE_OPCODE(HANDLE_STOBJBYINDEX_PREF_V8_IMM32) { + uint16_t v0 = READ_INST_8_1(); + uint32_t index = READ_INST_32_2(); + LOG_INST() << "intrinsics::stobjbyindex" + << " v" << v0 << " imm" << index; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + if (receiver.IsHeapObject()) { + SAVE_ACC(); + JSTaggedValue value = GET_ACC(); + // fast path + JSTaggedValue res = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); + } + RESTORE_ACC(); + } + // slow path + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + JSTaggedValue value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StObjByIndex(thread, receiver, index, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); + } + HANDLE_OPCODE(HANDLE_LDOBJBYVALUE_PREF_V8_V8) { + uint32_t v0 = READ_INST_8_1(); + uint32_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::Ldobjbyvalue" + << " v" << v0 << " v" << v1; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); + JSTaggedValue firstValue = profileTypeArray->Get(slotId); + JSTaggedValue res = JSTaggedValue::Hole(); + + if (LIKELY(firstValue.IsHeapObject())) { + JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); + res = ICRuntimeStub::TryLoadICByValue(thread, receiver, propKey, firstValue, secondValue); + } else if (firstValue.IsUndefined()) { + res = ICRuntimeStub::LoadICByValue(thread, + profileTypeArray, + receiver, propKey, slotId); + } + + if (LIKELY(!res.IsHole())) { + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + } +#endif + // fast path + if (LIKELY(receiver.IsHeapObject())) { + JSTaggedValue res = FastRuntimeStub::GetPropertyByValue(thread, receiver, propKey); + if (!res.IsHole()) { + ASSERT(!res.IsAccessor()); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + } + // slow path + JSTaggedValue res = SlowRuntimeStub::LdObjByValue(thread, receiver, propKey, false, JSTaggedValue::Undefined()); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_STOBJBYVALUE_PREF_V8_V8) { + uint32_t v0 = READ_INST_8_1(); + uint32_t v1 = READ_INST_8_2(); + + LOG_INST() << "intrinsics::stobjbyvalue" + << " v" << v0 << " v" << v1; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); + JSTaggedValue firstValue = profileTypeArray->Get(slotId); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + JSTaggedValue value = GET_ACC(); + JSTaggedValue res = JSTaggedValue::Hole(); + SAVE_ACC(); + + if (LIKELY(firstValue.IsHeapObject())) { + JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); + res = ICRuntimeStub::TryStoreICByValue(thread, receiver, propKey, firstValue, secondValue, value); + } else if (firstValue.IsUndefined()) { + res = ICRuntimeStub::StoreICByValue(thread, + profileTypeArray, + receiver, propKey, value, slotId); + } + + if (LIKELY(!res.IsHole())) { + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + } +#endif + if (receiver.IsHeapObject()) { + SAVE_ACC(); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + JSTaggedValue value = GET_ACC(); + // fast path + JSTaggedValue res = FastRuntimeStub::SetPropertyByValue(thread, receiver, propKey, value); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + RESTORE_ACC(); + } + { + // slow path + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + JSTaggedValue propKey = GET_VREG_VALUE(v1); // Maybe moved by GC + JSTaggedValue value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StObjByValue(thread, receiver, propKey, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + } + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_LDSUPERBYVALUE_PREF_V8_V8) { + uint32_t v0 = READ_INST_8_1(); + uint32_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsics::Ldsuperbyvalue" + << " v" << v0 << " v" << v1; + + JSTaggedValue receiver = GET_VREG_VALUE(v0); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + + // slow path + JSTaggedValue thisFunc = GetThisFunction(sp); + JSTaggedValue res = SlowRuntimeStub::LdSuperByValue(thread, receiver, propKey, thisFunc); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_STSUPERBYVALUE_PREF_V8_V8) { + uint32_t v0 = READ_INST_8_1(); + uint32_t v1 = READ_INST_8_2(); + + LOG_INST() << "intrinsics::stsuperbyvalue" + << " v" << v0 << " v" << v1; + JSTaggedValue receiver = GET_VREG_VALUE(v0); + JSTaggedValue propKey = GET_VREG_VALUE(v1); + JSTaggedValue value = GET_ACC(); + + // slow path + SAVE_ACC(); + JSTaggedValue thisFunc = GetThisFunction(sp); + JSTaggedValue res = SlowRuntimeStub::StSuperByValue(thread, receiver, propKey, value, thisFunc); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_TRYLDGLOBALBYNAME_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + auto prop = constpool->GetObjectFromCache(stringId); + + LOG_INST() << "intrinsics::tryldglobalbyname " + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); + +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + JSTaggedValue res = ICRuntimeStub::LoadGlobalICByName(thread, + ProfileTypeInfo::Cast( + profileTypeInfo.GetTaggedObject()), + globalObj, prop, slotId); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } +#endif + + bool found = false; + // order: 1. global record 2. global object + JSTaggedValue result = SlowRuntimeStub::LdGlobalRecord(thread, prop, &found); + if (found) { + SET_ACC(result); + } else { + JSTaggedValue globalResult = FastRuntimeStub::GetGlobalOwnProperty(globalObj, prop, &found); + if (found) { + SET_ACC(globalResult); + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::TryLdGlobalByName(thread, globalObj, prop); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + } + + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + HANDLE_OPCODE(HANDLE_TRYSTGLOBALBYNAME_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::trystglobalbyname" + << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); + +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = ICRuntimeStub::StoreGlobalICByName(thread, + ProfileTypeInfo::Cast( + profileTypeInfo.GetTaggedObject()), + globalObj, propKey, value, slotId); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } +#endif + + bool found = false; + SlowRuntimeStub::LdGlobalRecord(thread, propKey, &found); + // 1. find from global record + if (found) { + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::TryUpdateGlobalRecord(thread, propKey, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + } else { + // 2. find from global object + FastRuntimeStub::GetGlobalOwnProperty(globalObj, propKey, &found); + if (!found) { + auto result = SlowRuntimeStub::ThrowReferenceError(thread, propKey, " is not defined"); + INTERPRETER_RETURN_IF_ABRUPT(result); + } + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalVar(thread, propKey, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + } + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + + HANDLE_OPCODE(HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::stconsttoglobalrecord" + << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); + + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, true); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + + HANDLE_OPCODE(HANDLE_STLETTOGLOBALRECORD_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::stlettoglobalrecord" + << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); + + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + + HANDLE_OPCODE(HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::stclasstoglobalrecord" + << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); + + JSTaggedValue value = GET_ACC(); + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + + HANDLE_OPCODE(HANDLE_LDGLOBALVAR_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + JSTaggedValue res = ICRuntimeStub::LoadGlobalICByName(thread, + ProfileTypeInfo::Cast( + profileTypeInfo.GetTaggedObject()), + globalObj, propKey, slotId); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } +#endif + bool found = false; + JSTaggedValue result = FastRuntimeStub::GetGlobalOwnProperty(globalObj, propKey, &found); + if (found) { + SET_ACC(result); + } else { + // slow path + JSTaggedValue res = SlowRuntimeStub::LdGlobalVar(thread, globalObj, propKey); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + } + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + HANDLE_OPCODE(HANDLE_LDOBJBYNAME_PREF_ID32_V8) { + uint32_t v0 = READ_INST_8_5(); + JSTaggedValue receiver = GET_VREG_VALUE(v0); + +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); + JSTaggedValue firstValue = profileTypeArray->Get(slotId); + JSTaggedValue res = JSTaggedValue::Hole(); + + if (LIKELY(firstValue.IsHeapObject())) { + JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); + res = ICRuntimeStub::TryLoadICByName(thread, receiver, firstValue, secondValue); + } else if (firstValue.IsUndefined()) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + res = ICRuntimeStub::LoadICByName(thread, + profileTypeArray, + receiver, propKey, slotId); + } + + if (LIKELY(!res.IsHole())) { + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + } +#endif + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + LOG_INST() << "intrinsics::ldobjbyname " + << "v" << v0 << " stringId:" << stringId << ", " + << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())) << ", obj:" << receiver.GetRawData(); + + if (LIKELY(receiver.IsHeapObject())) { + // fast path + JSTaggedValue res = FastRuntimeStub::GetPropertyByName(thread, receiver, propKey); + if (!res.IsHole()) { + ASSERT(!res.IsAccessor()); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + } + // not meet fast condition or fast path return hole, walk slow path + // slow stub not need receiver + JSTaggedValue res = SlowRuntimeStub::LdObjByName(thread, receiver, propKey, false, JSTaggedValue::Undefined()); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_STOBJBYNAME_PREF_ID32_V8) { + uint32_t v0 = READ_INST_8_5(); + JSTaggedValue receiver = GET_VREG_VALUE(v0); + JSTaggedValue value = GET_ACC(); +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); + JSTaggedValue firstValue = profileTypeArray->Get(slotId); + JSTaggedValue res = JSTaggedValue::Hole(); + SAVE_ACC(); + + if (LIKELY(firstValue.IsHeapObject())) { + JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); + res = ICRuntimeStub::TryStoreICByName(thread, receiver, firstValue, secondValue, value); + } else if (firstValue.IsUndefined()) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + res = ICRuntimeStub::StoreICByName(thread, + profileTypeArray, + receiver, propKey, value, slotId); + } + + if (LIKELY(!res.IsHole())) { + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + } +#endif + uint32_t stringId = READ_INST_32_1(); + LOG_INST() << "intrinsics::stobjbyname " + << "v" << v0 << " stringId:" << stringId; + if (receiver.IsHeapObject()) { + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + value = GET_ACC(); + // fast path + SAVE_ACC(); + JSTaggedValue res = FastRuntimeStub::SetPropertyByName(thread, receiver, propKey, value); + if (!res.IsHole()) { + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + RESTORE_ACC(); + } + // slow path + SAVE_ACC(); + receiver = GET_VREG_VALUE(v0); // Maybe moved by GC + auto propKey = constpool->GetObjectFromCache(stringId); // Maybe moved by GC + value = GET_ACC(); // Maybe moved by GC + JSTaggedValue res = SlowRuntimeStub::StObjByName(thread, receiver, propKey, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_LDSUPERBYNAME_PREF_ID32_V8) { + uint32_t stringId = READ_INST_32_1(); + uint32_t v0 = READ_INST_8_5(); + JSTaggedValue obj = GET_VREG_VALUE(v0); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + + LOG_INST() << "intrinsics::ldsuperbyname" + << "v" << v0 << " stringId:" << stringId << ", " + << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())) << ", obj:" << obj.GetRawData(); + + JSTaggedValue thisFunc = GetThisFunction(sp); + JSTaggedValue res = SlowRuntimeStub::LdSuperByValue(thread, obj, propKey, thisFunc); + + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_STSUPERBYNAME_PREF_ID32_V8) { + uint32_t stringId = READ_INST_32_1(); + uint32_t v0 = READ_INST_8_5(); + + JSTaggedValue obj = GET_VREG_VALUE(v0); + JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); + JSTaggedValue value = GET_ACC(); + + LOG_INST() << "intrinsics::stsuperbyname" + << "v" << v0 << " stringId:" << stringId << ", " + << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())) << ", obj:" << obj.GetRawData() + << ", value:" << value.GetRawData(); + + // slow path + SAVE_ACC(); + JSTaggedValue thisFunc = GetThisFunction(sp); + JSTaggedValue res = SlowRuntimeStub::StSuperByValue(thread, obj, propKey, value, thisFunc); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); + } + HANDLE_OPCODE(HANDLE_STGLOBALVAR_PREF_ID32) { + uint32_t stringId = READ_INST_32_1(); + JSTaggedValue prop = constpool->GetObjectFromCache(stringId); + JSTaggedValue value = GET_ACC(); + + LOG_INST() << "intrinsics::stglobalvar " + << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())) + << ", value:" << value.GetRawData(); +#if ECMASCRIPT_ENABLE_IC + auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); + if (!profileTypeInfo.IsUndefined()) { + uint16_t slotId = READ_INST_8_0(); + SAVE_ACC(); + JSTaggedValue res = ICRuntimeStub::StoreGlobalICByName(thread, + ProfileTypeInfo::Cast( + profileTypeInfo.GetTaggedObject()), + globalObj, prop, value, slotId); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } +#endif + SAVE_ACC(); + JSTaggedValue res = SlowRuntimeStub::StGlobalVar(thread, prop, value); + INTERPRETER_RETURN_IF_ABRUPT(res); + RESTORE_ACC(); + DISPATCH(BytecodeInstruction::Format::PREF_ID32); + } + HANDLE_OPCODE(HANDLE_CREATEGENERATOROBJ_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsics::creategeneratorobj" + << " v" << v0; + JSTaggedValue genFunc = GET_VREG_VALUE(v0); + JSTaggedValue res = SlowRuntimeStub::CreateGeneratorObj(thread, genFunc); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_STARRAYSPREAD_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "ecmascript::intrinsics::starrayspread" + << " v" << v0 << " v" << v1 << "acc"; + JSTaggedValue dst = GET_VREG_VALUE(v0); + JSTaggedValue index = GET_VREG_VALUE(v1); + JSTaggedValue src = GET_ACC(); + JSTaggedValue res = SlowRuntimeStub::StArraySpread(thread, dst, index, src); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_GETITERATORNEXT_PREF_V8_V8) { + uint16_t v0 = READ_INST_8_1(); + uint16_t v1 = READ_INST_8_2(); + LOG_INST() << "intrinsic::getiteratornext" + << " v" << v0 << " v" << v1; + JSTaggedValue obj = GET_VREG_VALUE(v0); + JSTaggedValue method = GET_VREG_VALUE(v1); + JSTaggedValue res = SlowRuntimeStub::GetIteratorNext(thread, obj, method); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); + } + HANDLE_OPCODE(HANDLE_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8) { + uint16_t methodId = READ_INST_16_1(); + uint16_t imm = READ_INST_16_3(); + uint16_t length = READ_INST_16_5(); + uint16_t v0 = READ_INST_8_7(); + uint16_t v1 = READ_INST_8_8(); + LOG_INST() << "intrinsics::defineclasswithbuffer" + << " method id:" << methodId << " literal id:" << imm << " lexenv: v" << v0 << " parent: v" << v1; + JSFunction *cls = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); + ASSERT(cls != nullptr); + if (cls->IsResolved()) { + auto res = SlowRuntimeStub::NewClassFunc(thread, cls); + INTERPRETER_RETURN_IF_ABRUPT(res); + cls = JSFunction::Cast(res.GetTaggedObject()); + cls->SetConstantPool(thread, JSTaggedValue(constpool)); + } else { + cls->SetResolved(thread); + } + + cls->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); + JSTaggedValue lexenv = GET_VREG_VALUE(v0); + cls->SetLexicalEnv(thread, lexenv); + + TaggedArray *literalBuffer = TaggedArray::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); + JSTaggedValue proto = GET_VREG_VALUE(v1); + JSTaggedValue res = SlowRuntimeStub::DefineClass(thread, cls, literalBuffer, proto, lexenv, constpool); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_IMM16_V8_V8); + } + HANDLE_OPCODE(HANDLE_SUPERCALL_PREF_IMM16_V8) { + uint16_t range = READ_INST_16_1(); + uint16_t v0 = READ_INST_8_3(); + LOG_INST() << "intrinsics::supercall" + << " range: " << range << " v" << v0; + + FrameState *state = GET_FRAME(sp); + auto numVregs = state->method->GetNumVregs(); + JSTaggedValue thisFunc = GET_ACC(); + JSTaggedValue newTarget = GET_VREG_VALUE(numVregs + 1); + + JSTaggedValue res = SlowRuntimeStub::SuperCall(thread, thisFunc, newTarget, v0, range); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16_V8); + } + HANDLE_OPCODE(HANDLE_SUPERCALLSPREAD_PREF_V8) { + uint16_t v0 = READ_INST_8_1(); + LOG_INST() << "intrinsic::supercallspread" + << " array: v" << v0; + + FrameState *state = GET_FRAME(sp); + auto numVregs = state->method->GetNumVregs(); + JSTaggedValue thisFunc = GET_ACC(); + JSTaggedValue newTarget = GET_VREG_VALUE(numVregs + 1); + JSTaggedValue array = GET_VREG_VALUE(v0); + + JSTaggedValue res = SlowRuntimeStub::SuperCallSpread(thread, thisFunc, newTarget, array); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_V8); + } + HANDLE_OPCODE(HANDLE_CREATEOBJECTHAVINGMETHOD_PREF_IMM16) { + uint16_t imm = READ_INST_16_1(); + LOG_INST() << "intrinsics::createobjecthavingmethod" + << " imm:" << imm; + JSObject *result = JSObject::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); + JSTaggedValue env = GET_ACC(); + + JSTaggedValue res = SlowRuntimeStub::CreateObjectHavingMethod(thread, factory, result, env, constpool); + INTERPRETER_RETURN_IF_ABRUPT(res); + SET_ACC(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16); + } + HANDLE_OPCODE(HANDLE_THROWIFSUPERNOTCORRECTCALL_PREF_IMM16) { + uint16_t imm = READ_INST_16_1(); + JSTaggedValue thisValue = GET_ACC(); + LOG_INST() << "intrinsic::throwifsupernotcorrectcall" + << " imm:" << imm; + JSTaggedValue res = SlowRuntimeStub::ThrowIfSuperNotCorrectCall(thread, imm, thisValue); + INTERPRETER_RETURN_IF_ABRUPT(res); + DISPATCH(BytecodeInstruction::Format::PREF_IMM16); + } + HANDLE_OPCODE(HANDLE_LDHOMEOBJECT_PREF) { + LOG_INST() << "intrinsics::ldhomeobject"; + + JSTaggedValue thisFunc = GetThisFunction(sp); + JSTaggedValue homeObject = JSFunction::Cast(thisFunc.GetTaggedObject())->GetHomeObject(); + + SET_ACC(homeObject); + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_THROWDELETESUPERPROPERTY_PREF) { + LOG_INST() << "throwdeletesuperproperty"; + + SlowRuntimeStub::ThrowDeleteSuperProperty(thread); + INTERPRETER_GOTO_EXCEPTION_HANDLER(); + } + HANDLE_OPCODE(HANDLE_DEBUGGER_PREF) { + LOG_INST() << "intrinsics::debugger"; + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_ISTRUE_PREF) { + LOG_INST() << "intrinsics::istrue"; + if (GET_ACC().ToBoolean()) { + SET_ACC(JSTaggedValue::True()); + } else { + SET_ACC(JSTaggedValue::False()); + } + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(HANDLE_ISFALSE_PREF) { + LOG_INST() << "intrinsics::isfalse"; + if (!GET_ACC().ToBoolean()) { + SET_ACC(JSTaggedValue::True()); + } else { + SET_ACC(JSTaggedValue::False()); + } + DISPATCH(BytecodeInstruction::Format::PREF_NONE); + } + HANDLE_OPCODE(EXCEPTION_HANDLER) { + auto exception = thread->GetException(); + + EcmaFrameHandler frameHandler(sp); + uint32_t pcOffset = panda_file::INVALID_OFFSET; + for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { + if (frameHandler.IsBreakFrame()) { + return; + } + auto method = frameHandler.GetMethod(); + pcOffset = FindCatchBlock(method, frameHandler.GetBytecodeOffset()); + if (pcOffset != panda_file::INVALID_OFFSET) { + sp = frameHandler.GetSp(); + constpool = frameHandler.GetConstpool(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + pc = JSMethod::Cast(method)->GetBytecodeArray() + pcOffset; + break; + } + } + if (pcOffset == panda_file::INVALID_OFFSET) { + return; + } + + // set exception to acc + if (exception.IsObjectWrapper()) { + SET_ACC(ObjectWrapper::Cast(exception.GetTaggedObject())->GetValue()); + } else { + SET_ACC(exception); + } + thread->ClearException(); + thread->SetCurrentSPFrame(sp); + DISPATCH_OFFSET(0); + } + HANDLE_OPCODE(HANDLE_OVERFLOW) { + LOG(FATAL, INTERPRETER) << "opcode overflow"; + } +#include "templates/debugger_instruction_handler.inl" +} + +void EcmaInterpreter::InitStackFrame(JSThread *thread) +{ + uint64_t *prevSp = const_cast(thread->GetCurrentSPFrame()); + FrameState *state = GET_FRAME(prevSp); + state->pc = nullptr; + state->sp = nullptr; + state->method = nullptr; + state->acc = JSTaggedValue::Hole(); + state->constpool = nullptr; + state->profileTypeInfo = JSTaggedValue::Undefined(); + state->prev = nullptr; + state->numActualArgs = 0; +} + +uint32_t EcmaInterpreter::FindCatchBlock(JSMethod *caller, uint32_t pc) +{ + auto *pandaFile = caller->GetPandaFile(); + panda_file::MethodDataAccessor mda(*pandaFile, caller->GetFileId()); + panda_file::CodeDataAccessor cda(*pandaFile, mda.GetCodeId().value()); + + uint32_t pcOffset = panda_file::INVALID_OFFSET; + cda.EnumerateTryBlocks([&pcOffset, pc](panda_file::CodeDataAccessor::TryBlock &try_block) { + if ((try_block.GetStartPc() <= pc) && ((try_block.GetStartPc() + try_block.GetLength()) > pc)) { + try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) { + pcOffset = catch_block.GetHandlerPc(); + return false; + }); + } + return pcOffset == panda_file::INVALID_OFFSET; + }); + return pcOffset; +} + +void EcmaInterpreter::InterpreterFrameCopyArgs(JSTaggedType *newSp, uint32_t numVregs, uint32_t numActualArgs, + uint32_t numDeclaredArgs) +{ + for (size_t i = 0; i < numVregs; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[i] = JSTaggedValue::VALUE_UNDEFINED; + } + for (size_t i = numActualArgs; i < numDeclaredArgs; i++) { + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + newSp[numVregs + i] = JSTaggedValue::VALUE_UNDEFINED; + } +} + +JSTaggedValue EcmaInterpreter::GetThisFunction(JSTaggedType *sp) +{ + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + FrameState *state = reinterpret_cast(sp) - 1; + auto numVregs = state->method->GetNumVregs(); + return GET_VREG_VALUE(numVregs); +} + +size_t EcmaInterpreter::GetJumpSizeAfterCall(const uint8_t *prevPc) +{ + uint8_t op = *prevPc; + size_t jumpSize; + switch (op) { + case (EcmaOpcode::CALLARG0DYN_PREF_V8): + jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8); + break; + case (EcmaOpcode::CALLARG1DYN_PREF_V8_V8): + jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8); + break; + case (EcmaOpcode::CALLARGS2DYN_PREF_V8_V8_V8): + jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8_V8); + break; + case (EcmaOpcode::CALLARGS3DYN_PREF_V8_V8_V8_V8): + jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8_V8_V8); + break; + case (EcmaOpcode::CALLIRANGEDYN_PREF_IMM16_V8): + jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_IMM16_V8); + break; + case (EcmaOpcode::CALLITHISRANGEDYN_PREF_IMM16_V8): + jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_IMM16_V8); + break; + default: + UNREACHABLE(); + } + + return jumpSize; +} + +JSTaggedValue EcmaInterpreter::GetRuntimeProfileTypeInfo(TaggedType *sp) +{ + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + FrameState *state = reinterpret_cast(sp) - 1; + return state->profileTypeInfo; +} + +bool EcmaInterpreter::UpdateHotnessCounter(JSThread* thread, TaggedType *sp, JSTaggedValue acc, int32_t offset) +{ + FrameState *state = GET_FRAME(sp); + auto method = state->method; + auto hotnessCounter = static_cast(method->GetHotnessCounter()); + + hotnessCounter += offset; + if (UNLIKELY(hotnessCounter <= 0)) { + if (state->profileTypeInfo == JSTaggedValue::Undefined()) { + state->acc = acc; + auto numVregs = method->GetNumVregs(); + // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) + auto thisFunc = JSTaggedValue(sp[numVregs]); + auto res = SlowRuntimeStub::NotifyInlineCache( + thread, JSFunction::Cast(thisFunc.GetHeapObject()), method); + state->profileTypeInfo = res; + method->SetHotnessCounter(std::numeric_limits::max()); + return true; + } else { + hotnessCounter = std::numeric_limits::max(); + } + } + method->SetHotnessCounter(static_cast(hotnessCounter)); + return false; +} +#if defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +} // namespace panda::ecmascript +#endif // ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H diff --git a/ecmascript/interpreter/interpreter.h b/ecmascript/interpreter/interpreter.h index 62964b5a7d..cb988f3701 100644 --- a/ecmascript/interpreter/interpreter.h +++ b/ecmascript/interpreter/interpreter.h @@ -214,6 +214,8 @@ enum EcmaOpcode { STCONSTTOGLOBALRECORD_PREF_ID32, STLETTOGLOBALRECORD_PREF_ID32, STCLASSTOGLOBALRECORD_PREF_ID32, + STOWNBYVALUEWITHNAMESET_PREF_V8_V8, + STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, MOV_DYN_V8_V8, MOV_DYN_V16_V16, LDA_STR_ID32, diff --git a/ecmascript/interpreter/slow_runtime_stub.cpp b/ecmascript/interpreter/slow_runtime_stub.cpp index 5874bcd6cb..2c08c94165 100644 --- a/ecmascript/interpreter/slow_runtime_stub.cpp +++ b/ecmascript/interpreter/slow_runtime_stub.cpp @@ -740,6 +740,32 @@ JSTaggedValue SlowRuntimeStub::StOwnByName(JSThread *thread, JSTaggedValue obj, return JSTaggedValue::True(); } +JSTaggedValue SlowRuntimeStub::StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, + JSTaggedValue value) +{ + INTERPRETER_TRACE(thread, StOwnByNameDyn); + [[maybe_unused]] EcmaHandleScope handleScope(thread); + + JSHandle objHandle(thread, obj); + JSHandle propHandle(thread, prop); + JSHandle valueHandle(thread, value); + ASSERT(propHandle->IsStringOrSymbol()); + + JSHandle propKey = JSTaggedValue::ToPropertyKey(thread, propHandle); + + // property in class is non-enumerable + bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); + + PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); + bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propHandle, desc); + if (!ret) { + return ThrowTypeError(thread, "SetOwnByNameWithNameSet failed"); + } + JSFunctionBase::SetFunctionName(thread, JSHandle::Cast(valueHandle), propKey, + JSHandle(thread, JSTaggedValue::Undefined())); + return JSTaggedValue::True(); +} + JSTaggedValue SlowRuntimeStub::StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value) { INTERPRETER_TRACE(thread, StOwnByIdDyn); @@ -763,6 +789,7 @@ JSTaggedValue SlowRuntimeStub::StOwnByIndex(JSThread *thread, JSTaggedValue obj, JSTaggedValue SlowRuntimeStub::StOwnByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value) { [[maybe_unused]] EcmaHandleScope handleScope(thread); + INTERPRETER_TRACE(thread, StOwnByValueDyn); const GlobalEnvConstants *globalConst = thread->GlobalConstants(); JSHandle objHandle(thread, obj); @@ -783,6 +810,33 @@ JSTaggedValue SlowRuntimeStub::StOwnByValue(JSThread *thread, JSTaggedValue obj, if (!ret) { return ThrowTypeError(thread, "StOwnByValue failed"); } + return JSTaggedValue::True(); +} + +JSTaggedValue SlowRuntimeStub::StOwnByValueWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, + JSTaggedValue value) +{ + [[maybe_unused]] EcmaHandleScope handleScope(thread); + INTERPRETER_TRACE(thread, StOwnByValueDyn); + const GlobalEnvConstants *globalConst = thread->GlobalConstants(); + JSHandle objHandle(thread, obj); + JSHandle keyHandle(thread, key); + JSHandle valueHandle(thread, value); + + if (objHandle->IsClassConstructor() && + JSTaggedValue::SameValue(keyHandle, globalConst->GetHandledPrototypeString())) { + return ThrowTypeError(thread, "In a class, static property named 'prototype' throw a TypeError"); + } + + // property in class is non-enumerable + bool enumerable = !(objHandle->IsClassPrototype() || objHandle->IsClassConstructor()); + + PropertyDescriptor desc(thread, valueHandle, true, enumerable, true); + JSMutableHandle propKey(JSTaggedValue::ToPropertyKey(thread, keyHandle)); + bool ret = JSTaggedValue::DefineOwnProperty(thread, objHandle, propKey, desc); + if (!ret) { + return ThrowTypeError(thread, "StOwnByValueWithNameSet failed"); + } if (valueHandle->IsJSFunction()) { if (propKey->IsNumber()) { propKey.Update(base::NumberHelper::NumberToString(thread, propKey.GetTaggedValue()).GetTaggedValue()); diff --git a/ecmascript/interpreter/slow_runtime_stub.h b/ecmascript/interpreter/slow_runtime_stub.h index 5523c60564..afa120f0ce 100644 --- a/ecmascript/interpreter/slow_runtime_stub.h +++ b/ecmascript/interpreter/slow_runtime_stub.h @@ -79,8 +79,12 @@ public: static void ThrowDeleteSuperProperty(JSThread *thread); static JSTaggedValue StOwnByName(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, JSTaggedValue value); + static JSTaggedValue StOwnByNameWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue prop, + JSTaggedValue value); static JSTaggedValue StOwnByIndex(JSThread *thread, JSTaggedValue obj, uint32_t idx, JSTaggedValue value); static JSTaggedValue StOwnByValue(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, JSTaggedValue value); + static JSTaggedValue StOwnByValueWithNameSet(JSThread *thread, JSTaggedValue obj, JSTaggedValue key, + JSTaggedValue value); static JSTaggedValue CreateEmptyArray(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv); static JSTaggedValue CreateEmptyObject(JSThread *thread, ObjectFactory *factory, JSHandle globalEnv); static JSTaggedValue CreateObjectWithBuffer(JSThread *thread, ObjectFactory *factory, JSObject *literal); diff --git a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl index bb5386e842..5aaacdc932 100644 --- a/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl +++ b/ecmascript/interpreter/templates/debugger_instruction_dispatch.inl @@ -144,6 +144,8 @@ &&DEBUG_HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32, &&DEBUG_HANDLE_STLETTOGLOBALRECORD_PREF_ID32, &&DEBUG_HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32, + &&DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8, + &&DEBUG_HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, &&DEBUG_HANDLE_MOV_DYN_V8_V8, &&DEBUG_HANDLE_MOV_DYN_V16_V16, &&DEBUG_HANDLE_LDA_STR_ID32, @@ -266,6 +268,4 @@ &&DEBUG_HANDLE_OVERFLOW, &&DEBUG_HANDLE_OVERFLOW, &&DEBUG_HANDLE_OVERFLOW, - &&DEBUG_HANDLE_OVERFLOW, - &&DEBUG_HANDLE_OVERFLOW, - &&DEBUG_HANDLE_OVERFLOW, + &&DEBUG_HANDLE_OVERFLOW, \ No newline at end of file diff --git a/ecmascript/interpreter/templates/debugger_instruction_handler.inl b/ecmascript/interpreter/templates/debugger_instruction_handler.inl index 60d3cac4a8..e578e5cfeb 100644 --- a/ecmascript/interpreter/templates/debugger_instruction_handler.inl +++ b/ecmascript/interpreter/templates/debugger_instruction_handler.inl @@ -668,6 +668,16 @@ NOTIFY_DEBUGGER_EVENT(); REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STCLASSTOGLOBALRECORD_PREF_ID32); } + HANDLE_OPCODE(DEBUG_HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8) + { + NOTIFY_DEBUGGER_EVENT(); + REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STOWNBYVALUEWITHNAMESET_PREF_V8_V8); + } + HANDLE_OPCODE(DEBUG_HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8) + { + NOTIFY_DEBUGGER_EVENT(); + REAL_GOTO_DISPATCH_OPCODE(EcmaOpcode::STOWNBYNAMEWITHNAMESET_PREF_ID32_V8); + } HANDLE_OPCODE(DEBUG_HANDLE_MOV_DYN_V8_V8) { NOTIFY_DEBUGGER_EVENT(); diff --git a/ecmascript/interpreter/templates/instruction_dispatch.inl b/ecmascript/interpreter/templates/instruction_dispatch.inl index a9599b0c7a..2462b52359 100644 --- a/ecmascript/interpreter/templates/instruction_dispatch.inl +++ b/ecmascript/interpreter/templates/instruction_dispatch.inl @@ -144,6 +144,8 @@ &&HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32, &&HANDLE_STLETTOGLOBALRECORD_PREF_ID32, &&HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32, + &&HANDLE_STOWNBYVALUEWITHNAMESET_PREF_V8_V8, + &&HANDLE_STOWNBYNAMEWITHNAMESET_PREF_ID32_V8, &&HANDLE_MOV_DYN_V8_V8, &&HANDLE_MOV_DYN_V16_V16, &&HANDLE_LDA_STR_ID32, @@ -267,5 +269,4 @@ &&HANDLE_OVERFLOW, &&HANDLE_OVERFLOW, &&HANDLE_OVERFLOW, - &&HANDLE_OVERFLOW, - &&HANDLE_OVERFLOW, + -- Gitee From 0924296682b95d8523444412d1f3a3a6d82cd4ea Mon Sep 17 00:00:00 2001 From: DaiHN Date: Fri, 17 Sep 2021 17:15:04 +0800 Subject: [PATCH 04/11] fix for function's name setting pat2 Signed-off-by: DaiHN --- "\\" | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 "\\" diff --git "a/\\" "b/\\" deleted file mode 100644 index fa5bc0bd9a..0000000000 --- "a/\\" +++ /dev/null @@ -1,13 +0,0 @@ -fix function's name setting - -Signed-off-by: DaiHN - -# Please enter the commit message for your changes. Lines starting -# with '#' will be ignored, and an empty message aborts the commit. -# -# On branch master -# Your branch is up to date with 'origin/master'. -# -# Changes to be committed: -# modified: ecmascript/interpreter/slow_runtime_stub.cpp -# -- Gitee From 0af90524355a1838dc6f86ae0d39c5a2844c89b5 Mon Sep 17 00:00:00 2001 From: DaiHN Date: Sat, 18 Sep 2021 09:28:35 +0800 Subject: [PATCH 05/11] fix function's name setting pat3 Signed-off-by: DaiHN --- ecmascript/interpreter/interpreter-inl.h.orig | 3269 ----------------- 1 file changed, 3269 deletions(-) delete mode 100644 ecmascript/interpreter/interpreter-inl.h.orig diff --git a/ecmascript/interpreter/interpreter-inl.h.orig b/ecmascript/interpreter/interpreter-inl.h.orig deleted file mode 100644 index 99efe62c89..0000000000 --- a/ecmascript/interpreter/interpreter-inl.h.orig +++ /dev/null @@ -1,3269 +0,0 @@ -/* - * Copyright (c) 2021 Huawei Device Co., Ltd. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H -#define ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H - -#include "ecmascript/class_linker/program_object-inl.h" -#include "ecmascript/ecma_string.h" -#include "ecmascript/ecma_vm.h" -#include "ecmascript/global_env.h" -#include "ecmascript/ic/ic_runtime_stub-inl.h" -#include "ecmascript/interpreter/fast_runtime_stub-inl.h" -#include "ecmascript/interpreter/interpreter.h" -#include "ecmascript/interpreter/slow_runtime_stub.h" -#include "ecmascript/js_generator_object.h" -#include "ecmascript/js_tagged_value.h" -#include "ecmascript/literal_data_extractor.h" -#include "ecmascript/runtime_call_id.h" -#include "ecmascript/template_string.h" -#include "ecmascript/vmstat/runtime_stat.h" -#include "include/runtime_notification.h" -#include "libpandafile/code_data_accessor.h" -#include "libpandafile/file.h" -#include "libpandafile/method_data_accessor.h" - -namespace panda::ecmascript { -#if defined(__clang__) -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wvoid-ptr-dereference" -#pragma clang diagnostic ignored "-Wgnu-label-as-value" -#elif defined(__GNUC__) -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wpedantic" -#endif - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define LOG_INST() LOG(DEBUG, INTERPRETER) << ": " - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define HANDLE_OPCODE(handle_opcode) \ - handle_opcode: // NOLINT(clang-diagnostic-gnu-label-as-value, cppcoreguidelines-macro-usage) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define ADVANCE_PC(offset) \ - pc += (offset); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic, cppcoreguidelines-macro-usage) - -#define GOTO_NEXT() // NOLINT(clang-diagnostic-gnu-label-as-value, cppcoreguidelines-macro-usage) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DISPATCH(format) \ - do { \ - ADVANCE_PC(BytecodeInstruction::Size(format)) \ - opcode = READ_INST_OP(); goto * dispatchTable[opcode]; \ - } while (false) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define DISPATCH_OFFSET(offset) \ - do { \ - ADVANCE_PC(offset) \ - opcode = READ_INST_OP(); goto * dispatchTable[opcode]; \ - } while (false) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GET_FRAME(CurrentSp) \ - (reinterpret_cast(CurrentSp) - 1) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define SAVE_PC() (GET_FRAME(sp)->pc = pc) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define SAVE_ACC() (GET_FRAME(sp)->acc = acc) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define RESTORE_ACC() (acc = GET_FRAME(sp)->acc) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define INTERPRETER_GOTO_EXCEPTION_HANDLER() \ - do { \ - SAVE_PC(); \ - goto *dispatchTable[EcmaOpcode::LAST_OPCODE]; \ - } while (false) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define CHECK_SWITCH_TO_DEBUGGER_TABLE() \ - if (Runtime::GetCurrent()->IsDebugMode()) { \ - dispatchTable = debugDispatchTable; \ - } - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define REAL_GOTO_DISPATCH_OPCODE(opcode) \ - do { \ - goto *instDispatchTable[opcode]; \ - } while (false) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define REAL_GOTO_EXCEPTION_HANDLER() \ - do { \ - SAVE_PC(); \ - goto *instDispatchTable[EcmaOpcode::LAST_OPCODE]; \ - } while (false) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define INTERPRETER_RETURN_IF_ABRUPT(result) \ - do { \ - if (result.IsException()) { \ - INTERPRETER_GOTO_EXCEPTION_HANDLER(); \ - } \ - } while (false) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define NOTIFY_DEBUGGER_EVENT() \ - do { \ - SAVE_ACC(); \ - SAVE_PC(); \ - NotifyBytecodePcChanged(thread); \ - RESTORE_ACC(); \ - } while (false) - -#if ECMASCRIPT_ENABLE_IC -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define UPDATE_HOTNESS_COUNTER_NON_ACC(offset) (UpdateHotnessCounter(thread, sp, acc, offset)) - -#define UPDATE_HOTNESS_COUNTER(offset) \ - do { \ - if (UpdateHotnessCounter(thread, sp, acc, offset)) { \ - RESTORE_ACC(); \ - } \ - } while (false) -#else -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define UPDATE_HOTNESS_COUNTER(offset) static_cast(0) -#define UPDATE_HOTNESS_COUNTER_NON_ACC(offset) static_cast(0) -#endif - -#define READ_INST_OP() READ_INST_8(0) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_4_0() (READ_INST_8(1) & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_4_1() (READ_INST_8(1) >> 4 & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_4_2() (READ_INST_8(2) & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_4_3() (READ_INST_8(2) >> 4 & 0xf) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_0() READ_INST_8(1) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_1() READ_INST_8(2) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_2() READ_INST_8(3) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_3() READ_INST_8(4) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_4() READ_INST_8(5) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_5() READ_INST_8(6) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_6() READ_INST_8(7) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_7() READ_INST_8(8) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8_8() READ_INST_8(9) // NOLINT(hicpp-signed-bitwise, cppcoreguidelines-macro-usage) -#define READ_INST_8(offset) (*(pc + offset)) -#define MOVE_AND_READ_INST_8(currentInst, offset) \ - currentInst <<= 8; \ - currentInst += READ_INST_8(offset); \ - -#define READ_INST_16_0() READ_INST_16(2) -#define READ_INST_16_1() READ_INST_16(3) -#define READ_INST_16_2() READ_INST_16(4) -#define READ_INST_16_3() READ_INST_16(5) -#define READ_INST_16_5() READ_INST_16(7) -#define READ_INST_16(offset) \ - ({ \ - uint16_t currentInst = READ_INST_8(offset); \ - MOVE_AND_READ_INST_8(currentInst, offset - 1) \ - }) - -#define READ_INST_32_0() READ_INST_32(4) -#define READ_INST_32_1() READ_INST_32(5) -#define READ_INST_32_2() READ_INST_32(6) -#define READ_INST_32(offset) \ - ({ \ - uint32_t currentInst = READ_INST_8(offset); \ - MOVE_AND_READ_INST_8(currentInst, offset - 1) \ - MOVE_AND_READ_INST_8(currentInst, offset - 2) \ - MOVE_AND_READ_INST_8(currentInst, offset - 3) \ - }) - -#define READ_INST_64_0() \ - ({ \ - uint64_t currentInst = READ_INST_8(8); \ - MOVE_AND_READ_INST_8(currentInst, 7) \ - MOVE_AND_READ_INST_8(currentInst, 6) \ - MOVE_AND_READ_INST_8(currentInst, 5) \ - MOVE_AND_READ_INST_8(currentInst, 4) \ - MOVE_AND_READ_INST_8(currentInst, 3) \ - MOVE_AND_READ_INST_8(currentInst, 2) \ - MOVE_AND_READ_INST_8(currentInst, 1) \ - }) - -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GET_VREG(idx) (sp[idx]) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define GET_VREG_VALUE(idx) (JSTaggedValue(sp[idx])) // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) -// NOLINTNEXTLINE(cppcoreguidelines-macro-usage) -#define SET_VREG(idx, val) (sp[idx] = (val)); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) -#define GET_ACC() (acc) // NOLINT(cppcoreguidelines-macro-usage) -#define SET_ACC(val) (acc = val); // NOLINT(cppcoreguidelines-macro-usage) - -JSTaggedValue EcmaInterpreter::ExecuteNative(JSThread *thread, const CallParams& params) -{ - JSTaggedType *sp = const_cast(thread->GetCurrentSPFrame()); - JSMethod *methodToCall = params.callTarget->GetCallTarget(); - ASSERT(methodToCall->GetNumVregs() == 0); - uint32_t numActualArgs = params.argc + RESERVED_CALL_ARGCOUNT; - // Tags and values of thread, new_tgt and argv_length are put into frames too for native frames - // NOLINTNEXTLINE(hicpp-signed-bitwise) - size_t frameSize = FRAME_STATE_SIZE + numActualArgs; - JSTaggedType *newSp = sp - frameSize; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) - if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { - return JSTaggedValue::Undefined(); - } - - EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, numActualArgs, reinterpret_cast(newSp)); - newSp[RESERVED_INDEX_CALL_TARGET] = reinterpret_cast(params.callTarget); - newSp[RESERVED_INDEX_NEW_TARGET] = params.newTarget; - newSp[RESERVED_INDEX_THIS] = params.thisArg; - for (size_t i = 0; i < params.argc; i++) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[i + RESERVED_CALL_ARGCOUNT] = params.argv[i]; - } - - FrameState *state = GET_FRAME(newSp); - state->prev = sp; - state->pc = nullptr; - state->sp = newSp; - state->method = methodToCall; - thread->SetCurrentSPFrame(newSp); - LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call."; - JSTaggedValue tagged = - reinterpret_cast(const_cast(methodToCall->GetNativePointer()))(&ecmaRuntimeCallInfo); - LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call."; - thread->SetCurrentSPFrame(sp); - return tagged; -} - -JSTaggedValue EcmaInterpreter::Execute(JSThread *thread, const CallParams& params) -{ - JSMethod *method = params.callTarget->GetCallTarget(); - ASSERT(thread->IsEcmaInterpreter()); - if (method->IsNative()) { - return EcmaInterpreter::ExecuteNative(thread, params); - } - - JSTaggedType *originalPrevSp = const_cast(thread->GetCurrentSPFrame()); - - // push break state - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - JSTaggedType *newSp = originalPrevSp - FRAME_STATE_SIZE; - if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { - return JSTaggedValue::Undefined(); - } - FrameState *breakState = GET_FRAME(newSp); - breakState->pc = nullptr; - breakState->sp = nullptr; - breakState->prev = originalPrevSp; - breakState->numActualArgs = 0; - JSTaggedType *prevSp = newSp; - - uint32_t numActualArgs = params.argc + RESERVED_CALL_ARGCOUNT; - // push method frame - uint32_t numVregs = method->GetNumVregs(); - uint32_t numDeclaredArgs = method->GetNumArgs(); - size_t frameSize = FRAME_STATE_SIZE + numVregs + std::max(numDeclaredArgs, numActualArgs); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp = prevSp - frameSize; - if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { - return JSTaggedValue::Undefined(); - } - // push args - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + RESERVED_INDEX_CALL_TARGET] = reinterpret_cast(params.callTarget); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + RESERVED_INDEX_NEW_TARGET] = params.newTarget; - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + RESERVED_INDEX_THIS] = params.thisArg; - for (size_t i = 0; i < params.argc; i++) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + i + RESERVED_CALL_ARGCOUNT] = params.argv[i]; - } - InterpreterFrameCopyArgs(newSp, numVregs, numActualArgs, numDeclaredArgs); - - const uint8_t *pc = JSMethod::Cast(method)->GetBytecodeArray(); - FrameState *state = GET_FRAME(newSp); - state->pc = pc; - state->sp = newSp; - state->method = method; - state->acc = JSTaggedValue::Hole(); - JSHandle callTargetHandle(thread, params.callTarget); - ASSERT(callTargetHandle->IsJSFunction()); - JSHandle thisFunc = JSHandle::Cast(callTargetHandle); - ConstantPool *constpool = ConstantPool::Cast(thisFunc->GetConstantPool().GetTaggedObject()); - state->constpool = constpool; - state->profileTypeInfo = thisFunc->GetProfileTypeInfo(); - state->prev = prevSp; - state->numActualArgs = numActualArgs; - - JSTaggedValue env = thisFunc->GetLexicalEnv(); - state->env = env; - - thread->SetCurrentSPFrame(newSp); - - LOG(DEBUG, INTERPRETER) << "break Entry: Runtime Call " << std::hex << reinterpret_cast(newSp) << " " - << std::hex << reinterpret_cast(pc); - - EcmaInterpreter::RunInternal(thread, constpool, pc, newSp); - - // NOLINTNEXTLINE(readability-identifier-naming) - const JSTaggedValue resAcc = state->acc; - // pop frame - thread->SetCurrentSPFrame(originalPrevSp); - - return resAcc; -} - -JSTaggedValue EcmaInterpreter::GeneratorReEnterInterpreter(JSThread *thread, JSHandle context) -{ - [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle func = JSHandle::Cast(JSHandle(thread, context->GetMethod())); - JSMethod *method = func->GetCallTarget(); - - JSTaggedType *currentSp = const_cast(thread->GetCurrentSPFrame()); - - // push break frame - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - JSTaggedType *breakSp = currentSp - FRAME_STATE_SIZE; - if (thread->DoStackOverflowCheck(breakSp) || thread->HasPendingException()) { - return JSTaggedValue::Exception(); - } - FrameState *breakState = GET_FRAME(breakSp); - breakState->pc = nullptr; - breakState->sp = nullptr; - breakState->prev = currentSp; - breakState->numActualArgs = 0; - - // create new frame and resume sp and pc - uint32_t nregs = context->GetNRegs().GetInt(); - size_t newFrameSize = FRAME_STATE_SIZE + nregs; - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic - JSTaggedType *newSp = breakSp - newFrameSize; - if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { - return JSTaggedValue::Exception(); - } - JSHandle regsArray(thread, context->GetRegsArray()); - for (size_t i = 0; i < nregs; i++) { - newSp[i] = regsArray->Get(i).GetRawData(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - } - ConstantPool *constpool = ConstantPool::Cast(func->GetConstantPool().GetTaggedObject()); - JSTaggedValue pcOffset = context->GetBCOffset(); - // pc = first_inst + offset + size(Opcode::SUSPENDGENERATOR_IMM8_V8_V8) - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - const uint8_t *resumePc = JSMethod::Cast(method)->GetBytecodeArray() + static_cast(pcOffset.GetInt()) + - BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8); - - FrameState *state = GET_FRAME(newSp); - state->pc = resumePc; - state->sp = newSp; - state->method = method; - state->constpool = constpool; - state->profileTypeInfo = func->GetProfileTypeInfo(); - state->acc = context->GetAcc(); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - state->prev = breakSp; - JSTaggedValue env = context->GetLexicalEnv(); - state->env = env; - // execute interpreter - thread->SetCurrentSPFrame(newSp); - EcmaInterpreter::RunInternal(thread, constpool, resumePc, newSp); - - JSTaggedValue res = state->acc; - // pop frame - thread->SetCurrentSPFrame(currentSp); - - return res; -} - -void EcmaInterpreter::ChangeGenContext(JSThread *thread, JSHandle context) -{ - [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle func = JSHandle::Cast(JSHandle(thread, context->GetMethod())); - JSMethod *method = func->GetCallTarget(); - - JSTaggedType *currentSp = const_cast(thread->GetCurrentSPFrame()); - - // push break frame - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - JSTaggedType *breakSp = currentSp - FRAME_STATE_SIZE; - if (thread->DoStackOverflowCheck(breakSp) || thread->HasPendingException()) { - return; - } - FrameState *breakState = GET_FRAME(breakSp); - breakState->pc = nullptr; - breakState->sp = nullptr; - breakState->prev = currentSp; - - // create new frame and resume sp and pc - uint32_t nregs = context->GetNRegs().GetInt(); - size_t newFrameSize = FRAME_STATE_SIZE + nregs; - - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic - JSTaggedType *newSp = breakSp - newFrameSize; - if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { - return; - } - JSHandle regsArray(thread, context->GetRegsArray()); - for (size_t i = 0; i < nregs; i++) { - newSp[i] = regsArray->Get(i).GetRawData(); // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - } - ConstantPool *constpool = ConstantPool::Cast(func->GetConstantPool().GetTaggedObject()); - JSTaggedValue pcOffset = context->GetBCOffset(); - // pc = first_inst + offset - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - const uint8_t *pc = JSMethod::Cast(method)->GetBytecodeArray() + static_cast(pcOffset.GetInt()); - - FrameState *state = GET_FRAME(newSp); - state->pc = pc; - state->sp = newSp; - state->method = method; - state->constpool = constpool; - state->profileTypeInfo = func->GetProfileTypeInfo(); - state->acc = context->GetAcc(); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - state->prev = breakSp; - state->env = context->GetLexicalEnv(); - - thread->SetCurrentSPFrame(newSp); -} - -void EcmaInterpreter::ResumeContext(JSThread *thread) -{ - JSTaggedType *sp = const_cast(thread->GetCurrentSPFrame()); - FrameState *state = GET_FRAME(sp); - thread->SetCurrentSPFrame(state->prev); -} - -void EcmaInterpreter::NotifyBytecodePcChanged(JSThread *thread) -{ - EcmaFrameHandler frameHandler(thread); - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { - if (frameHandler.IsBreakFrame()) { - continue; - } - JSMethod *method = frameHandler.GetMethod(); - // Skip builtins method - if (method->IsNative()) { - continue; - } - auto bcOffset = frameHandler.GetBytecodeOffset(); - Runtime::GetCurrent()->GetNotificationManager()->BytecodePcChangedEvent(thread, method, bcOffset); - return; - } -} - -// NOLINTNEXTLINE(readability-function-size) -NO_UB_SANITIZE void EcmaInterpreter::RunInternal(JSThread *thread, ConstantPool *constpool, const uint8_t *pc, - JSTaggedType *sp) -{ - INTERPRETER_TRACE(thread, RunInternal); - uint8_t opcode = READ_INST_OP(); - JSTaggedValue acc = JSTaggedValue::Hole(); - EcmaVM *ecmaVm = thread->GetEcmaVM(); - JSHandle globalEnv = ecmaVm->GetGlobalEnv(); - JSTaggedValue globalObj = globalEnv->GetGlobalObject(); - ObjectFactory *factory = ecmaVm->GetFactory(); - - constexpr size_t numOps = 0x100; - - static std::array instDispatchTable{ -#include "templates/instruction_dispatch.inl" - }; - - static std::array debugDispatchTable{ -#include "templates/debugger_instruction_dispatch.inl" - }; - - std::array dispatchTable = instDispatchTable; - CHECK_SWITCH_TO_DEBUGGER_TABLE(); - goto *dispatchTable[opcode]; - - HANDLE_OPCODE(HANDLE_MOV_V4_V4) { - uint16_t vdst = READ_INST_4_0(); - uint16_t vsrc = READ_INST_4_1(); - LOG_INST() << "mov v" << vdst << ", v" << vsrc; - uint64_t value = GET_VREG(vsrc); - SET_VREG(vdst, value) - DISPATCH(BytecodeInstruction::Format::V4_V4); - } - - HANDLE_OPCODE(HANDLE_MOV_DYN_V8_V8) { - uint16_t vdst = READ_INST_8_0(); - uint16_t vsrc = READ_INST_8_1(); - LOG_INST() << "mov.dyn v" << vdst << ", v" << vsrc; - uint64_t value = GET_VREG(vsrc); - SET_VREG(vdst, value) - DISPATCH(BytecodeInstruction::Format::V8_V8); - } - HANDLE_OPCODE(HANDLE_MOV_DYN_V16_V16) { - uint16_t vdst = READ_INST_16_0(); - uint16_t vsrc = READ_INST_16_2(); - LOG_INST() << "mov.dyn v" << vdst << ", v" << vsrc; - uint64_t value = GET_VREG(vsrc); - SET_VREG(vdst, value) - DISPATCH(BytecodeInstruction::Format::V16_V16); - } - HANDLE_OPCODE(HANDLE_LDA_STR_ID32) { - uint32_t stringId = READ_INST_32_0(); - LOG_INST() << "lda.str " << std::hex << stringId; - SET_ACC(constpool->GetObjectFromCache(stringId)); - DISPATCH(BytecodeInstruction::Format::ID32); - } - HANDLE_OPCODE(HANDLE_JMP_IMM8) { - int8_t offset = READ_INST_8_0(); - UPDATE_HOTNESS_COUNTER(offset); - LOG_INST() << "jmp " << std::hex << static_cast(offset); - DISPATCH_OFFSET(offset); - } - HANDLE_OPCODE(HANDLE_JMP_IMM16) { - int16_t offset = READ_INST_16_0(); - UPDATE_HOTNESS_COUNTER(offset); - LOG_INST() << "jmp " << std::hex << static_cast(offset); - DISPATCH_OFFSET(offset); - } - HANDLE_OPCODE(HANDLE_JMP_IMM32) { - int32_t offset = READ_INST_32_0(); - UPDATE_HOTNESS_COUNTER(offset); - LOG_INST() << "jmp " << std::hex << offset; - DISPATCH_OFFSET(offset); - } - HANDLE_OPCODE(HANDLE_JEQZ_IMM8) { - int8_t offset = READ_INST_8_0(); - LOG_INST() << "jeqz ->\t" - << "cond jmpz " << std::hex << static_cast(offset); - if (GET_ACC() == JSTaggedValue::False() || (GET_ACC().IsInt() && GET_ACC().GetInt() == 0) || - (GET_ACC().IsDouble() && GET_ACC().GetDouble() == 0)) { - UPDATE_HOTNESS_COUNTER(offset); - DISPATCH_OFFSET(offset); - } else { - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - } - HANDLE_OPCODE(HANDLE_JEQZ_IMM16) { - int16_t offset = READ_INST_16_0(); - LOG_INST() << "jeqz ->\t" - << "cond jmpz " << std::hex << static_cast(offset); - if (GET_ACC() == JSTaggedValue::False() || (GET_ACC().IsInt() && GET_ACC().GetInt() == 0) || - (GET_ACC().IsDouble() && GET_ACC().GetDouble() == 0)) { - UPDATE_HOTNESS_COUNTER(offset); - DISPATCH_OFFSET(offset); - } else { - DISPATCH(BytecodeInstruction::Format::IMM16); - } - } - HANDLE_OPCODE(HANDLE_JNEZ_IMM8) { - int8_t offset = READ_INST_8_0(); - LOG_INST() << "jnez ->\t" - << "cond jmpz " << std::hex << static_cast(offset); - if (GET_ACC() == JSTaggedValue::True() || (GET_ACC().IsInt() && GET_ACC().GetInt() != 0) || - (GET_ACC().IsDouble() && GET_ACC().GetDouble() != 0)) { - UPDATE_HOTNESS_COUNTER(offset); - DISPATCH_OFFSET(offset); - } else { - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - } - HANDLE_OPCODE(HANDLE_JNEZ_IMM16) { - int16_t offset = READ_INST_16_0(); - LOG_INST() << "jnez ->\t" - << "cond jmpz " << std::hex << static_cast(offset); - if (GET_ACC() == JSTaggedValue::True() || (GET_ACC().IsInt() && GET_ACC().GetInt() != 0) || - (GET_ACC().IsDouble() && GET_ACC().GetDouble() != 0)) { - UPDATE_HOTNESS_COUNTER(offset); - DISPATCH_OFFSET(offset); - } else { - DISPATCH(BytecodeInstruction::Format::IMM16); - } - } - HANDLE_OPCODE(HANDLE_LDA_DYN_V8) { - uint16_t vsrc = READ_INST_8_0(); - LOG_INST() << "lda.dyn v" << vsrc; - uint64_t value = GET_VREG(vsrc); - SET_ACC(JSTaggedValue(value)) - DISPATCH(BytecodeInstruction::Format::V8); - } - HANDLE_OPCODE(HANDLE_STA_DYN_V8) { - uint16_t vdst = READ_INST_8_0(); - LOG_INST() << "sta.dyn v" << vdst; - SET_VREG(vdst, GET_ACC().GetRawData()) - DISPATCH(BytecodeInstruction::Format::V8); - } - HANDLE_OPCODE(HANDLE_LDAI_DYN_IMM32) { - int32_t imm = READ_INST_32_0(); - LOG_INST() << "ldai.dyn " << std::hex << imm; - SET_ACC(JSTaggedValue(imm)) - DISPATCH(BytecodeInstruction::Format::IMM32); - } - - HANDLE_OPCODE(HANDLE_FLDAI_DYN_IMM64) { - auto imm = bit_cast(READ_INST_64_0()); - LOG_INST() << "fldai.dyn " << imm; - SET_ACC(JSTaggedValue(imm)) - DISPATCH(BytecodeInstruction::Format::IMM64); - } - { - uint32_t actualNumArgs; - uint32_t funcReg; - bool callThis; - bool callRange; - - HANDLE_OPCODE(HANDLE_CALLARG0DYN_PREF_V8) { - funcReg = READ_INST_8_1(); - actualNumArgs = ActualNumArgsOfCall::CALLARG0; - - LOG_INST() << "callarg0.dyn " - << "v" << funcReg; - callRange = false; - callThis = false; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) - goto handlerCall; - } - HANDLE_OPCODE(HANDLE_CALLARG1DYN_PREF_V8_V8) { - funcReg = READ_INST_8_1(); - actualNumArgs = ActualNumArgsOfCall::CALLARG1; - - LOG_INST() << "callarg1.dyn " - << "v" << funcReg << ", v" << READ_INST_8_2(); - callRange = false; - callThis = false; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) - goto handlerCall; - } - HANDLE_OPCODE(HANDLE_CALLARGS2DYN_PREF_V8_V8_V8) { - funcReg = READ_INST_8_1(); - actualNumArgs = ActualNumArgsOfCall::CALLARGS2; - - LOG_INST() << "callargs2.dyn " - << "v" << funcReg << ", v" << READ_INST_8_2() << ", v" << READ_INST_8_3(); - callRange = false; - callThis = false; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) - goto handlerCall; - } - HANDLE_OPCODE(HANDLE_CALLARGS3DYN_PREF_V8_V8_V8_V8) { - funcReg = READ_INST_8_1(); - actualNumArgs = ActualNumArgsOfCall::CALLARGS3; - - LOG_INST() << "callargs3.dyn " - << "v" << funcReg << ", v" << READ_INST_8_2() << ", v" << READ_INST_8_3() - << ", v" << READ_INST_8_4(); - callRange = false; - callThis = false; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) - goto handlerCall; - } - HANDLE_OPCODE(HANDLE_CALLITHISRANGEDYN_PREF_IMM16_V8) { - actualNumArgs = READ_INST_16_1() + 2; // 2: func and newTarget - funcReg = READ_INST_8_3(); - - LOG_INST() << "calli.dyn.this.range " << actualNumArgs << ", v" << funcReg; - callRange = true; - callThis = true; - // NOLINTNEXTLINE(cppcoreguidelines-avoid-goto, hicpp-avoid-goto) - goto handlerCall; - } - HANDLE_OPCODE(HANDLE_CALLSPREADDYN_PREF_V8_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - uint16_t v2 = READ_INST_8_3(); - LOG_INST() << "intrinsics::callspreaddyn" - << " v" << v0 << " v" << v1 << " v" << v2; - JSTaggedValue func = GET_VREG_VALUE(v0); - JSTaggedValue obj = GET_VREG_VALUE(v1); - JSTaggedValue array = GET_VREG_VALUE(v2); - - JSTaggedValue res = SlowRuntimeStub::CallSpreadDyn(thread, func, obj, array); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8); - } - HANDLE_OPCODE(HANDLE_CALLIRANGEDYN_PREF_IMM16_V8) { - actualNumArgs = READ_INST_16_1() + NUM_MANDATORY_JSFUNC_ARGS; - funcReg = READ_INST_8_3(); - callRange = true; - callThis = false; - LOG_INST() << "calli.rangedyn " << actualNumArgs << ", v" << funcReg; - - handlerCall: - JSTaggedValue func = GET_VREG_VALUE(funcReg); - if (!func.IsCallable()) { - { - [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle error = factory->GetJSError(ErrorType::TYPE_ERROR, "is not callable"); - thread->SetException(error.GetTaggedValue()); - } - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - ECMAObject *thisFunc = ECMAObject::Cast(func.GetTaggedObject()); - JSMethod *methodToCall = thisFunc->GetCallTarget(); - if (methodToCall->IsNative()) { - ASSERT(methodToCall->GetNumVregs() == 0); - // Tags and values of thread, new_tgt and argv_length are put into frames too for native frames - // NOLINTNEXTLINE(hicpp-signed-bitwise) - size_t frameSize = FRAME_STATE_SIZE + actualNumArgs; - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - JSTaggedType *newSp = sp - frameSize; - if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - EcmaRuntimeCallInfo ecmaRuntimeCallInfo(thread, actualNumArgs, - reinterpret_cast(newSp)); - uint32_t startIdx = 0; - // func - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = static_cast(ToUintPtr(thisFunc)); - // new target - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; - - if (callRange) { - size_t copyArgs = actualNumArgs - 2; // 2: skip func and new target - if (!callThis) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; - // skip this - copyArgs--; - } - for (size_t i = 1; i <= copyArgs; i++) { - JSTaggedValue arg = GET_VREG_VALUE(funcReg + i); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = arg.GetRawData(); - } - } else { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx] = JSTaggedValue::VALUE_UNDEFINED; - switch (actualNumArgs) { - case ActualNumArgsOfCall::CALLARGS3: { - uint32_t reg = READ_INST_8_4(); - JSTaggedValue arg = GET_VREG_VALUE(reg); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[ActualNumArgsOfCall::CALLARGS3 - 1] = arg.GetRawData(); - [[fallthrough]]; - } - case ActualNumArgsOfCall::CALLARGS2: { - uint32_t reg = READ_INST_8_3(); - JSTaggedValue arg = GET_VREG_VALUE(reg); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[ActualNumArgsOfCall::CALLARGS2 - 1] = arg.GetRawData(); - [[fallthrough]]; - } - case ActualNumArgsOfCall::CALLARG1: { - uint32_t reg = READ_INST_8_2(); - JSTaggedValue arg = GET_VREG_VALUE(reg); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[ActualNumArgsOfCall::CALLARG1 - 1] = arg.GetRawData(); - break; - } - case ActualNumArgsOfCall::CALLARG0: { - break; - } - default: - UNREACHABLE(); - } - } - - FrameState *state = GET_FRAME(newSp); - state->prev = sp; - state->pc = nullptr; - state->sp = newSp; - state->method = methodToCall; - thread->SetCurrentSPFrame(newSp); - LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call."; - JSTaggedValue retValue = reinterpret_cast( - const_cast(methodToCall->GetNativePointer()))(&ecmaRuntimeCallInfo); - if (UNLIKELY(thread->HasPendingException())) { - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call."; - thread->SetCurrentSPFrame(sp); - SET_ACC(retValue); - size_t jumpSize = GetJumpSizeAfterCall(pc); - DISPATCH_OFFSET(jumpSize); - } else { - if (JSFunction::Cast(thisFunc)->IsClassConstructor()) { - { - [[maybe_unused]] EcmaHandleScope handleScope(thread); - JSHandle error = - factory->GetJSError(ErrorType::TYPE_ERROR, "class constructor cannot called without 'new'"); - thread->SetException(error.GetTaggedValue()); - } - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - SAVE_PC(); - uint32_t numVregs = methodToCall->GetNumVregs(); - uint32_t numDeclaredArgs = methodToCall->GetNumArgs(); - size_t frameSize = FRAME_STATE_SIZE + numVregs + std::max(numDeclaredArgs, actualNumArgs); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - JSTaggedType *newSp = sp - frameSize; - if (thread->DoStackOverflowCheck(newSp) || thread->HasPendingException()) { - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - - // copy args - uint32_t startIdx = numVregs; - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = static_cast(ToUintPtr(thisFunc)); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; - if (callRange) { - size_t copyArgs = actualNumArgs - 2; // 2: skip func and new target - if (!callThis) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = JSTaggedValue::VALUE_UNDEFINED; - // skip this - copyArgs--; - } - for (size_t i = 1; i <= copyArgs; i++) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx++] = sp[funcReg + i]; - } - } else { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[startIdx] = JSTaggedValue::VALUE_UNDEFINED; - switch (actualNumArgs) { - case ActualNumArgsOfCall::CALLARGS3: { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + ActualNumArgsOfCall::CALLARGS3 - 1] = sp[READ_INST_8_4()]; - [[fallthrough]]; - } - case ActualNumArgsOfCall::CALLARGS2: { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + ActualNumArgsOfCall::CALLARGS2 - 1] = sp[READ_INST_8_3()]; - [[fallthrough]]; - } - case ActualNumArgsOfCall::CALLARG1: { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + ActualNumArgsOfCall::CALLARG1 - 1] = sp[READ_INST_8_2()]; - break; - } - case ActualNumArgsOfCall::CALLARG0: { - break; - } - default: - UNREACHABLE(); - } - } - InterpreterFrameCopyArgs(newSp, numVregs, actualNumArgs, numDeclaredArgs); - - FrameState *state = GET_FRAME(newSp); - state->prev = sp; - state->pc = pc = JSMethod::Cast(methodToCall)->GetBytecodeArray(); - state->sp = sp = newSp; - state->method = methodToCall; - state->acc = JSTaggedValue::Hole(); - state->constpool = constpool = - ConstantPool::Cast(JSFunction::Cast(thisFunc)->GetConstantPool().GetTaggedObject()); - state->profileTypeInfo = JSFunction::Cast(thisFunc)->GetProfileTypeInfo(); - state->numActualArgs = actualNumArgs; - JSTaggedValue env = JSFunction::Cast(thisFunc)->GetLexicalEnv(); - state->env = env; - - thread->SetCurrentSPFrame(newSp); - LOG(DEBUG, INTERPRETER) << "Entry: Runtime Call " << std::hex << reinterpret_cast(sp) << " " - << std::hex << reinterpret_cast(pc); - DISPATCH_OFFSET(0); - } - } - } - HANDLE_OPCODE(HANDLE_RETURN_DYN) { - LOG_INST() << "return.dyn"; - FrameState *state = GET_FRAME(sp); - LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call " << std::hex << reinterpret_cast(state->sp) << " " - << std::hex << reinterpret_cast(state->pc); - [[maybe_unused]] auto fistPC = state->method->GetInstructions(); - UPDATE_HOTNESS_COUNTER(-(pc - fistPC)); - sp = state->prev; - ASSERT(sp != nullptr); - FrameState *prevState = GET_FRAME(sp); - pc = prevState->pc; - - // break frame - if (pc == nullptr) { - state->acc = acc; - return; - } - thread->SetCurrentSPFrame(sp); - - constpool = prevState->constpool; - - size_t jumpSize = GetJumpSizeAfterCall(pc); - DISPATCH_OFFSET(jumpSize); - } - HANDLE_OPCODE(HANDLE_RETURNUNDEFINED_PREF) { - LOG_INST() << "return.undefined"; - FrameState *state = GET_FRAME(sp); - LOG(DEBUG, INTERPRETER) << "Exit: Runtime Call " << std::hex << reinterpret_cast(sp) << " " - << std::hex << reinterpret_cast(state->pc); - [[maybe_unused]] auto fistPC = state->method->GetInstructions(); - UPDATE_HOTNESS_COUNTER_NON_ACC(-(pc - fistPC)); - sp = state->prev; - ASSERT(sp != nullptr); - FrameState *prevState = GET_FRAME(sp); - pc = prevState->pc; - - // break frame - if (pc == nullptr) { - state->acc = JSTaggedValue::Undefined(); - return; - } - thread->SetCurrentSPFrame(sp); - - constpool = prevState->constpool; - - acc = JSTaggedValue::Undefined(); - size_t jumpSize = GetJumpSizeAfterCall(pc); - DISPATCH_OFFSET(jumpSize); - } - HANDLE_OPCODE(HANDLE_LDNAN_PREF) { - LOG_INST() << "intrinsics::ldnan"; - SET_ACC(JSTaggedValue(base::NAN_VALUE)); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDINFINITY_PREF) { - LOG_INST() << "intrinsics::ldinfinity"; - SET_ACC(JSTaggedValue(base::POSITIVE_INFINITY)); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDGLOBALTHIS_PREF) { - LOG_INST() << "intrinsics::ldglobalthis"; - SET_ACC(globalObj) - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDUNDEFINED_PREF) { - LOG_INST() << "intrinsics::ldundefined"; - SET_ACC(JSTaggedValue::Undefined()) - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDNULL_PREF) { - LOG_INST() << "intrinsics::ldnull"; - SET_ACC(JSTaggedValue::Null()) - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDSYMBOL_PREF) { - LOG_INST() << "intrinsics::ldsymbol"; - SET_ACC(globalEnv->GetSymbolFunction().GetTaggedValue()); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDGLOBAL_PREF) { - LOG_INST() << "intrinsics::ldglobal"; - SET_ACC(globalObj) - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDTRUE_PREF) { - LOG_INST() << "intrinsics::ldtrue"; - SET_ACC(JSTaggedValue::True()) - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDFALSE_PREF) { - LOG_INST() << "intrinsics::ldfalse"; - SET_ACC(JSTaggedValue::False()) - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_LDLEXENVDYN_PREF) { - LOG_INST() << "intrinsics::ldlexenvDyn "; - FrameState *state = GET_FRAME(sp); - JSTaggedValue currentLexenv = state->env; - SET_ACC(currentLexenv); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_GETUNMAPPEDARGS_PREF) { - LOG_INST() << "intrinsics::getunmappedargs"; - - FrameState *state = GET_FRAME(sp); - uint32_t numVregs = state->method->GetNumVregs(); - // Exclude func, newTarget and "this" - uint32_t actualNumArgs = state->numActualArgs - NUM_MANDATORY_JSFUNC_ARGS; - uint32_t startIdx = numVregs + NUM_MANDATORY_JSFUNC_ARGS; - - JSTaggedValue res = SlowRuntimeStub::GetUnmapedArgs(thread, sp, actualNumArgs, startIdx); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONENTER_PREF) { - LOG_INST() << "intrinsics::asyncfunctionenter"; - JSTaggedValue res = SlowRuntimeStub::AsyncFunctionEnter(thread); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_TONUMBER_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::tonumber" - << " v" << v0; - JSTaggedValue value = GET_VREG_VALUE(v0); - if (value.IsNumber()) { - // fast path - SET_ACC(value); - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::ToNumber(thread, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_NEGDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::negdyn" - << " v" << v0; - JSTaggedValue value = GET_VREG_VALUE(v0); - // fast path - if (value.IsInt()) { - if (value.GetInt() == 0) { - SET_ACC(JSTaggedValue(-0.0)); - } else { - SET_ACC(JSTaggedValue(-value.GetInt())); - } - } else if (value.IsDouble()) { - SET_ACC(JSTaggedValue(-value.GetDouble())); - } else { // slow path - JSTaggedValue res = SlowRuntimeStub::NegDyn(thread, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_NOTDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::notdyn" - << " v" << v0; - JSTaggedValue value = GET_VREG_VALUE(v0); - int32_t number; - // number, fast path - if (value.IsInt()) { - number = static_cast(value.GetInt()); - SET_ACC(JSTaggedValue(~number)); // NOLINT(hicpp-signed-bitwise) - } else if (value.IsDouble()) { - number = base::NumberHelper::DoubleToInt(value.GetDouble(), base::INT32_BITS); - SET_ACC(JSTaggedValue(~number)); // NOLINT(hicpp-signed-bitwise) - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::NotDyn(thread, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_INCDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::incdyn" - << " v" << v0; - - JSTaggedValue value = GET_VREG_VALUE(v0); - // number fast path - if (value.IsInt()) { - int32_t a0 = value.GetInt(); - if (UNLIKELY(a0 == INT32_MAX)) { - auto ret = static_cast(a0) + 1.0; - SET_ACC(JSTaggedValue(ret)) - } else { - SET_ACC(JSTaggedValue(a0 + 1)) - } - } else if (value.IsDouble()) { - SET_ACC(JSTaggedValue(value.GetDouble() + 1.0)) - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::IncDyn(thread, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_DECDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::decdyn" - << " v" << v0; - - JSTaggedValue value = GET_VREG_VALUE(v0); - // number, fast path - if (value.IsInt()) { - int32_t a0 = value.GetInt(); - if (UNLIKELY(a0 == INT32_MIN)) { - auto ret = static_cast(a0) - 1.0; - SET_ACC(JSTaggedValue(ret)) - } else { - SET_ACC(JSTaggedValue(a0 - 1)) - } - } else if (value.IsDouble()) { - SET_ACC(JSTaggedValue(value.GetDouble() - 1.0)) - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::DecDyn(thread, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_THROWDYN_PREF) { - LOG_INST() << "intrinsics::throwdyn"; - SlowRuntimeStub::ThrowDyn(thread, GET_ACC()); - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - HANDLE_OPCODE(HANDLE_TYPEOFDYN_PREF) { - LOG_INST() << "intrinsics::typeofdyn"; - JSTaggedValue res = FastRuntimeStub::FastTypeOf(thread, GET_ACC()); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_GETPROPITERATOR_PREF) { - LOG_INST() << "intrinsics::getpropiterator"; - JSTaggedValue res = SlowRuntimeStub::GetPropIterator(thread, GET_ACC()); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_RESUMEGENERATOR_PREF_V8) { - LOG_INST() << "intrinsics::resumegenerator"; - uint16_t vs = READ_INST_8_1(); - JSGeneratorObject *obj = JSGeneratorObject::Cast(GET_VREG_VALUE(vs).GetTaggedObject()); - SET_ACC(obj->GetResumeResult()); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_GETRESUMEMODE_PREF_V8) { - LOG_INST() << "intrinsics::getresumemode"; - uint16_t vs = READ_INST_8_1(); - JSGeneratorObject *obj = JSGeneratorObject::Cast(GET_VREG_VALUE(vs).GetTaggedObject()); - SET_ACC(obj->GetResumeMode()); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_GETITERATOR_PREF) { - LOG_INST() << "intrinsics::getiterator"; - JSTaggedValue obj = GET_ACC(); - - // fast path: Generator obj is already store in acc - if (!obj.IsGeneratorObject()) { - // slow path - JSTaggedValue res = SlowRuntimeStub::GetIterator(thread, obj); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_THROWCONSTASSIGNMENT_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "throwconstassignment" - << " v" << v0; - SlowRuntimeStub::ThrowConstAssignment(thread, GET_VREG_VALUE(v0)); - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - HANDLE_OPCODE(HANDLE_THROWTHROWNOTEXISTS_PREF) { - LOG_INST() << "throwthrownotexists"; - - SlowRuntimeStub::ThrowThrowNotExists(thread); - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - HANDLE_OPCODE(HANDLE_THROWPATTERNNONCOERCIBLE_PREF) { - LOG_INST() << "throwpatternnoncoercible"; - - SlowRuntimeStub::ThrowPatternNonCoercible(thread); - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - HANDLE_OPCODE(HANDLE_THROWIFNOTOBJECT_PREF_V8) { - LOG_INST() << "throwifnotobject"; - uint16_t v0 = READ_INST_8_1(); - - JSTaggedValue value = GET_VREG_VALUE(v0); - // fast path - if (value.IsECMAObject()) { - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - - // slow path - SlowRuntimeStub::ThrowIfNotObject(thread); - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - HANDLE_OPCODE(HANDLE_ITERNEXT_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::iternext" - << " v" << v0; - JSTaggedValue iter = GET_VREG_VALUE(v0); - JSTaggedValue res = SlowRuntimeStub::IterNext(thread, iter); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_CLOSEITERATOR_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::closeiterator" - << " v" << v0; - JSTaggedValue iter = GET_VREG_VALUE(v0); - JSTaggedValue res = SlowRuntimeStub::CloseIterator(thread, iter); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_ADD2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::add2dyn" - << " v" << v0; - int32_t a0; - int32_t a1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - // number, fast path - if (left.IsInt() && right.IsInt()) { - a0 = left.GetInt(); - a1 = right.GetInt(); - if ((a0 > 0 && a1 > INT32_MAX - a0) || (a0 < 0 && a1 < INT32_MIN - a0)) { - auto ret = static_cast(a0) + static_cast(a1); - SET_ACC(JSTaggedValue(ret)) - } else { - SET_ACC(JSTaggedValue(a0 + a1)) - } - } else if (left.IsNumber() && right.IsNumber()) { - double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble(); - double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble(); - double ret = a0Double + a1Double; - SET_ACC(JSTaggedValue(ret)) - } else { - // one or both are not number, slow path - JSTaggedValue res = SlowRuntimeStub::Add2Dyn(thread, ecmaVm, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_SUB2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::sub2dyn" - << " v" << v0; - int32_t a0; - int32_t a1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - if (left.IsInt() && right.IsInt()) { - a0 = left.GetInt(); - a1 = -right.GetInt(); - if ((a0 > 0 && a1 > INT32_MAX - a0) || (a0 < 0 && a1 < INT32_MIN - a0)) { - auto ret = static_cast(a0) + static_cast(a1); - SET_ACC(JSTaggedValue(ret)) - } else { - SET_ACC(JSTaggedValue(a0 + a1)) - } - } else if (left.IsNumber() && right.IsNumber()) { - double a0Double = left.IsInt() ? left.GetInt() : left.GetDouble(); - double a1Double = right.IsInt() ? right.GetInt() : right.GetDouble(); - double ret = a0Double - a1Double; - SET_ACC(JSTaggedValue(ret)) - } else { - // one or both are not number, slow path - JSTaggedValue res = SlowRuntimeStub::Sub2Dyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_MUL2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::mul2dyn" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = acc; - JSTaggedValue value = FastRuntimeStub::FastMul(left, right); - if (!value.IsHole()) { - SET_ACC(value); - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::Mul2Dyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_DIV2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::div2dyn" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = acc; - // fast path - JSTaggedValue res = FastRuntimeStub::FastDiv(left, right); - if (!res.IsHole()) { - SET_ACC(res); - } else { - // slow path - JSTaggedValue slowRes = SlowRuntimeStub::Div2Dyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(slowRes); - SET_ACC(slowRes); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_MOD2DYN_PREF_V8) { - uint16_t vs = READ_INST_8_1(); - LOG_INST() << "intrinsics::mod2dyn" - << " v" << vs; - JSTaggedValue left = GET_VREG_VALUE(vs); - JSTaggedValue right = GET_ACC(); - // fast path - JSTaggedValue res = FastRuntimeStub::FastMod(left, right); - if (!res.IsHole()) { - SET_ACC(res); - } else { - // slow path - JSTaggedValue slowRes = SlowRuntimeStub::Mod2Dyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(slowRes); - SET_ACC(slowRes); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_EQDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::eqdyn" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = acc; - JSTaggedValue res = FastRuntimeStub::FastEqual(left, right); - if (!res.IsHole()) { - SET_ACC(res); - } else { - // slow path - res = SlowRuntimeStub::EqDyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_NOTEQDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::noteqdyn" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = acc; - - JSTaggedValue res = FastRuntimeStub::FastEqual(left, right); - if (!res.IsHole()) { - res = res.IsTrue() ? JSTaggedValue::False() : JSTaggedValue::True(); - SET_ACC(res); - } else { - // slow path - res = SlowRuntimeStub::NotEqDyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_LESSDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::lessdyn" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - if (left.IsNumber() && right.IsNumber()) { - // fast path - double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); - double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); - bool ret = JSTaggedValue::StrictNumberCompare(valueA, valueB) == ComparisonResult::LESS; - SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::LessDyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_LESSEQDYN_PREF_V8) { - uint16_t vs = READ_INST_8_1(); - LOG_INST() << "intrinsics::lesseqdyn " - << " v" << vs; - JSTaggedValue left = GET_VREG_VALUE(vs); - JSTaggedValue right = GET_ACC(); - if (left.IsNumber() && right.IsNumber()) { - // fast path - double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); - double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); - bool ret = JSTaggedValue::StrictNumberCompare(valueA, valueB) <= ComparisonResult::EQUAL; - SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::LessEqDyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_GREATERDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::greaterdyn" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = acc; - if (left.IsNumber() && right.IsNumber()) { - // fast path - double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); - double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); - bool ret = JSTaggedValue::StrictNumberCompare(valueA, valueB) == ComparisonResult::GREAT; - SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::GreaterDyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_GREATEREQDYN_PREF_V8) { - uint16_t vs = READ_INST_8_1(); - LOG_INST() << "intrinsics::greateqdyn " - << " v" << vs; - JSTaggedValue left = GET_VREG_VALUE(vs); - JSTaggedValue right = GET_ACC(); - if (left.IsNumber() && right.IsNumber()) { - // fast path - double valueA = left.IsInt() ? static_cast(left.GetInt()) : left.GetDouble(); - double valueB = right.IsInt() ? static_cast(right.GetInt()) : right.GetDouble(); - ComparisonResult comparison = JSTaggedValue::StrictNumberCompare(valueA, valueB); - bool ret = (comparison == ComparisonResult::GREAT) || (comparison == ComparisonResult::EQUAL); - SET_ACC(ret ? JSTaggedValue::True() : JSTaggedValue::False()) - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::GreaterEqDyn(thread, left, right); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_SHL2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::shl2dyn" - << " v" << v0; - int32_t opNumber0; - int32_t opNumber1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - // both number, fast path - if (left.IsInt() && right.IsInt()) { - opNumber0 = left.GetInt(); - opNumber1 = right.GetInt(); - } else if (left.IsNumber() && right.IsNumber()) { - opNumber0 = - left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); - opNumber1 = - right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); - } else { - // slow path - SAVE_ACC(); - JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); - RESTORE_ACC(); - right = GET_ACC(); // Maybe moved by GC - JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, right); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); - opNumber0 = taggedNumber0.GetInt(); - opNumber1 = taggedNumber1.GetInt(); - } - - uint32_t shift = - static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) - using unsigned_type = std::make_unsigned_t; - auto ret = - static_cast(static_cast(opNumber0) << shift); // NOLINT(hicpp-signed-bitwise) - SET_ACC(JSTaggedValue(ret)) - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_SHR2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::shr2dyn" - << " v" << v0; - int32_t opNumber0; - int32_t opNumber1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - // both number, fast path - if (left.IsInt() && right.IsInt()) { - opNumber0 = left.GetInt(); - opNumber1 = right.GetInt(); - } else if (left.IsNumber() && right.IsNumber()) { - opNumber0 = - left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); - opNumber1 = - right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); - } else { - // slow path - SAVE_ACC(); - JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); - RESTORE_ACC(); - right = GET_ACC(); // Maybe moved by GC - JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, right); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); - opNumber0 = taggedNumber0.GetInt(); - opNumber1 = taggedNumber1.GetInt(); - } - - uint32_t shift = - static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) - auto ret = static_cast(opNumber0 >> shift); // NOLINT(hicpp-signed-bitwise) - SET_ACC(JSTaggedValue(ret)) - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_ASHR2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::ashr2dyn" - << " v" << v0; - int32_t opNumber0; - int32_t opNumber1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - if (left.IsInt() && right.IsInt()) { - opNumber0 = left.GetInt(); - opNumber1 = right.GetInt(); - } else if (left.IsNumber() && right.IsNumber()) { - opNumber0 = - left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); - opNumber1 = - right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); - } else { - // slow path - SAVE_ACC(); - JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, left); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); - RESTORE_ACC(); - right = GET_ACC(); // Maybe moved by GC - JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithUint32(thread, right); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); - opNumber0 = taggedNumber0.GetInt(); - opNumber1 = taggedNumber1.GetInt(); - } - - uint32_t shift = - static_cast(opNumber1) & 0x1f; // NOLINT(hicpp-signed-bitwise, readability-magic-numbers) - using unsigned_type = std::make_unsigned_t; - auto ret = - static_cast(static_cast(opNumber0) >> shift); // NOLINT(hicpp-signed-bitwise) - SET_ACC(JSTaggedValue(ret)) - - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_AND2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::and2dyn" - << " v" << v0; - int32_t opNumber0; - int32_t opNumber1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - // both number, fast path - if (left.IsInt() && right.IsInt()) { - opNumber0 = left.GetInt(); - opNumber1 = right.GetInt(); - } else if (left.IsNumber() && right.IsNumber()) { - opNumber0 = - left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); - opNumber1 = - right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); - } else { - // slow path - SAVE_ACC(); - JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); - RESTORE_ACC(); - right = GET_ACC(); // Maybe moved by GC - JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, right); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); - opNumber0 = taggedNumber0.GetInt(); - opNumber1 = taggedNumber1.GetInt(); - } - // NOLINT(hicpp-signed-bitwise) - auto ret = static_cast(opNumber0) & static_cast(opNumber1); - SET_ACC(JSTaggedValue(static_cast(ret))) - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_OR2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::or2dyn" - << " v" << v0; - int32_t opNumber0; - int32_t opNumber1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - // both number, fast path - if (left.IsInt() && right.IsInt()) { - opNumber0 = left.GetInt(); - opNumber1 = right.GetInt(); - } else if (left.IsNumber() && right.IsNumber()) { - opNumber0 = - left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); - opNumber1 = - right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); - } else { - // slow path - SAVE_ACC(); - JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); - RESTORE_ACC(); - right = GET_ACC(); // Maybe moved by GC - JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, right); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); - opNumber0 = taggedNumber0.GetInt(); - opNumber1 = taggedNumber1.GetInt(); - } - // NOLINT(hicpp-signed-bitwise) - auto ret = static_cast(opNumber0) | static_cast(opNumber1); - SET_ACC(JSTaggedValue(static_cast(ret))) - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_XOR2DYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - - LOG_INST() << "intrinsics::xor2dyn" - << " v" << v0; - int32_t opNumber0; - int32_t opNumber1; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - // both number, fast path - if (left.IsInt() && right.IsInt()) { - opNumber0 = left.GetInt(); - opNumber1 = right.GetInt(); - } else if (left.IsNumber() && right.IsNumber()) { - opNumber0 = - left.IsInt() ? left.GetInt() : base::NumberHelper::DoubleToInt(left.GetDouble(), base::INT32_BITS); - opNumber1 = - right.IsInt() ? right.GetInt() : base::NumberHelper::DoubleToInt(right.GetDouble(), base::INT32_BITS); - } else { - // slow path - SAVE_ACC(); - JSTaggedValue taggedNumber0 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, left); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber0); - RESTORE_ACC(); - right = GET_ACC(); // Maybe moved by GC - JSTaggedValue taggedNumber1 = SlowRuntimeStub::ToJSTaggedValueWithInt32(thread, right); - INTERPRETER_RETURN_IF_ABRUPT(taggedNumber1); - opNumber0 = taggedNumber0.GetInt(); - opNumber1 = taggedNumber1.GetInt(); - } - // NOLINT(hicpp-signed-bitwise) - auto ret = static_cast(opNumber0) ^ static_cast(opNumber1); - SET_ACC(JSTaggedValue(static_cast(ret))) - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_DELOBJPROP_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::delobjprop" - << " v0" << v0 << " v1" << v1; - - JSTaggedValue obj = GET_VREG_VALUE(v0); - JSTaggedValue prop = GET_VREG_VALUE(v1); - JSTaggedValue res = SlowRuntimeStub::DelObjProp(thread, obj, prop); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_DEFINEFUNCDYN_PREF_ID16_IMM16_V8) { - uint16_t methodId = READ_INST_16_1(); - uint16_t length = READ_INST_16_3(); - uint16_t v0 = READ_INST_8_5(); - LOG_INST() << "intrinsics::definefuncDyn length: " << length - << " v" << v0; - JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); - ASSERT(result != nullptr); - if (result->IsResolved()) { - auto res = SlowRuntimeStub::DefinefuncDyn(thread, result); - INTERPRETER_RETURN_IF_ABRUPT(res); - result = JSFunction::Cast(res.GetTaggedObject()); - result->SetConstantPool(thread, JSTaggedValue(constpool)); - } else { - result->SetResolved(thread); - } - - result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); - JSTaggedValue envHandle = GET_VREG_VALUE(v0); - result->SetLexicalEnv(thread, envHandle); - SET_ACC(JSTaggedValue(result)) - - DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_DEFINENCFUNCDYN_PREF_ID16_IMM16_V8) { - uint16_t methodId = READ_INST_16_1(); - uint16_t length = READ_INST_16_3(); - uint16_t v0 = READ_INST_8_5(); - JSTaggedValue homeObject = GET_ACC(); - LOG_INST() << "intrinsics::definencfuncDyn length: " << length - << " v" << v0; - JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); - ASSERT(result != nullptr); - if (result->IsResolved()) { - auto res = SlowRuntimeStub::DefineNCFuncDyn(thread, result); - INTERPRETER_RETURN_IF_ABRUPT(res); - result = JSFunction::Cast(res.GetTaggedObject()); - result->SetConstantPool(thread, JSTaggedValue(constpool)); - } else { - result->SetResolved(thread); - } - - result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); - JSTaggedValue env = GET_VREG_VALUE(v0); - result->SetLexicalEnv(thread, env); - result->SetHomeObject(thread, homeObject); - SET_ACC(JSTaggedValue(result)); - - DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_DEFINEMETHOD_PREF_ID16_IMM16_V8) { - uint16_t methodId = READ_INST_16_1(); - uint16_t length = READ_INST_16_3(); - uint16_t v0 = READ_INST_8_5(); - JSTaggedValue homeObject = GET_ACC(); - LOG_INST() << "intrinsics::definemethod length: " << length - << " v" << v0; - JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); - ASSERT(result != nullptr); - if (result->IsResolved()) { - auto res = SlowRuntimeStub::DefineMethod(thread, result, homeObject); - INTERPRETER_RETURN_IF_ABRUPT(res); - result = JSFunction::Cast(res.GetTaggedObject()); - result->SetConstantPool(thread, JSTaggedValue(constpool)); - } else { - result->SetHomeObject(thread, homeObject); - result->SetResolved(thread); - } - - result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); - JSTaggedValue taggedCurEnv = GET_VREG_VALUE(v0); - result->SetLexicalEnv(thread, taggedCurEnv); - SET_ACC(JSTaggedValue(result)); - - DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_NEWOBJDYNRANGE_PREF_IMM16_V8) { - uint16_t numArgs = READ_INST_16_1(); - uint16_t firstArgRegIdx = READ_INST_8_3(); - LOG_INST() << "intrinsics::newobjDynrange " << numArgs << " v" << firstArgRegIdx; - - constexpr uint16_t firstArgOffset = 2; - JSTaggedValue func = GET_VREG_VALUE(firstArgRegIdx); - JSTaggedValue newTarget = GET_VREG_VALUE(firstArgRegIdx + 1); - // Exclude func and newTarget - uint16_t firstArgIdx = firstArgRegIdx + firstArgOffset; - uint16_t length = numArgs - firstArgOffset; - - JSTaggedValue res = SlowRuntimeStub::NewObjDynRange(thread, func, newTarget, firstArgIdx, length); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_EXPDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::expdyn" - << " v" << v0; - JSTaggedValue base = GET_VREG_VALUE(v0); - JSTaggedValue exponent = GET_ACC(); - if (base.IsNumber() && exponent.IsNumber()) { - // fast path - double doubleBase = base.IsInt() ? base.GetInt() : base.GetDouble(); - double doubleExponent = exponent.IsInt() ? exponent.GetInt() : exponent.GetDouble(); - if (std::abs(doubleBase) == 1 && std::isinf(doubleExponent)) { - SET_ACC(JSTaggedValue(base::NAN_VALUE)); - } - if ((doubleBase == 0 && - ((bit_cast(doubleBase)) & base::DOUBLE_SIGN_MASK) == base::DOUBLE_SIGN_MASK) && - std::isfinite(doubleExponent) && base::NumberHelper::TruncateDouble(doubleExponent) == doubleExponent && - base::NumberHelper::TruncateDouble(doubleExponent / 2) + base::HALF == // 2 : half - (doubleExponent / 2)) { // 2 : half - if (doubleExponent > 0) { - SET_ACC(JSTaggedValue(-0.0)); - } - if (doubleExponent < 0) { - SET_ACC(JSTaggedValue(-base::POSITIVE_INFINITY)); - } - } - SET_ACC(JSTaggedValue(std::pow(doubleBase, doubleExponent))); - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::ExpDyn(thread, base, exponent); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_ISINDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::isindyn" - << " v" << v0; - JSTaggedValue prop = GET_VREG_VALUE(v0); - JSTaggedValue obj = GET_ACC(); - JSTaggedValue res = SlowRuntimeStub::IsInDyn(thread, prop, obj); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_INSTANCEOFDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::instanceofdyn" - << " v" << v0; - JSTaggedValue obj = GET_VREG_VALUE(v0); - JSTaggedValue target = GET_ACC(); - JSTaggedValue res = SlowRuntimeStub::InstanceofDyn(thread, obj, target); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_STRICTNOTEQDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::strictnoteq" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - bool res = FastRuntimeStub::FastStrictEqual(left, right); - SET_ACC(JSTaggedValue(!res)); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_STRICTEQDYN_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::stricteq" - << " v" << v0; - JSTaggedValue left = GET_VREG_VALUE(v0); - JSTaggedValue right = GET_ACC(); - bool res = FastRuntimeStub::FastStrictEqual(left, right); - SET_ACC(JSTaggedValue(res)); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_LDLEXVARDYN_PREF_IMM16_IMM16) { - uint16_t level = READ_INST_16_1(); - uint16_t slot = READ_INST_16_3(); - - LOG_INST() << "intrinsics::ldlexvardyn" - << " level:" << level << " slot:" << slot; - FrameState *state = GET_FRAME(sp); - JSTaggedValue currentLexenv = state->env; - JSTaggedValue env(currentLexenv); - for (int i = 0; i < level; i++) { - JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); - ASSERT(!taggedParentEnv.IsUndefined()); - env = taggedParentEnv; - } - SET_ACC(LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot)); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16_IMM16); - } - HANDLE_OPCODE(HANDLE_LDLEXVARDYN_PREF_IMM8_IMM8) { - uint16_t level = READ_INST_8_1(); - uint16_t slot = READ_INST_8_2(); - - LOG_INST() << "intrinsics::ldlexvardyn" - << " level:" << level << " slot:" << slot; - FrameState *state = GET_FRAME(sp); - JSTaggedValue currentLexenv = state->env; - JSTaggedValue env(currentLexenv); - for (int i = 0; i < level; i++) { - JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); - ASSERT(!taggedParentEnv.IsUndefined()); - env = taggedParentEnv; - } - SET_ACC(LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot)); - DISPATCH(BytecodeInstruction::Format::PREF_IMM8_IMM8); - } - HANDLE_OPCODE(HANDLE_LDLEXVARDYN_PREF_IMM4_IMM4) { - uint16_t level = READ_INST_4_2(); - uint16_t slot = READ_INST_4_3(); - - LOG_INST() << "intrinsics::ldlexvardyn" - << " level:" << level << " slot:" << slot; - FrameState *state = GET_FRAME(sp); - JSTaggedValue currentLexenv = state->env; - JSTaggedValue env(currentLexenv); - for (int i = 0; i < level; i++) { - JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); - ASSERT(!taggedParentEnv.IsUndefined()); - env = taggedParentEnv; - } - SET_ACC(LexicalEnv::Cast(env.GetTaggedObject())->GetProperties(slot)); - DISPATCH(BytecodeInstruction::Format::PREF_IMM4_IMM4); - } - HANDLE_OPCODE(HANDLE_STLEXVARDYN_PREF_IMM16_IMM16_V8) { - uint16_t level = READ_INST_16_1(); - uint16_t slot = READ_INST_16_3(); - uint16_t v0 = READ_INST_8_5(); - LOG_INST() << "intrinsics::stlexvardyn" - << " level:" << level << " slot:" << slot << " v" << v0; - - JSTaggedValue value = GET_VREG_VALUE(v0); - FrameState *state = GET_FRAME(sp); - JSTaggedValue env = state->env; - for (int i = 0; i < level; i++) { - JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); - ASSERT(!taggedParentEnv.IsUndefined()); - env = taggedParentEnv; - } - LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(thread, slot, value); - - DISPATCH(BytecodeInstruction::Format::PREF_IMM16_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_STLEXVARDYN_PREF_IMM8_IMM8_V8) { - uint16_t level = READ_INST_8_1(); - uint16_t slot = READ_INST_8_2(); - uint16_t v0 = READ_INST_8_3(); - LOG_INST() << "intrinsics::stlexvardyn" - << " level:" << level << " slot:" << slot << " v" << v0; - - JSTaggedValue value = GET_VREG_VALUE(v0); - FrameState *state = GET_FRAME(sp); - JSTaggedValue env = state->env; - for (int i = 0; i < level; i++) { - JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); - ASSERT(!taggedParentEnv.IsUndefined()); - env = taggedParentEnv; - } - LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(thread, slot, value); - - DISPATCH(BytecodeInstruction::Format::PREF_IMM8_IMM8_V8); - } - HANDLE_OPCODE(HANDLE_STLEXVARDYN_PREF_IMM4_IMM4_V8) { - uint16_t level = READ_INST_4_2(); - uint16_t slot = READ_INST_4_3(); - uint16_t v0 = READ_INST_8_2(); - LOG_INST() << "intrinsics::stlexvardyn" - << " level:" << level << " slot:" << slot << " v" << v0; - - JSTaggedValue value = GET_VREG_VALUE(v0); - FrameState *state = GET_FRAME(sp); - JSTaggedValue env = state->env; - for (int i = 0; i < level; i++) { - JSTaggedValue taggedParentEnv = LexicalEnv::Cast(env.GetTaggedObject())->GetParentEnv(); - ASSERT(!taggedParentEnv.IsUndefined()); - env = taggedParentEnv; - } - LexicalEnv::Cast(env.GetTaggedObject())->SetProperties(thread, slot, value); - - DISPATCH(BytecodeInstruction::Format::PREF_IMM4_IMM4_V8); - } - HANDLE_OPCODE(HANDLE_NEWLEXENVDYN_PREF_IMM16) { - uint16_t numVars = READ_INST_16_1(); - LOG_INST() << "intrinsics::newlexenvdyn" - << " imm " << numVars; - - JSTaggedValue res = FastRuntimeStub::NewLexicalEnvDyn(thread, factory, numVars); - if (res.IsHole()) { - res = SlowRuntimeStub::NewLexicalEnvDyn(thread, numVars); - INTERPRETER_RETURN_IF_ABRUPT(res); - } - SET_ACC(res); - GET_FRAME(sp)->env = res; - DISPATCH(BytecodeInstruction::Format::PREF_IMM16); - } - HANDLE_OPCODE(HANDLE_POPLEXENVDYN_PREF) { - FrameState *state = GET_FRAME(sp); - JSTaggedValue currentLexenv = state->env; - JSTaggedValue parentLexenv = LexicalEnv::Cast(currentLexenv.GetTaggedObject())->GetParentEnv(); - GET_FRAME(sp)->env = parentLexenv; - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_CREATEITERRESULTOBJ_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::createiterresultobj" - << " v" << v0 << " v" << v1; - JSTaggedValue value = GET_VREG_VALUE(v0); - JSTaggedValue flag = GET_VREG_VALUE(v1); - JSTaggedValue res = SlowRuntimeStub::CreateIterResultObj(thread, value, flag); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_SUSPENDGENERATOR_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::suspendgenerator" - << " v" << v0 << " v" << v1; - JSTaggedValue genObj = GET_VREG_VALUE(v0); - JSTaggedValue value = GET_VREG_VALUE(v1); - // suspend will record bytecode offset - SAVE_PC(); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::SuspendGenerator(thread, genObj, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - - FrameState *state = GET_FRAME(sp); - [[maybe_unused]] auto fistPC = state->method->GetInstructions(); - UPDATE_HOTNESS_COUNTER(-(pc - fistPC)); - LOG(DEBUG, INTERPRETER) << "Exit: SuspendGenerator " << std::hex << reinterpret_cast(sp) << " " - << std::hex << reinterpret_cast(state->pc); - sp = state->prev; - ASSERT(sp != nullptr); - FrameState *prevState = GET_FRAME(sp); - pc = prevState->pc; - - // break frame - if (pc == nullptr) { - state->acc = acc; - return; - } - thread->SetCurrentSPFrame(sp); - constpool = prevState->constpool; - - size_t jumpSize = GetJumpSizeAfterCall(pc); - DISPATCH_OFFSET(jumpSize); - } - HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONAWAITUNCAUGHT_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::asyncfunctionawaituncaught" - << " v" << v0 << " v" << v1; - JSTaggedValue asyncFuncObj = GET_VREG_VALUE(v0); - JSTaggedValue value = GET_VREG_VALUE(v1); - JSTaggedValue res = SlowRuntimeStub::AsyncFunctionAwaitUncaught(thread, asyncFuncObj, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONRESOLVE_PREF_V8_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - [[maybe_unused]] uint16_t v1 = READ_INST_8_2(); - uint16_t v2 = READ_INST_8_3(); - LOG_INST() << "intrinsics::asyncfunctionresolve" - << " v" << v0 << " v" << v1 << " v" << v2; - - JSTaggedValue asyncFuncObj = GET_VREG_VALUE(v0); - JSTaggedValue value = GET_VREG_VALUE(v2); - JSTaggedValue res = SlowRuntimeStub::AsyncFunctionResolveOrReject(thread, asyncFuncObj, value, true); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8); - } - HANDLE_OPCODE(HANDLE_ASYNCFUNCTIONREJECT_PREF_V8_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - [[maybe_unused]] uint16_t v1 = READ_INST_8_2(); - uint16_t v2 = READ_INST_8_3(); - LOG_INST() << "intrinsics::asyncfunctionreject" - << " v" << v0 << " v" << v1 << " v" << v2; - - JSTaggedValue asyncFuncObj = GET_VREG_VALUE(v0); - JSTaggedValue value = GET_VREG_VALUE(v2); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::AsyncFunctionResolveOrReject(thread, asyncFuncObj, value, false); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8); - } - HANDLE_OPCODE(HANDLE_NEWOBJSPREADDYN_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsic::newobjspearddyn" - << " v" << v0 << " v" << v1; - JSTaggedValue func = GET_VREG_VALUE(v0); - JSTaggedValue newTarget = GET_VREG_VALUE(v1); - JSTaggedValue array = GET_ACC(); - JSTaggedValue res = SlowRuntimeStub::NewObjSpreadDyn(thread, func, newTarget, array); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_THROWUNDEFINEDIFHOLE_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsic::throwundefinedifhole" - << " v" << v0 << " v" << v1; - JSTaggedValue hole = GET_VREG_VALUE(v0); - if (!hole.IsHole()) { - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - JSTaggedValue obj = GET_VREG_VALUE(v1); - ASSERT(obj.IsString()); - SlowRuntimeStub::ThrowUndefinedIfHole(thread, obj); - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - HANDLE_OPCODE(HANDLE_STOWNBYNAME_PREF_ID32_V8) { - uint32_t stringId = READ_INST_32_1(); - uint32_t v0 = READ_INST_8_5(); - LOG_INST() << "intrinsics::stownbyname " - << "v" << v0 << " stringId:" << stringId; - - JSTaggedValue receiver = GET_VREG_VALUE(v0); - if (receiver.IsJSObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - JSTaggedValue value = GET_ACC(); - // fast path - SAVE_ACC(); - JSTaggedValue res = FastRuntimeStub::SetPropertyByName(thread, receiver, propKey, value); - if (!res.IsHole()) { - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - RESTORE_ACC(); - } - - SAVE_ACC(); - receiver = GET_VREG_VALUE(v0); // Maybe moved by GC - auto propKey = constpool->GetObjectFromCache(stringId); // Maybe moved by GC - auto value = GET_ACC(); // Maybe moved by GC - JSTaggedValue res = SlowRuntimeStub::StOwnByName(thread, receiver, propKey, value); - RESTORE_ACC(); - INTERPRETER_RETURN_IF_ABRUPT(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - HANDLE_OPCODE(HANDLE_CREATEEMPTYARRAY_PREF) { - LOG_INST() << "intrinsics::createemptyarray"; - JSTaggedValue res = SlowRuntimeStub::CreateEmptyArray(thread, factory, globalEnv); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_CREATEEMPTYOBJECT_PREF) { - LOG_INST() << "intrinsics::createemptyobject"; - JSTaggedValue res = SlowRuntimeStub::CreateEmptyObject(thread, factory, globalEnv); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_CREATEOBJECTWITHBUFFER_PREF_IMM16) { - uint16_t imm = READ_INST_16_1(); - LOG_INST() << "intrinsics::createobjectwithbuffer" - << " imm:" << imm; - JSObject *result = JSObject::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); - - JSTaggedValue res = SlowRuntimeStub::CreateObjectWithBuffer(thread, factory, result); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16); - } - HANDLE_OPCODE(HANDLE_SETOBJECTWITHPROTO_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::setobjectwithproto" - << " v" << v0 << " v" << v1; - JSTaggedValue proto = GET_VREG_VALUE(v0); - JSTaggedValue obj = GET_VREG_VALUE(v1); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::SetObjectWithProto(thread, proto, obj); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_CREATEARRAYWITHBUFFER_PREF_IMM16) { - uint16_t imm = READ_INST_16_1(); - LOG_INST() << "intrinsics::createarraywithbuffer" - << " imm:" << imm; - JSArray *result = JSArray::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); - JSTaggedValue res = SlowRuntimeStub::CreateArrayWithBuffer(thread, factory, result); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16); - } - HANDLE_OPCODE(HANDLE_IMPORTMODULE_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - auto prop = constpool->GetObjectFromCache(stringId); - - LOG_INST() << "intrinsics::importmodule " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); - - JSTaggedValue moduleRef = SlowRuntimeStub::ImportModule(thread, prop); - SET_ACC(moduleRef); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - HANDLE_OPCODE(HANDLE_STMODULEVAR_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - auto prop = constpool->GetObjectFromCache(stringId); - - LOG_INST() << "intrinsics::stmodulevar " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); - JSTaggedValue value = GET_ACC(); - - SAVE_ACC(); - SlowRuntimeStub::StModuleVar(thread, prop, value); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - HANDLE_OPCODE(HANDLE_COPYMODULE_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - JSTaggedValue srcModule = GET_VREG_VALUE(v0); - - LOG_INST() << "intrinsics::copymodule "; - - SAVE_ACC(); - SlowRuntimeStub::CopyModule(thread, srcModule); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_LDMODVARBYNAME_PREF_ID32_V8) { - uint32_t stringId = READ_INST_32_1(); - uint32_t v0 = READ_INST_8_5(); - - JSTaggedValue itemName = constpool->GetObjectFromCache(stringId); - JSTaggedValue moduleObj = GET_VREG_VALUE(v0); - LOG_INST() << "intrinsics::ldmodvarbyname " - << "string_id:" << stringId << ", " - << "itemName: " << ConvertToString(EcmaString::Cast(itemName.GetTaggedObject())); - - JSTaggedValue moduleVar = SlowRuntimeStub::LdModvarByName(thread, moduleObj, itemName); - SET_ACC(moduleVar); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - HANDLE_OPCODE(HANDLE_CREATEREGEXPWITHLITERAL_PREF_ID32_IMM8) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue pattern = constpool->GetObjectFromCache(stringId); - uint8_t flags = READ_INST_8_5(); - LOG_INST() << "intrinsics::createregexpwithliteral " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(pattern.GetTaggedObject())) - << ", flags:" << flags; - JSTaggedValue res = SlowRuntimeStub::CreateRegExpWithLiteral(thread, pattern, flags); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_IMM8); - } - HANDLE_OPCODE(HANDLE_GETTEMPLATEOBJECT_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsic::gettemplateobject" - << " v" << v0; - - JSTaggedValue literal = GET_VREG_VALUE(v0); - JSTaggedValue res = SlowRuntimeStub::GetTemplateObject(thread, literal); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_GETNEXTPROPNAME_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsic::getnextpropname" - << " v" << v0; - JSTaggedValue iter = GET_VREG_VALUE(v0); - JSTaggedValue res = SlowRuntimeStub::GetNextPropName(thread, iter); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_COPYDATAPROPERTIES_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsic::copydataproperties" - << " v" << v0 << " v" << v1; - JSTaggedValue dst = GET_VREG_VALUE(v0); - JSTaggedValue src = GET_VREG_VALUE(v1); - JSTaggedValue res = SlowRuntimeStub::CopyDataProperties(thread, dst, src); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_STOWNBYINDEX_PREF_V8_IMM32) { - uint32_t v0 = READ_INST_8_1(); - uint32_t index = READ_INST_32_2(); - LOG_INST() << "intrinsics::stownbyindex" - << " v" << v0 << " imm" << index; - JSTaggedValue receiver = GET_VREG_VALUE(v0); - // fast path - if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { - SAVE_ACC(); - JSTaggedValue value = GET_ACC(); - // fast path - JSTaggedValue res = - FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value); - if (!res.IsHole()) { - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); - } - RESTORE_ACC(); - } - SAVE_ACC(); - receiver = GET_VREG_VALUE(v0); // Maybe moved by GC - auto value = GET_ACC(); // Maybe moved by GC - JSTaggedValue res = SlowRuntimeStub::StOwnByIndex(thread, receiver, index, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); - } - HANDLE_OPCODE(HANDLE_STOWNBYVALUE_PREF_V8_V8) { - uint32_t v0 = READ_INST_8_1(); - uint32_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::stownbyvalue" - << " v" << v0 << " v" << v1; - - JSTaggedValue receiver = GET_VREG_VALUE(v0); - if (receiver.IsHeapObject() && !receiver.IsClassConstructor() && !receiver.IsClassPrototype()) { - SAVE_ACC(); - JSTaggedValue propKey = GET_VREG_VALUE(v1); - JSTaggedValue value = GET_ACC(); - // fast path - JSTaggedValue res = FastRuntimeStub::SetPropertyByValue(thread, receiver, propKey, value); - - // SetPropertyByValue maybe gc need update the value - RESTORE_ACC(); - propKey = GET_VREG_VALUE(v1); - value = GET_ACC(); - if (!res.IsHole()) { - INTERPRETER_RETURN_IF_ABRUPT(res); - if (value.IsJSFunction()) { - JSFunction::SetFunctionNameNoPrefix(thread, JSFunction::Cast(value.GetTaggedObject()), propKey); - } - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - } - - // slow path - SAVE_ACC(); - receiver = GET_VREG_VALUE(v0); // Maybe moved by GC - auto propKey = GET_VREG_VALUE(v1); // Maybe moved by GC - auto value = GET_ACC(); // Maybe moved by GC - JSTaggedValue res = SlowRuntimeStub::StOwnByValue(thread, receiver, propKey, value); - RESTORE_ACC(); - INTERPRETER_RETURN_IF_ABRUPT(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_CREATEOBJECTWITHEXCLUDEDKEYS_PREF_IMM16_V8_V8) { - uint16_t numKeys = READ_INST_16_1(); - uint16_t v0 = READ_INST_8_3(); - uint16_t firstArgRegIdx = READ_INST_8_4(); - LOG_INST() << "intrinsics::createobjectwithexcludedkeys " << numKeys << " v" << firstArgRegIdx; - - JSTaggedValue obj = GET_VREG_VALUE(v0); - - JSTaggedValue res = SlowRuntimeStub::CreateObjectWithExcludedKeys(thread, numKeys, obj, firstArgRegIdx); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16_V8_V8); - } - HANDLE_OPCODE(HANDLE_DEFINEGENERATORFUNC_PREF_ID16_IMM16_V8) { - uint16_t methodId = READ_INST_16_1(); - uint16_t length = READ_INST_16_3(); - uint16_t v0 = READ_INST_8_5(); - LOG_INST() << "define gengerator function length: " << length - << " v" << v0; - JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); - ASSERT(result != nullptr); - if (result->IsResolved()) { - auto res = SlowRuntimeStub::DefineGeneratorFunc(thread, result); - INTERPRETER_RETURN_IF_ABRUPT(res); - result = JSFunction::Cast(res.GetTaggedObject()); - result->SetConstantPool(thread, JSTaggedValue(constpool)); - } else { - result->SetResolved(thread); - } - - result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); - JSTaggedValue env = GET_VREG_VALUE(v0); - result->SetLexicalEnv(thread, env); - SET_ACC(JSTaggedValue(result)) - DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_DEFINEASYNCFUNC_PREF_ID16_IMM16_V8) { - uint16_t methodId = READ_INST_16_1(); - uint16_t length = READ_INST_16_3(); - uint16_t v0 = READ_INST_8_5(); - LOG_INST() << "define async function length: " << length - << " v" << v0; - JSFunction *result = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); - ASSERT(result != nullptr); - if (result->IsResolved()) { - auto res = SlowRuntimeStub::DefineAsyncFunc(thread, result); - INTERPRETER_RETURN_IF_ABRUPT(res); - result = JSFunction::Cast(res.GetTaggedObject()); - result->SetConstantPool(thread, JSTaggedValue(constpool)); - } else { - result->SetResolved(thread); - } - - result->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); - JSTaggedValue env = GET_VREG_VALUE(v0); - result->SetLexicalEnv(thread, env); - SET_ACC(JSTaggedValue(result)) - DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_LDHOLE_PREF) { - LOG_INST() << "intrinsic::ldhole"; - SET_ACC(JSTaggedValue::Hole()); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_COPYRESTARGS_PREF_IMM16) { - uint16_t restIdx = READ_INST_16_1(); - LOG_INST() << "intrinsics::copyrestargs" - << " index: " << restIdx; - - FrameState *state = GET_FRAME(sp); - uint32_t numVregs = state->method->GetNumVregs(); - // Exclude func, newTarget and "this" - int32_t actualNumArgs = state->numActualArgs - NUM_MANDATORY_JSFUNC_ARGS; - int32_t tmp = actualNumArgs - restIdx; - uint32_t restNumArgs = (tmp > 0) ? tmp : 0; - uint32_t startIdx = numVregs + NUM_MANDATORY_JSFUNC_ARGS + restIdx; - - JSTaggedValue res = SlowRuntimeStub::CopyRestArgs(thread, sp, restNumArgs, startIdx); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16); - } - HANDLE_OPCODE(HANDLE_DEFINEGETTERSETTERBYVALUE_PREF_V8_V8_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - uint16_t v2 = READ_INST_8_3(); - uint16_t v3 = READ_INST_8_4(); - LOG_INST() << "intrinsics::definegettersetterbyvalue" - << " v" << v0 << " v" << v1 << " v" << v2 << " v" << v3; - - JSTaggedValue obj = GET_VREG_VALUE(v0); - JSTaggedValue prop = GET_VREG_VALUE(v1); - JSTaggedValue getter = GET_VREG_VALUE(v2); - JSTaggedValue setter = GET_VREG_VALUE(v3); - JSTaggedValue flag = GET_ACC(); - JSTaggedValue res = - SlowRuntimeStub::DefineGetterSetterByValue(thread, obj, prop, getter, setter, flag.ToBoolean()); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8_V8_V8); - } - HANDLE_OPCODE(HANDLE_LDOBJBYINDEX_PREF_V8_IMM32) { - uint16_t v0 = READ_INST_8_1(); - uint32_t idx = READ_INST_32_2(); - LOG_INST() << "intrinsics::ldobjbyindex" - << " v" << v0 << " imm" << idx; - - JSTaggedValue receiver = GET_VREG_VALUE(v0); - // fast path - if (LIKELY(receiver.IsHeapObject())) { - JSTaggedValue res = FastRuntimeStub::GetPropertyByIndex(thread, receiver, idx); - if (!res.IsHole()) { - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); - } - } - // not meet fast condition or fast path return hole, walk slow path - // slow stub not need receiver - JSTaggedValue res = SlowRuntimeStub::LdObjByIndex(thread, receiver, idx, false, JSTaggedValue::Undefined()); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); - } - HANDLE_OPCODE(HANDLE_STOBJBYINDEX_PREF_V8_IMM32) { - uint16_t v0 = READ_INST_8_1(); - uint32_t index = READ_INST_32_2(); - LOG_INST() << "intrinsics::stobjbyindex" - << " v" << v0 << " imm" << index; - - JSTaggedValue receiver = GET_VREG_VALUE(v0); - if (receiver.IsHeapObject()) { - SAVE_ACC(); - JSTaggedValue value = GET_ACC(); - // fast path - JSTaggedValue res = FastRuntimeStub::SetPropertyByIndex(thread, receiver, index, value); - if (!res.IsHole()) { - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); - } - RESTORE_ACC(); - } - // slow path - SAVE_ACC(); - receiver = GET_VREG_VALUE(v0); // Maybe moved by GC - JSTaggedValue value = GET_ACC(); // Maybe moved by GC - JSTaggedValue res = SlowRuntimeStub::StObjByIndex(thread, receiver, index, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_IMM32); - } - HANDLE_OPCODE(HANDLE_LDOBJBYVALUE_PREF_V8_V8) { - uint32_t v0 = READ_INST_8_1(); - uint32_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::Ldobjbyvalue" - << " v" << v0 << " v" << v1; - - JSTaggedValue receiver = GET_VREG_VALUE(v0); - JSTaggedValue propKey = GET_VREG_VALUE(v1); - -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); - JSTaggedValue firstValue = profileTypeArray->Get(slotId); - JSTaggedValue res = JSTaggedValue::Hole(); - - if (LIKELY(firstValue.IsHeapObject())) { - JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); - res = ICRuntimeStub::TryLoadICByValue(thread, receiver, propKey, firstValue, secondValue); - } else if (firstValue.IsUndefined()) { - res = ICRuntimeStub::LoadICByValue(thread, - profileTypeArray, - receiver, propKey, slotId); - } - - if (LIKELY(!res.IsHole())) { - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - } -#endif - // fast path - if (LIKELY(receiver.IsHeapObject())) { - JSTaggedValue res = FastRuntimeStub::GetPropertyByValue(thread, receiver, propKey); - if (!res.IsHole()) { - ASSERT(!res.IsAccessor()); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - } - // slow path - JSTaggedValue res = SlowRuntimeStub::LdObjByValue(thread, receiver, propKey, false, JSTaggedValue::Undefined()); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_STOBJBYVALUE_PREF_V8_V8) { - uint32_t v0 = READ_INST_8_1(); - uint32_t v1 = READ_INST_8_2(); - - LOG_INST() << "intrinsics::stobjbyvalue" - << " v" << v0 << " v" << v1; - - JSTaggedValue receiver = GET_VREG_VALUE(v0); -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); - JSTaggedValue firstValue = profileTypeArray->Get(slotId); - JSTaggedValue propKey = GET_VREG_VALUE(v1); - JSTaggedValue value = GET_ACC(); - JSTaggedValue res = JSTaggedValue::Hole(); - SAVE_ACC(); - - if (LIKELY(firstValue.IsHeapObject())) { - JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); - res = ICRuntimeStub::TryStoreICByValue(thread, receiver, propKey, firstValue, secondValue, value); - } else if (firstValue.IsUndefined()) { - res = ICRuntimeStub::StoreICByValue(thread, - profileTypeArray, - receiver, propKey, value, slotId); - } - - if (LIKELY(!res.IsHole())) { - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - } -#endif - if (receiver.IsHeapObject()) { - SAVE_ACC(); - JSTaggedValue propKey = GET_VREG_VALUE(v1); - JSTaggedValue value = GET_ACC(); - // fast path - JSTaggedValue res = FastRuntimeStub::SetPropertyByValue(thread, receiver, propKey, value); - if (!res.IsHole()) { - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - RESTORE_ACC(); - } - { - // slow path - SAVE_ACC(); - receiver = GET_VREG_VALUE(v0); // Maybe moved by GC - JSTaggedValue propKey = GET_VREG_VALUE(v1); // Maybe moved by GC - JSTaggedValue value = GET_ACC(); // Maybe moved by GC - JSTaggedValue res = SlowRuntimeStub::StObjByValue(thread, receiver, propKey, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - } - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_LDSUPERBYVALUE_PREF_V8_V8) { - uint32_t v0 = READ_INST_8_1(); - uint32_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsics::Ldsuperbyvalue" - << " v" << v0 << " v" << v1; - - JSTaggedValue receiver = GET_VREG_VALUE(v0); - JSTaggedValue propKey = GET_VREG_VALUE(v1); - - // slow path - JSTaggedValue thisFunc = GetThisFunction(sp); - JSTaggedValue res = SlowRuntimeStub::LdSuperByValue(thread, receiver, propKey, thisFunc); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_STSUPERBYVALUE_PREF_V8_V8) { - uint32_t v0 = READ_INST_8_1(); - uint32_t v1 = READ_INST_8_2(); - - LOG_INST() << "intrinsics::stsuperbyvalue" - << " v" << v0 << " v" << v1; - JSTaggedValue receiver = GET_VREG_VALUE(v0); - JSTaggedValue propKey = GET_VREG_VALUE(v1); - JSTaggedValue value = GET_ACC(); - - // slow path - SAVE_ACC(); - JSTaggedValue thisFunc = GetThisFunction(sp); - JSTaggedValue res = SlowRuntimeStub::StSuperByValue(thread, receiver, propKey, value, thisFunc); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_TRYLDGLOBALBYNAME_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - auto prop = constpool->GetObjectFromCache(stringId); - - LOG_INST() << "intrinsics::tryldglobalbyname " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())); - -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - JSTaggedValue res = ICRuntimeStub::LoadGlobalICByName(thread, - ProfileTypeInfo::Cast( - profileTypeInfo.GetTaggedObject()), - globalObj, prop, slotId); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } -#endif - - bool found = false; - // order: 1. global record 2. global object - JSTaggedValue result = SlowRuntimeStub::LdGlobalRecord(thread, prop, &found); - if (found) { - SET_ACC(result); - } else { - JSTaggedValue globalResult = FastRuntimeStub::GetGlobalOwnProperty(globalObj, prop, &found); - if (found) { - SET_ACC(globalResult); - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::TryLdGlobalByName(thread, globalObj, prop); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - } - - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - HANDLE_OPCODE(HANDLE_TRYSTGLOBALBYNAME_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - LOG_INST() << "intrinsics::trystglobalbyname" - << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); - -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - JSTaggedValue value = GET_ACC(); - SAVE_ACC(); - JSTaggedValue res = ICRuntimeStub::StoreGlobalICByName(thread, - ProfileTypeInfo::Cast( - profileTypeInfo.GetTaggedObject()), - globalObj, propKey, value, slotId); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } -#endif - - bool found = false; - SlowRuntimeStub::LdGlobalRecord(thread, propKey, &found); - // 1. find from global record - if (found) { - JSTaggedValue value = GET_ACC(); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::TryUpdateGlobalRecord(thread, propKey, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - } else { - // 2. find from global object - FastRuntimeStub::GetGlobalOwnProperty(globalObj, propKey, &found); - if (!found) { - auto result = SlowRuntimeStub::ThrowReferenceError(thread, propKey, " is not defined"); - INTERPRETER_RETURN_IF_ABRUPT(result); - } - JSTaggedValue value = GET_ACC(); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::StGlobalVar(thread, propKey, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - } - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - - HANDLE_OPCODE(HANDLE_STCONSTTOGLOBALRECORD_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - LOG_INST() << "intrinsics::stconsttoglobalrecord" - << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); - - JSTaggedValue value = GET_ACC(); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, true); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - - HANDLE_OPCODE(HANDLE_STLETTOGLOBALRECORD_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - LOG_INST() << "intrinsics::stlettoglobalrecord" - << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); - - JSTaggedValue value = GET_ACC(); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - - HANDLE_OPCODE(HANDLE_STCLASSTOGLOBALRECORD_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - LOG_INST() << "intrinsics::stclasstoglobalrecord" - << " stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())); - - JSTaggedValue value = GET_ACC(); - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::StGlobalRecord(thread, propKey, value, false); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - - HANDLE_OPCODE(HANDLE_LDGLOBALVAR_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - JSTaggedValue res = ICRuntimeStub::LoadGlobalICByName(thread, - ProfileTypeInfo::Cast( - profileTypeInfo.GetTaggedObject()), - globalObj, propKey, slotId); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } -#endif - bool found = false; - JSTaggedValue result = FastRuntimeStub::GetGlobalOwnProperty(globalObj, propKey, &found); - if (found) { - SET_ACC(result); - } else { - // slow path - JSTaggedValue res = SlowRuntimeStub::LdGlobalVar(thread, globalObj, propKey); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - } - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - HANDLE_OPCODE(HANDLE_LDOBJBYNAME_PREF_ID32_V8) { - uint32_t v0 = READ_INST_8_5(); - JSTaggedValue receiver = GET_VREG_VALUE(v0); - -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); - JSTaggedValue firstValue = profileTypeArray->Get(slotId); - JSTaggedValue res = JSTaggedValue::Hole(); - - if (LIKELY(firstValue.IsHeapObject())) { - JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); - res = ICRuntimeStub::TryLoadICByName(thread, receiver, firstValue, secondValue); - } else if (firstValue.IsUndefined()) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - res = ICRuntimeStub::LoadICByName(thread, - profileTypeArray, - receiver, propKey, slotId); - } - - if (LIKELY(!res.IsHole())) { - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - } -#endif - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - LOG_INST() << "intrinsics::ldobjbyname " - << "v" << v0 << " stringId:" << stringId << ", " - << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())) << ", obj:" << receiver.GetRawData(); - - if (LIKELY(receiver.IsHeapObject())) { - // fast path - JSTaggedValue res = FastRuntimeStub::GetPropertyByName(thread, receiver, propKey); - if (!res.IsHole()) { - ASSERT(!res.IsAccessor()); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - } - // not meet fast condition or fast path return hole, walk slow path - // slow stub not need receiver - JSTaggedValue res = SlowRuntimeStub::LdObjByName(thread, receiver, propKey, false, JSTaggedValue::Undefined()); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - HANDLE_OPCODE(HANDLE_STOBJBYNAME_PREF_ID32_V8) { - uint32_t v0 = READ_INST_8_5(); - JSTaggedValue receiver = GET_VREG_VALUE(v0); - JSTaggedValue value = GET_ACC(); -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - auto profileTypeArray = ProfileTypeInfo::Cast(profileTypeInfo.GetTaggedObject()); - JSTaggedValue firstValue = profileTypeArray->Get(slotId); - JSTaggedValue res = JSTaggedValue::Hole(); - SAVE_ACC(); - - if (LIKELY(firstValue.IsHeapObject())) { - JSTaggedValue secondValue = profileTypeArray->Get(slotId + 1); - res = ICRuntimeStub::TryStoreICByName(thread, receiver, firstValue, secondValue, value); - } else if (firstValue.IsUndefined()) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - res = ICRuntimeStub::StoreICByName(thread, - profileTypeArray, - receiver, propKey, value, slotId); - } - - if (LIKELY(!res.IsHole())) { - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - } -#endif - uint32_t stringId = READ_INST_32_1(); - LOG_INST() << "intrinsics::stobjbyname " - << "v" << v0 << " stringId:" << stringId; - if (receiver.IsHeapObject()) { - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - value = GET_ACC(); - // fast path - SAVE_ACC(); - JSTaggedValue res = FastRuntimeStub::SetPropertyByName(thread, receiver, propKey, value); - if (!res.IsHole()) { - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - RESTORE_ACC(); - } - // slow path - SAVE_ACC(); - receiver = GET_VREG_VALUE(v0); // Maybe moved by GC - auto propKey = constpool->GetObjectFromCache(stringId); // Maybe moved by GC - value = GET_ACC(); // Maybe moved by GC - JSTaggedValue res = SlowRuntimeStub::StObjByName(thread, receiver, propKey, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - HANDLE_OPCODE(HANDLE_LDSUPERBYNAME_PREF_ID32_V8) { - uint32_t stringId = READ_INST_32_1(); - uint32_t v0 = READ_INST_8_5(); - JSTaggedValue obj = GET_VREG_VALUE(v0); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - - LOG_INST() << "intrinsics::ldsuperbyname" - << "v" << v0 << " stringId:" << stringId << ", " - << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())) << ", obj:" << obj.GetRawData(); - - JSTaggedValue thisFunc = GetThisFunction(sp); - JSTaggedValue res = SlowRuntimeStub::LdSuperByValue(thread, obj, propKey, thisFunc); - - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - HANDLE_OPCODE(HANDLE_STSUPERBYNAME_PREF_ID32_V8) { - uint32_t stringId = READ_INST_32_1(); - uint32_t v0 = READ_INST_8_5(); - - JSTaggedValue obj = GET_VREG_VALUE(v0); - JSTaggedValue propKey = constpool->GetObjectFromCache(stringId); - JSTaggedValue value = GET_ACC(); - - LOG_INST() << "intrinsics::stsuperbyname" - << "v" << v0 << " stringId:" << stringId << ", " - << ConvertToString(EcmaString::Cast(propKey.GetTaggedObject())) << ", obj:" << obj.GetRawData() - << ", value:" << value.GetRawData(); - - // slow path - SAVE_ACC(); - JSTaggedValue thisFunc = GetThisFunction(sp); - JSTaggedValue res = SlowRuntimeStub::StSuperByValue(thread, obj, propKey, value, thisFunc); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32_V8); - } - HANDLE_OPCODE(HANDLE_STGLOBALVAR_PREF_ID32) { - uint32_t stringId = READ_INST_32_1(); - JSTaggedValue prop = constpool->GetObjectFromCache(stringId); - JSTaggedValue value = GET_ACC(); - - LOG_INST() << "intrinsics::stglobalvar " - << "stringId:" << stringId << ", " << ConvertToString(EcmaString::Cast(prop.GetTaggedObject())) - << ", value:" << value.GetRawData(); -#if ECMASCRIPT_ENABLE_IC - auto profileTypeInfo = GetRuntimeProfileTypeInfo(sp); - if (!profileTypeInfo.IsUndefined()) { - uint16_t slotId = READ_INST_8_0(); - SAVE_ACC(); - JSTaggedValue res = ICRuntimeStub::StoreGlobalICByName(thread, - ProfileTypeInfo::Cast( - profileTypeInfo.GetTaggedObject()), - globalObj, prop, value, slotId); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } -#endif - SAVE_ACC(); - JSTaggedValue res = SlowRuntimeStub::StGlobalVar(thread, prop, value); - INTERPRETER_RETURN_IF_ABRUPT(res); - RESTORE_ACC(); - DISPATCH(BytecodeInstruction::Format::PREF_ID32); - } - HANDLE_OPCODE(HANDLE_CREATEGENERATOROBJ_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsics::creategeneratorobj" - << " v" << v0; - JSTaggedValue genFunc = GET_VREG_VALUE(v0); - JSTaggedValue res = SlowRuntimeStub::CreateGeneratorObj(thread, genFunc); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_STARRAYSPREAD_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "ecmascript::intrinsics::starrayspread" - << " v" << v0 << " v" << v1 << "acc"; - JSTaggedValue dst = GET_VREG_VALUE(v0); - JSTaggedValue index = GET_VREG_VALUE(v1); - JSTaggedValue src = GET_ACC(); - JSTaggedValue res = SlowRuntimeStub::StArraySpread(thread, dst, index, src); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_GETITERATORNEXT_PREF_V8_V8) { - uint16_t v0 = READ_INST_8_1(); - uint16_t v1 = READ_INST_8_2(); - LOG_INST() << "intrinsic::getiteratornext" - << " v" << v0 << " v" << v1; - JSTaggedValue obj = GET_VREG_VALUE(v0); - JSTaggedValue method = GET_VREG_VALUE(v1); - JSTaggedValue res = SlowRuntimeStub::GetIteratorNext(thread, obj, method); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8_V8); - } - HANDLE_OPCODE(HANDLE_DEFINECLASSWITHBUFFER_PREF_ID16_IMM16_IMM16_V8_V8) { - uint16_t methodId = READ_INST_16_1(); - uint16_t imm = READ_INST_16_3(); - uint16_t length = READ_INST_16_5(); - uint16_t v0 = READ_INST_8_7(); - uint16_t v1 = READ_INST_8_8(); - LOG_INST() << "intrinsics::defineclasswithbuffer" - << " method id:" << methodId << " literal id:" << imm << " lexenv: v" << v0 << " parent: v" << v1; - JSFunction *cls = JSFunction::Cast(constpool->GetObjectFromCache(methodId).GetTaggedObject()); - ASSERT(cls != nullptr); - if (cls->IsResolved()) { - auto res = SlowRuntimeStub::NewClassFunc(thread, cls); - INTERPRETER_RETURN_IF_ABRUPT(res); - cls = JSFunction::Cast(res.GetTaggedObject()); - cls->SetConstantPool(thread, JSTaggedValue(constpool)); - } else { - cls->SetResolved(thread); - } - - cls->SetPropertyInlinedProps(thread, JSFunction::LENGTH_INLINE_PROPERTY_INDEX, JSTaggedValue(length)); - JSTaggedValue lexenv = GET_VREG_VALUE(v0); - cls->SetLexicalEnv(thread, lexenv); - - TaggedArray *literalBuffer = TaggedArray::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); - JSTaggedValue proto = GET_VREG_VALUE(v1); - JSTaggedValue res = SlowRuntimeStub::DefineClass(thread, cls, literalBuffer, proto, lexenv, constpool); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_ID16_IMM16_IMM16_V8_V8); - } - HANDLE_OPCODE(HANDLE_SUPERCALL_PREF_IMM16_V8) { - uint16_t range = READ_INST_16_1(); - uint16_t v0 = READ_INST_8_3(); - LOG_INST() << "intrinsics::supercall" - << " range: " << range << " v" << v0; - - FrameState *state = GET_FRAME(sp); - auto numVregs = state->method->GetNumVregs(); - JSTaggedValue thisFunc = GET_ACC(); - JSTaggedValue newTarget = GET_VREG_VALUE(numVregs + 1); - - JSTaggedValue res = SlowRuntimeStub::SuperCall(thread, thisFunc, newTarget, v0, range); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16_V8); - } - HANDLE_OPCODE(HANDLE_SUPERCALLSPREAD_PREF_V8) { - uint16_t v0 = READ_INST_8_1(); - LOG_INST() << "intrinsic::supercallspread" - << " array: v" << v0; - - FrameState *state = GET_FRAME(sp); - auto numVregs = state->method->GetNumVregs(); - JSTaggedValue thisFunc = GET_ACC(); - JSTaggedValue newTarget = GET_VREG_VALUE(numVregs + 1); - JSTaggedValue array = GET_VREG_VALUE(v0); - - JSTaggedValue res = SlowRuntimeStub::SuperCallSpread(thread, thisFunc, newTarget, array); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_V8); - } - HANDLE_OPCODE(HANDLE_CREATEOBJECTHAVINGMETHOD_PREF_IMM16) { - uint16_t imm = READ_INST_16_1(); - LOG_INST() << "intrinsics::createobjecthavingmethod" - << " imm:" << imm; - JSObject *result = JSObject::Cast(constpool->GetObjectFromCache(imm).GetTaggedObject()); - JSTaggedValue env = GET_ACC(); - - JSTaggedValue res = SlowRuntimeStub::CreateObjectHavingMethod(thread, factory, result, env, constpool); - INTERPRETER_RETURN_IF_ABRUPT(res); - SET_ACC(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16); - } - HANDLE_OPCODE(HANDLE_THROWIFSUPERNOTCORRECTCALL_PREF_IMM16) { - uint16_t imm = READ_INST_16_1(); - JSTaggedValue thisValue = GET_ACC(); - LOG_INST() << "intrinsic::throwifsupernotcorrectcall" - << " imm:" << imm; - JSTaggedValue res = SlowRuntimeStub::ThrowIfSuperNotCorrectCall(thread, imm, thisValue); - INTERPRETER_RETURN_IF_ABRUPT(res); - DISPATCH(BytecodeInstruction::Format::PREF_IMM16); - } - HANDLE_OPCODE(HANDLE_LDHOMEOBJECT_PREF) { - LOG_INST() << "intrinsics::ldhomeobject"; - - JSTaggedValue thisFunc = GetThisFunction(sp); - JSTaggedValue homeObject = JSFunction::Cast(thisFunc.GetTaggedObject())->GetHomeObject(); - - SET_ACC(homeObject); - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_THROWDELETESUPERPROPERTY_PREF) { - LOG_INST() << "throwdeletesuperproperty"; - - SlowRuntimeStub::ThrowDeleteSuperProperty(thread); - INTERPRETER_GOTO_EXCEPTION_HANDLER(); - } - HANDLE_OPCODE(HANDLE_DEBUGGER_PREF) { - LOG_INST() << "intrinsics::debugger"; - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_ISTRUE_PREF) { - LOG_INST() << "intrinsics::istrue"; - if (GET_ACC().ToBoolean()) { - SET_ACC(JSTaggedValue::True()); - } else { - SET_ACC(JSTaggedValue::False()); - } - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(HANDLE_ISFALSE_PREF) { - LOG_INST() << "intrinsics::isfalse"; - if (!GET_ACC().ToBoolean()) { - SET_ACC(JSTaggedValue::True()); - } else { - SET_ACC(JSTaggedValue::False()); - } - DISPATCH(BytecodeInstruction::Format::PREF_NONE); - } - HANDLE_OPCODE(EXCEPTION_HANDLER) { - auto exception = thread->GetException(); - - EcmaFrameHandler frameHandler(sp); - uint32_t pcOffset = panda_file::INVALID_OFFSET; - for (; frameHandler.HasFrame(); frameHandler.PrevFrame()) { - if (frameHandler.IsBreakFrame()) { - return; - } - auto method = frameHandler.GetMethod(); - pcOffset = FindCatchBlock(method, frameHandler.GetBytecodeOffset()); - if (pcOffset != panda_file::INVALID_OFFSET) { - sp = frameHandler.GetSp(); - constpool = frameHandler.GetConstpool(); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - pc = JSMethod::Cast(method)->GetBytecodeArray() + pcOffset; - break; - } - } - if (pcOffset == panda_file::INVALID_OFFSET) { - return; - } - - // set exception to acc - if (exception.IsObjectWrapper()) { - SET_ACC(ObjectWrapper::Cast(exception.GetTaggedObject())->GetValue()); - } else { - SET_ACC(exception); - } - thread->ClearException(); - thread->SetCurrentSPFrame(sp); - DISPATCH_OFFSET(0); - } - HANDLE_OPCODE(HANDLE_OVERFLOW) { - LOG(FATAL, INTERPRETER) << "opcode overflow"; - } -#include "templates/debugger_instruction_handler.inl" -} - -void EcmaInterpreter::InitStackFrame(JSThread *thread) -{ - uint64_t *prevSp = const_cast(thread->GetCurrentSPFrame()); - FrameState *state = GET_FRAME(prevSp); - state->pc = nullptr; - state->sp = nullptr; - state->method = nullptr; - state->acc = JSTaggedValue::Hole(); - state->constpool = nullptr; - state->profileTypeInfo = JSTaggedValue::Undefined(); - state->prev = nullptr; - state->numActualArgs = 0; -} - -uint32_t EcmaInterpreter::FindCatchBlock(JSMethod *caller, uint32_t pc) -{ - auto *pandaFile = caller->GetPandaFile(); - panda_file::MethodDataAccessor mda(*pandaFile, caller->GetFileId()); - panda_file::CodeDataAccessor cda(*pandaFile, mda.GetCodeId().value()); - - uint32_t pcOffset = panda_file::INVALID_OFFSET; - cda.EnumerateTryBlocks([&pcOffset, pc](panda_file::CodeDataAccessor::TryBlock &try_block) { - if ((try_block.GetStartPc() <= pc) && ((try_block.GetStartPc() + try_block.GetLength()) > pc)) { - try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) { - pcOffset = catch_block.GetHandlerPc(); - return false; - }); - } - return pcOffset == panda_file::INVALID_OFFSET; - }); - return pcOffset; -} - -void EcmaInterpreter::InterpreterFrameCopyArgs(JSTaggedType *newSp, uint32_t numVregs, uint32_t numActualArgs, - uint32_t numDeclaredArgs) -{ - for (size_t i = 0; i < numVregs; i++) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[i] = JSTaggedValue::VALUE_UNDEFINED; - } - for (size_t i = numActualArgs; i < numDeclaredArgs; i++) { - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - newSp[numVregs + i] = JSTaggedValue::VALUE_UNDEFINED; - } -} - -JSTaggedValue EcmaInterpreter::GetThisFunction(JSTaggedType *sp) -{ - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - FrameState *state = reinterpret_cast(sp) - 1; - auto numVregs = state->method->GetNumVregs(); - return GET_VREG_VALUE(numVregs); -} - -size_t EcmaInterpreter::GetJumpSizeAfterCall(const uint8_t *prevPc) -{ - uint8_t op = *prevPc; - size_t jumpSize; - switch (op) { - case (EcmaOpcode::CALLARG0DYN_PREF_V8): - jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8); - break; - case (EcmaOpcode::CALLARG1DYN_PREF_V8_V8): - jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8); - break; - case (EcmaOpcode::CALLARGS2DYN_PREF_V8_V8_V8): - jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8_V8); - break; - case (EcmaOpcode::CALLARGS3DYN_PREF_V8_V8_V8_V8): - jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_V8_V8_V8_V8); - break; - case (EcmaOpcode::CALLIRANGEDYN_PREF_IMM16_V8): - jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_IMM16_V8); - break; - case (EcmaOpcode::CALLITHISRANGEDYN_PREF_IMM16_V8): - jumpSize = BytecodeInstruction::Size(BytecodeInstruction::Format::PREF_IMM16_V8); - break; - default: - UNREACHABLE(); - } - - return jumpSize; -} - -JSTaggedValue EcmaInterpreter::GetRuntimeProfileTypeInfo(TaggedType *sp) -{ - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - FrameState *state = reinterpret_cast(sp) - 1; - return state->profileTypeInfo; -} - -bool EcmaInterpreter::UpdateHotnessCounter(JSThread* thread, TaggedType *sp, JSTaggedValue acc, int32_t offset) -{ - FrameState *state = GET_FRAME(sp); - auto method = state->method; - auto hotnessCounter = static_cast(method->GetHotnessCounter()); - - hotnessCounter += offset; - if (UNLIKELY(hotnessCounter <= 0)) { - if (state->profileTypeInfo == JSTaggedValue::Undefined()) { - state->acc = acc; - auto numVregs = method->GetNumVregs(); - // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) - auto thisFunc = JSTaggedValue(sp[numVregs]); - auto res = SlowRuntimeStub::NotifyInlineCache( - thread, JSFunction::Cast(thisFunc.GetHeapObject()), method); - state->profileTypeInfo = res; - method->SetHotnessCounter(std::numeric_limits::max()); - return true; - } else { - hotnessCounter = std::numeric_limits::max(); - } - } - method->SetHotnessCounter(static_cast(hotnessCounter)); - return false; -} -#if defined(__clang__) -#pragma clang diagnostic pop -#elif defined(__GNUC__) -#pragma GCC diagnostic pop -#endif -} // namespace panda::ecmascript -#endif // ECMASCRIPT_INTERPRETER_INTERPRETER_INL_H -- Gitee From 2e4c0ee9d1f11191906675f4d7873d56b3de2314 Mon Sep 17 00:00:00 2001 From: Han00000000 Date: Sun, 19 Sep 2021 22:05:41 +0800 Subject: [PATCH 06/11] fixed 138e227 from https://gitee.com/Han00000000/ark_js_runtime/pulls/84 fix README Signed-off-by: Han00000000 Change-Id: I8a4e017492cc1798a7524608738a2e61c8ead427 --- README.md | 8 ++++---- README_zh.md | 8 +++----- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 99fc3c4781..f9ba018a5a 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ For more infomation, see: [ARK Runtime Subsystem](https://gitee.com/openharmony/ ## Build ``` -./build.sh --product-name Hi3516DV300 --build-target ark\_js\_runtime +./build.sh --product-name Hi3516DV300 --build-target ark_js_runtime ``` ### Available APIs @@ -66,9 +66,9 @@ For details about how to generate JS bytecodes, see [Using the Toolchain](docs/ To run bytecodes: ``` -cd out/release -LD\_LIBRARY\_PATH=clang\_x64/ark/ark\_js\_runtime:clang\_x64/ark/ark:clang\_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86\_64/llvm/lib/ -./clang\_x64/ark/ark\_js\_runtime/ark\_js\_vm helloworld.abc +$ cd out/release +$ export LD_LIBRARY_PATH=clang_x64/ark/ark_js_runtime:clang_x64/ark/ark:clang_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/ +$ ./clang_x64/ark/ark_js_runtime/ark_js_vm helloworld.abc ``` For more infomation, please see: [ARK-Runtime-Usage-Guide](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Usage-Guide.md). diff --git a/README_zh.md b/README_zh.md index d7adae57ad..4a7ad9eb04 100644 --- a/README_zh.md +++ b/README_zh.md @@ -66,11 +66,9 @@ JS生成字节码参考[工具链使用](docs/using-the-toolchain-zh.md) 字节码执行: ``` -cd out/release - -LD\_LIBRARY\_PATH=clang\_x64/ark/ark\_js\_runtime:clang\_x64/ark/ark:clang\_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86\_64/llvm/lib/ - -./clang\_x64/ark/ark\_js\_runtime/ark\_js\_vm helloworld.abc +$ cd out/release +$ export LD_LIBRARY_PATH=clang_x64/ark/ark_js_runtime:clang_x64/ark/ark:clang_x64/global/i18n:../../prebuilts/clang/ohos/linux-x86_64/llvm/lib/ +$ ./clang_x64/ark/ark_js_runtime/ark_js_vm helloworld.abc ``` 更多使用说明请参考:[方舟运行时使用指南](https://gitee.com/openharmony/ark_js_runtime/blob/master/docs/ARK-Runtime-Usage-Guide-zh.md) -- Gitee From 6eab4cc4f39cd4a40fd93679748a220db9c84fbd Mon Sep 17 00:00:00 2001 From: Han Date: Sun, 19 Sep 2021 14:40:33 +0000 Subject: [PATCH 07/11] update README_zh.md. Signed-off-by: Han00000000 --- README_zh.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README_zh.md b/README_zh.md index 4a7ad9eb04..952dce67e1 100644 --- a/README_zh.md +++ b/README_zh.md @@ -53,7 +53,7 @@ ## 编译构建 ``` -./build.sh --product-name Hi3516DV300 --build-target ark\_js\_runtime +$ ./build.sh --product-name Hi3516DV300 --build-target ark_js_runtime ``` ### 接口说明 -- Gitee From 724404bda538019df58956778bc9d827fee390e6 Mon Sep 17 00:00:00 2001 From: Han00000000 Date: Sun, 19 Sep 2021 18:11:35 +0800 Subject: [PATCH 08/11] fixed 536d127 from https://gitee.com/Han00000000/ark_js_runtime/pulls/82 fix ace2.0 bugs Signed-off-by: Han00000000 Change-Id: I6a1b3889eb3a10108aa479bacab553f89ed73efa --- BUILD.gn | 6 ++++-- ecmascript/js_object.h | 2 +- ecmascript/js_tagged_value.cpp | 5 ++--- ecmascript/napi/jsnapi.cpp | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/BUILD.gn b/BUILD.gn index 0f8e7fe84d..ece963d62d 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -51,7 +51,8 @@ group("ark_js_unittest") { "//ark/js_runtime/ecmascript/regexp/tests:unittest", "//ark/js_runtime/ecmascript/snapshot/tests:unittest", "//ark/js_runtime/ecmascript/tests:unittest", - "//ark/js_runtime/ecmascript/tooling/test:unittest", + + # "//ark/js_runtime/ecmascript/tooling/test:unittest", ] } } @@ -68,7 +69,8 @@ group("ark_js_host_unittest") { "//ark/js_runtime/ecmascript/regexp/tests:host_unittest", "//ark/js_runtime/ecmascript/snapshot/tests:host_unittest", "//ark/js_runtime/ecmascript/tests:host_unittest", - "//ark/js_runtime/ecmascript/tooling/test:host_unittest", + + # "//ark/js_runtime/ecmascript/tooling/test:host_unittest", ] if (current_cpu == "x86_64" || current_cpu == "x64") { deps += [ "//ark/js_runtime/ecmascript/compiler:libark_jsoptimizer(${host_toolchain})" ] diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index 127658b16b..1aabc268d5 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -353,7 +353,7 @@ public: void VisitObjects([[maybe_unused]] const EcmaObjectRangeVisitor &visitor) const { - // no field in this object + Visitor(visitor); } }; diff --git a/ecmascript/js_tagged_value.cpp b/ecmascript/js_tagged_value.cpp index b86a3f164a..3b7ca1440a 100644 --- a/ecmascript/js_tagged_value.cpp +++ b/ecmascript/js_tagged_value.cpp @@ -261,11 +261,10 @@ JSTaggedValue JSTaggedValue::ToPrimitive(JSThread *thread, const JSHandleIsECMAObject()) { - JSHandle object(tagged); EcmaVM *vm = thread->GetEcmaVM(); JSHandle keyString = vm->GetGlobalEnv()->GetToPrimitiveSymbol(); - JSHandle exoticToprim = JSObject::GetProperty(thread, object, keyString).GetValue(); + JSHandle exoticToprim = GetProperty(thread, tagged, keyString).GetValue(); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); if (!exoticToprim->IsUndefined()) { JSTaggedValue value = GetTypeString(thread, type).GetTaggedValue(); @@ -298,7 +297,7 @@ JSTaggedValue JSTaggedValue::OrdinaryToPrimitive(JSThread *thread, const JSHandl } else { keyString = globalConst->GetHandledValueOfString(); } - JSHandle entryfunc = JSObject::GetProperty(thread, tagged, keyString).GetValue(); + JSHandle entryfunc = GetProperty(thread, tagged, keyString).GetValue(); if (entryfunc->IsCallable()) { JSTaggedValue valueResult = JSFunction::Call(thread, entryfunc, tagged, 0, nullptr); RETURN_VALUE_IF_ABRUPT_COMPLETION(thread, JSTaggedValue::Exception()); diff --git a/ecmascript/napi/jsnapi.cpp b/ecmascript/napi/jsnapi.cpp index 4ab3e3ad29..bc4c9f1536 100644 --- a/ecmascript/napi/jsnapi.cpp +++ b/ecmascript/napi/jsnapi.cpp @@ -580,7 +580,7 @@ Local ObjectRef::Get(const EcmaVM *vm, Local key) OperationResult ret = JSTaggedValue::GetProperty(thread, obj, keyValue); RETURN_VALUE_IF_ABRUPT(thread, JSValueRef::Exception(vm)); if (!ret.GetPropertyMetaData().IsFound()) { - return Local(); + return JSValueRef::Undefined(vm); } return JSNApiHelper::ToLocal(ret.GetValue()); } -- Gitee From 430122142d84fab5255157accaf3ac518a4d43f4 Mon Sep 17 00:00:00 2001 From: linxiang Date: Wed, 22 Sep 2021 14:10:02 +0800 Subject: [PATCH 09/11] fix ace2.0 hashcode initialization bugs Signed-off-by: linxiang --- ecmascript/js_object.h | 5 +++++ ecmascript/object_factory.cpp | 1 + 2 files changed, 6 insertions(+) diff --git a/ecmascript/js_object.h b/ecmascript/js_object.h index 127658b16b..7371b866a0 100644 --- a/ecmascript/js_object.h +++ b/ecmascript/js_object.h @@ -339,6 +339,10 @@ public: void SetHash(int32_t hash); int32_t GetHash() const; + void InitializeHash() + { + Barriers::SetDynPrimitive(this, ECMAObject::HASH_OFFSET, JSTaggedValue(0).GetRawData()); + } void* GetNativePointerField(int32_t index) const; void SetNativePointerField(int32_t index, void *data); @@ -354,6 +358,7 @@ public: void VisitObjects([[maybe_unused]] const EcmaObjectRangeVisitor &visitor) const { // no field in this object + Visitor(visitor); } }; diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 7282588009..0e4ed0a300 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -290,6 +290,7 @@ JSHandle ObjectFactory::NewJSObject(const JSHandle &jshclass NewObjectHook(); JSHandle obj(thread_, JSObject::Cast(NewDynObject(jshclass, JSHClass::DEFAULT_CAPACITY_OF_IN_OBJECTS))); JSHandle emptyArray = EmptyArray(); + obj->InitializeHash(); obj->SetElements(thread_, emptyArray, SKIP_BARRIER); obj->SetProperties(thread_, emptyArray, SKIP_BARRIER); return obj; -- Gitee From e2c64acdc4e2bd8a95e58e88dad88dd20127ec21 Mon Sep 17 00:00:00 2001 From: zhangyukun Date: Wed, 22 Sep 2021 16:25:41 +0800 Subject: [PATCH 10/11] Clean Codedex and reviewbot in ark js_runtime Signed-off-by: zhangyukun --- ecmascript/compiler/stub_interface.h | 22 +++++++++++----------- ecmascript/compiler/stub_optimizer.h | 7 +++---- ecmascript/ecma_handle_scope.h | 2 +- ecmascript/ecma_string.h | 12 +++--------- ecmascript/internal_call_params.h | 10 +++++----- ecmascript/js_date_time_format.h | 2 +- ecmascript/js_locale.h | 8 ++++---- ecmascript/js_number_format.h | 16 +++++++++------- ecmascript/mem/compress_gc_marker-inl.h | 2 +- ecmascript/mem/region_factory.h | 10 +++++----- ecmascript/napi/include/jsnapi.h | 4 ++-- ecmascript/vmstat/caller_stat.h | 16 ++++++++-------- 12 files changed, 53 insertions(+), 58 deletions(-) diff --git a/ecmascript/compiler/stub_interface.h b/ecmascript/compiler/stub_interface.h index 758fb6f1fa..529c9db47a 100644 --- a/ecmascript/compiler/stub_interface.h +++ b/ecmascript/compiler/stub_interface.h @@ -121,13 +121,13 @@ public: } private: - CallStubKind kind_{CODE_STUB}; - int flags_{0}; - int paramCounter_{0}; - ArgumentsOrder order_{DEFAULT_ORDER}; + CallStubKind kind_ {CODE_STUB}; + int flags_ {0}; + int paramCounter_ {0}; + ArgumentsOrder order_ {DEFAULT_ORDER}; - MachineType returnType_{MachineType::NONE_TYPE}; - std::unique_ptr> paramsType_{nullptr}; + MachineType returnType_ {MachineType::NONE_TYPE}; + std::unique_ptr> paramsType_ {nullptr}; }; class CallStubsImplement { @@ -160,9 +160,9 @@ public: } private: - std::array llvmCallStubs_{nullptr}; - std::array llvm_fuction_type_{nullptr}; - LLVMModuleRef stubsModule_{nullptr}; + std::array llvmCallStubs_ {nullptr}; + std::array llvm_fuction_type_ {nullptr}; + LLVMModuleRef stubsModule_ {nullptr}; }; // NOLINTNEXTLINE(cppcoreguidelines-macro-usage) #define FAST_STUB_ID(name) NAME_##name @@ -219,8 +219,8 @@ private: ~FastStubs() {} NO_MOVE_SEMANTIC(FastStubs); NO_COPY_SEMANTIC(FastStubs); - std::unique_ptr stubsImpl_{nullptr}; - std::array callStubsDescriptor_{}; + std::unique_ptr stubsImpl_ {nullptr}; + std::array callStubsDescriptor_ {}; }; } // namespace kungfu #endif // ECMASCRIPT_COMPILER_STUB_INTERFACE_H \ No newline at end of file diff --git a/ecmascript/compiler/stub_optimizer.h b/ecmascript/compiler/stub_optimizer.h index cedc09c784..16846802c7 100644 --- a/ecmascript/compiler/stub_optimizer.h +++ b/ecmascript/compiler/stub_optimizer.h @@ -707,9 +707,8 @@ public: Word64Equal(Word64And(x, GetWord64Constant(~panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)), GetWord64Constant(0))), WordLogicOr(SExtInt1ToInt32(Word64NotEqual( - Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)), - GetWord64Constant(0))), - SExtInt1ToInt32(TaggedIsHole(x))))); + Word64And(x, GetWord64Constant(panda::ecmascript::JSTaggedValue::TAG_SPECIAL_MASK)), + GetWord64Constant(0))), SExtInt1ToInt32(TaggedIsHole(x))))); } AddrShift TaggedIsHeapObject(AddrShift x) @@ -994,7 +993,7 @@ public: Word64Or(Word64And(oldValue, GetWord64Constant(~panda::ecmascript::JSHClass::ElementRepresentationBits::Mask())), Word64LSR(value, GetWord64Constant( - panda::ecmascript::JSHClass::ElementRepresentationBits::START_BIT)))); + panda::ecmascript::JSHClass::ElementRepresentationBits::START_BIT)))); } void UpdateValueAndDetails(AddrShift elements, AddrShift index, AddrShift value, AddrShift attr) diff --git a/ecmascript/ecma_handle_scope.h b/ecmascript/ecma_handle_scope.h index 13604c4555..b0b88d52e2 100644 --- a/ecmascript/ecma_handle_scope.h +++ b/ecmascript/ecma_handle_scope.h @@ -42,7 +42,7 @@ private: JSThread *thread_; JSTaggedType *prevNext_; JSTaggedType *prevEnd_; - int prevHandleStorageIndex_{-1}; + int prevHandleStorageIndex_ {-1}; NO_COPY_SEMANTIC(EcmaHandleScope); NO_MOVE_SEMANTIC(EcmaHandleScope); diff --git a/ecmascript/ecma_string.h b/ecmascript/ecma_string.h index 499295787b..2781094489 100644 --- a/ecmascript/ecma_string.h +++ b/ecmascript/ecma_string.h @@ -65,9 +65,7 @@ public: return length * sizeof(dataUtf16_[0]); } - /** - * Methods for uncompressed strings (UTF16): - */ + // Methods for uncompressed strings (UTF16): static size_t ComputeSizeUtf16(uint32_t utf16Len) { return sizeof(EcmaString) + ComputeDataSizeUtf16(utf16Len); @@ -79,17 +77,13 @@ public: return dataUtf16_; } - /** - * Methods for compresses strings (UTF8 or LATIN1): - */ + // Methods for compresses strings (UTF8 or LATIN1): static size_t ComputeSizeUtf8(uint32_t utf8Len) { return sizeof(EcmaString) + utf8Len; } - /** - * It's Utf8 format, but without 0 in the end. - */ + // It's Utf8 format, but without 0 in the end. const uint8_t *GetDataUtf8() const { LOG_IF(IsUtf16(), FATAL, RUNTIME) << "EcmaString: Read data as utf8 for utf16 string"; diff --git a/ecmascript/internal_call_params.h b/ecmascript/internal_call_params.h index 2d97914037..b873d28ad3 100644 --- a/ecmascript/internal_call_params.h +++ b/ecmascript/internal_call_params.h @@ -213,11 +213,11 @@ private: variable_data_.insert(variable_data_.begin(), val.GetRawData()); } - std::array fixed_data_{}; - CVector variable_data_{}; - uint32_t fixed_length_{0}; - uint32_t variable_length_{0}; - bool variable_mode_{false}; + std::array fixed_data_ {}; + CVector variable_data_ {}; + uint32_t fixed_length_ {0}; + uint32_t variable_length_ {0}; + bool variable_mode_ {false}; }; } // namespace panda::ecmascript diff --git a/ecmascript/js_date_time_format.h b/ecmascript/js_date_time_format.h index eaedd7f34c..e1121b37d7 100644 --- a/ecmascript/js_date_time_format.h +++ b/ecmascript/js_date_time_format.h @@ -79,7 +79,7 @@ public: } private: - std::vector data{}; + std::vector data {}; NO_COPY_SEMANTIC(Pattern); NO_MOVE_SEMANTIC(Pattern); }; diff --git a/ecmascript/js_locale.h b/ecmascript/js_locale.h index e553afef86..ccb87729a9 100644 --- a/ecmascript/js_locale.h +++ b/ecmascript/js_locale.h @@ -111,10 +111,10 @@ public: } private: - std::vector data_{}; - array_size_t length_{0}; - array_size_t curIdx_{0}; - icu::Locale locale_{}; + std::vector data_ {}; + array_size_t length_ {0}; + array_size_t curIdx_ {0}; + icu::Locale locale_ {}; }; struct ResolvedLocale { diff --git a/ecmascript/js_number_format.h b/ecmascript/js_number_format.h index bf0791b9c8..5bb865212d 100644 --- a/ecmascript/js_number_format.h +++ b/ecmascript/js_number_format.h @@ -41,13 +41,15 @@ struct FractionDigitsOption { int32_t mxfdDefault = 0; }; -static const std::set sanctionedUnit({ "acre", "bit", "byte", "celsius", "centimeter", "day", "degree", - "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte", - "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram", - "kilometer", "liter", "megabit", "megabyte", "meter", "mile", - "mile-scandinavian", "millimeter", "milliliter", "millisecond", - "minute", "month", "ounce", "percent", "petabyte", "pound", "second", - "stone", "terabit", "terabyte", "week", "yard", "year" }); +static const std::set sanctionedUnit({ + "acre", "bit", "byte", "celsius", "centimeter", "day", "degree", + "fahrenheit", "fluid-ounce", "foot", "gallon", "gigabit", "gigabyte", + "gram", "hectare", "hour", "inch", "kilobit", "kilobyte", "kilogram", + "kilometer", "liter", "megabit", "megabyte", "meter", "mile", + "mile-scandinavian", "millimeter", "milliliter", "millisecond", + "minute", "month", "ounce", "percent", "petabyte", "pound", "second", + "stone", "terabit", "terabyte", "week", "yard", "year" +}); class JSNumberFormat : public JSObject { public: diff --git a/ecmascript/mem/compress_gc_marker-inl.h b/ecmascript/mem/compress_gc_marker-inl.h index 1f52bfc10f..5363bb362a 100644 --- a/ecmascript/mem/compress_gc_marker-inl.h +++ b/ecmascript/mem/compress_gc_marker-inl.h @@ -80,7 +80,7 @@ inline void CompressGCMarker::EvacuateObject(uint32_t threadId, TaggedObject *ob inline void CompressGCMarker::CopyObjectWithoutHeader(TaggedObject *object, uintptr_t address, size_t size) { if (memcpy_s(ToVoidPtr(address + HEAD_SIZE), size - HEAD_SIZE, ToVoidPtr(ToUintPtr(object) + HEAD_SIZE), - size - HEAD_SIZE) != EOK) { + size - HEAD_SIZE) != EOK) { LOG_ECMA(FATAL) << "memcpy_s failed"; UNREACHABLE(); } diff --git a/ecmascript/mem/region_factory.h b/ecmascript/mem/region_factory.h index af2bf0438b..fa70e81a23 100644 --- a/ecmascript/mem/region_factory.h +++ b/ecmascript/mem/region_factory.h @@ -124,11 +124,11 @@ private: NO_COPY_SEMANTIC(RegionFactory); NO_MOVE_SEMANTIC(RegionFactory); - Area *cachedArea_{nullptr}; - std::atomic annoMemoryUsage_{0}; - std::atomic maxAnnoMemoryUsage_{0}; - std::atomic nativeMemoryUsage_{0}; - std::atomic maxNativeMemoryUsage_{0}; + Area *cachedArea_ {nullptr}; + std::atomic annoMemoryUsage_ {0}; + std::atomic maxAnnoMemoryUsage_ {0}; + std::atomic nativeMemoryUsage_ {0}; + std::atomic maxNativeMemoryUsage_ {0}; }; } // namespace panda::ecmascript diff --git a/ecmascript/napi/include/jsnapi.h b/ecmascript/napi/include/jsnapi.h index 4bf334dd88..01b2f65c93 100644 --- a/ecmascript/napi/include/jsnapi.h +++ b/ecmascript/napi/include/jsnapi.h @@ -525,10 +525,10 @@ public: }; using FunctionCallback = Local (*)(EcmaVM *, Local, - const Local[], // NOLINTNEXTLINE(modernize-avoid-c-arrays) + const Local [], // NOLINTNEXTLINE(modernize-avoid-c-arrays) int32_t, void *); using FunctionCallbackWithNewTarget = - Local (*)(EcmaVM *, Local, Local, const Local[], int32_t, void *); + Local (*)(EcmaVM *, Local, Local, const Local [], int32_t, void *); class PUBLIC_API FunctionRef : public ObjectRef { public: static Local New(EcmaVM *vm, FunctionCallback nativeFunc, void *data); diff --git a/ecmascript/vmstat/caller_stat.h b/ecmascript/vmstat/caller_stat.h index 88bc26f71c..58db728f61 100644 --- a/ecmascript/vmstat/caller_stat.h +++ b/ecmascript/vmstat/caller_stat.h @@ -66,10 +66,10 @@ public: } private: - CString name_{}; - uint64_t totalCount_{0}; - uint64_t totalTime_{0}; - uint64_t maxTime_{0}; + CString name_ {}; + uint64_t totalCount_ {0}; + uint64_t totalTime_ {0}; + uint64_t maxTime_ {0}; }; class PandaRuntimeTimer { @@ -109,10 +109,10 @@ private: PandaRuntimeTimer *Stop(); void Pause(uint64_t now); void Resume(uint64_t now); - PandaRuntimeCallerStat *callerStat_{nullptr}; - PandaRuntimeTimer *parent_{nullptr}; - uint64_t start_{0}; - uint64_t elapsed_{0}; + PandaRuntimeCallerStat *callerStat_ {nullptr}; + PandaRuntimeTimer *parent_ {nullptr}; + uint64_t start_ {0}; + uint64_t elapsed_ {0}; friend class EcmaRuntimeStat; }; -- Gitee From e01156ac26743419fd165e44d9d9ca465f3847f2 Mon Sep 17 00:00:00 2001 From: "yingguofeng@huawei.com" Date: Fri, 24 Sep 2021 14:31:54 +0800 Subject: [PATCH 11/11] Concurrent sweep Signed-off-by: yingguofeng@huawei.com --- BUILD.gn | 4 + ecmascript/ecma_vm.cpp | 3 + ecmascript/mem/allocator-inl.h | 55 ++++- ecmascript/mem/allocator.h | 15 +- ecmascript/mem/compress_collector.cpp | 62 +---- ecmascript/mem/compress_collector.h | 1 - ecmascript/mem/concurrent_sweeper.cpp | 257 +++++++++++++++++++++ ecmascript/mem/concurrent_sweeper.h | 95 ++++++++ ecmascript/mem/ecma_heap_manager-inl.h | 22 +- ecmascript/mem/ecma_heap_manager.cpp | 5 +- ecmascript/mem/ecma_heap_manager.h | 21 +- ecmascript/mem/free_object_kind.cpp | 3 + ecmascript/mem/free_object_kind.h | 5 +- ecmascript/mem/free_object_list.cpp | 114 +++++---- ecmascript/mem/free_object_list.h | 20 +- ecmascript/mem/heap.cpp | 19 +- ecmascript/mem/heap.h | 7 + ecmascript/mem/old_space_collector-inl.h | 15 +- ecmascript/mem/old_space_collector.cpp | 93 ++------ ecmascript/mem/old_space_collector.h | 17 +- ecmascript/mem/region.h | 36 ++- ecmascript/mem/semi_space_collector.cpp | 2 +- ecmascript/mem/semi_space_collector.h | 1 - ecmascript/mem/semi_space_worker.cpp | 29 +++ ecmascript/mem/semi_space_worker.h | 15 +- ecmascript/mem/space.cpp | 31 ++- ecmascript/mem/space.h | 12 +- ecmascript/mem/tlab_allocator-inl.h | 2 +- ecmascript/object_factory.cpp | 2 + ecmascript/platform/platform.cpp | 45 ++++ ecmascript/platform/platform.h | 59 +++++ ecmascript/platform/runner.cpp | 49 ++++ ecmascript/platform/runner.h | 48 ++++ ecmascript/platform/task.h | 32 +++ ecmascript/platform/task_queue.cpp | 50 ++++ ecmascript/platform/task_queue.h | 49 ++++ ecmascript/tests/BUILD.gn | 1 + ecmascript/tests/concurrent_sweep_test.cpp | 64 +++++ 38 files changed, 1102 insertions(+), 258 deletions(-) create mode 100644 ecmascript/mem/concurrent_sweeper.cpp create mode 100644 ecmascript/mem/concurrent_sweeper.h create mode 100644 ecmascript/platform/platform.cpp create mode 100644 ecmascript/platform/platform.h create mode 100644 ecmascript/platform/runner.cpp create mode 100644 ecmascript/platform/runner.h create mode 100644 ecmascript/platform/task.h create mode 100644 ecmascript/platform/task_queue.cpp create mode 100644 ecmascript/platform/task_queue.h create mode 100644 ecmascript/tests/concurrent_sweep_test.cpp diff --git a/BUILD.gn b/BUILD.gn index ece963d62d..7f1300c2ec 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -327,6 +327,7 @@ ecma_source = [ "ecmascript/mem/c_string.cpp", "ecmascript/mem/chunk.cpp", "ecmascript/mem/compress_collector.cpp", + "ecmascript/mem/concurrent_sweeper.cpp", "ecmascript/mem/ecma_heap_manager.cpp", "ecmascript/mem/free_object_kind.cpp", "ecmascript/mem/free_object_list.cpp", @@ -344,6 +345,9 @@ ecma_source = [ "ecmascript/napi/jsnapi.cpp", "ecmascript/object_factory.cpp", "ecmascript/object_operator.cpp", + "ecmascript/platform/platform.cpp", + "ecmascript/platform/runner.cpp", + "ecmascript/platform/task_queue.cpp", "ecmascript/layout_info.cpp", "ecmascript/regexp/dyn_chunk.cpp", "ecmascript/regexp/regexp_executor.cpp", diff --git a/ecmascript/ecma_vm.cpp b/ecmascript/ecma_vm.cpp index 31bb8274e6..33b1a4b0d6 100644 --- a/ecmascript/ecma_vm.cpp +++ b/ecmascript/ecma_vm.cpp @@ -35,6 +35,7 @@ #include "ecmascript/mem/heap.h" #include "ecmascript/tagged_dictionary.h" #include "ecmascript/object_factory.h" +#include "ecmascript/platform/platform.h" #include "ecmascript/regexp/regexp_parser_cache.h" #include "ecmascript/runtime_call_id.h" #include "ecmascript/runtime_trampolines.h" @@ -116,6 +117,7 @@ EcmaVM::EcmaVM(RuntimeOptions options) bool EcmaVM::Initialize() { trace::ScopedTrace scoped_trace("EcmaVM::Initialize"); + Platform::GetCurrentPlatform()->Initialize(); RuntimeTrampolines::InitializeRuntimeTrampolines(thread_); @@ -231,6 +233,7 @@ bool EcmaVM::InitializeFinish() } EcmaVM::~EcmaVM() { + Platform::GetCurrentPlatform()->Destory(); vmInitialized_ = false; ClearNativeMethodsData(); diff --git a/ecmascript/mem/allocator-inl.h b/ecmascript/mem/allocator-inl.h index bf0d150fcb..0117a740a9 100644 --- a/ecmascript/mem/allocator-inl.h +++ b/ecmascript/mem/allocator-inl.h @@ -19,6 +19,7 @@ #include #include "ecmascript/mem/allocator.h" +#include "ecmascript/mem/concurrent_sweeper.h" #include "ecmascript/mem/heap-inl.h" #include "ecmascript/mem/space.h" #include "ecmascript/free_object.h" @@ -67,13 +68,13 @@ uintptr_t BumpPointerAllocator::Allocate(size_t size) return result; } -FreeListAllocator::FreeListAllocator(const Space *space) +FreeListAllocator::FreeListAllocator(const Space *space) : heap_(space->GetHeap()), type_(space->GetSpaceType()) { freeList_ = std::make_unique(); - heap_ = space->GetHeap(); uintptr_t begin = space->GetCurrentRegion()->GetBegin(); size_t size = space->GetCurrentRegion()->GetSize(); FreeObject::Cast(begin)->SetAvailable(size); + FreeObject::Cast(begin)->SetNext(nullptr); freeList_->Free(begin, size); } @@ -96,18 +97,39 @@ uintptr_t FreeListAllocator::Allocate(size_t size) } FreeObject *object = freeList_->Allocator(size); if (LIKELY(object != nullptr && !object->IsEmpty())) { - FreeBumpPoint(); - bpAllocator_.Reset(object->GetBegin(), object->GetEnd()); - ret = bpAllocator_.Allocate(size); - if (ret != 0 && bpAllocator_.Available() > 0) { - FreeObject::FillFreeObject(heap_->GetEcmaVM(), bpAllocator_.GetTop(), bpAllocator_.Available()); + return Allocate(object, size); + } + + if (sweeping_) { + // Concurrent sweep maybe sweep same region + heap_->GetSweeper()->FillSweptRegion(type_); + object = freeList_->Allocator(size); + if (LIKELY(object != nullptr && !object->IsEmpty())) { + return Allocate(object, size); + } + + // Parallel + heap_->GetSweeper()->ParallelSweepSpace(type_); + object = freeList_->Allocator(size); + if (LIKELY(object != nullptr && !object->IsEmpty())) { + return Allocate(object, size); } - return ret; } return 0; } +uintptr_t FreeListAllocator::Allocate(FreeObject *object, size_t size) +{ + FreeBumpPoint(); + bpAllocator_.Reset(object->GetBegin(), object->GetEnd()); + auto ret = bpAllocator_.Allocate(size); + if (ret != 0 && bpAllocator_.Available() > 0) { + FreeObject::FillFreeObject(heap_->GetEcmaVM(), bpAllocator_.GetTop(), bpAllocator_.Available()); + } + return ret; +} + void FreeListAllocator::FreeBumpPoint() { auto begin = bpAllocator_.GetTop(); @@ -116,7 +138,7 @@ void FreeListAllocator::FreeBumpPoint() bpAllocator_.Reset(); } -void FreeListAllocator::Free(uintptr_t begin, uintptr_t end) +void FreeListAllocator::Free(uintptr_t begin, uintptr_t end, bool isAdd) { ASSERT(heap_ != nullptr); size_t size = end - begin; @@ -125,7 +147,7 @@ void FreeListAllocator::Free(uintptr_t begin, uintptr_t end) } FreeObject::FillFreeObject(heap_->GetEcmaVM(), begin, size); - freeList_->Free(begin, static_cast(end - begin)); + freeList_->Free(begin, size, isAdd); } void FreeListAllocator::RebuildFreeList() @@ -133,5 +155,18 @@ void FreeListAllocator::RebuildFreeList() bpAllocator_.Reset(); freeList_->Rebuild(); } + +void FreeListAllocator::FillFreeList(FreeObjectKind *kind) +{ + freeList_->AddKind(kind); +} + +size_t FreeListAllocator::GetAvailableSize() const +{ + if (sweeping_) { + heap_->GetSweeper()->WaitingTaskFinish(type_); + } + return freeList_->GetFreeObjectSize(); +} } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_ALLOCATOR_INL_H diff --git a/ecmascript/mem/allocator.h b/ecmascript/mem/allocator.h index 25b3d3d4cc..0ea0cf0f08 100644 --- a/ecmascript/mem/allocator.h +++ b/ecmascript/mem/allocator.h @@ -91,28 +91,37 @@ public: inline void AddFree(Region *region); inline void RebuildFreeList(); + inline void FillFreeList(FreeObjectKind *kind); void Swap(FreeListAllocator &other) { heap_ = other.heap_; bpAllocator_.Swap(other.bpAllocator_); freeList_.swap(other.freeList_); + type_ = other.type_; + sweeping_ = other.sweeping_; } inline void FreeBumpPoint(); - inline void Free(uintptr_t begin, uintptr_t end); + inline void Free(uintptr_t begin, uintptr_t end, bool isAdd = true); inline void SplitFreeObject(FreeObject *current, size_t allocateSize); - size_t GetAvailableSize() const + inline size_t GetAvailableSize() const; + + void SetSweeping(bool sweeping) { - return freeList_->GetFreeObjectSize(); + sweeping_ = sweeping; } private: + inline uintptr_t Allocate(FreeObject *object, size_t size); + BumpPointerAllocator bpAllocator_; std::unique_ptr freeList_; Heap *heap_{nullptr}; + MemSpaceType type_ = OLD_SPACE; + bool sweeping_ = false; }; } // namespace panda::ecmascript diff --git a/ecmascript/mem/compress_collector.cpp b/ecmascript/mem/compress_collector.cpp index db3759594c..fe0ac9997f 100644 --- a/ecmascript/mem/compress_collector.cpp +++ b/ecmascript/mem/compress_collector.cpp @@ -13,9 +13,10 @@ * limitations under the License. */ +#include "ecmascript/mem/compress_collector.h" + #include "ecmascript/ecma_vm.h" #include "ecmascript/mem/clock_scope.h" -#include "ecmascript/mem/compress_collector.h" #include "ecmascript/mem/compress_gc_marker-inl.h" #include "ecmascript/mem/ecma_heap_manager.h" #include "ecmascript/mem/heap-inl.h" @@ -58,6 +59,7 @@ void CompressCollector::RunPhases() void CompressCollector::InitializePhase() { heap_->GetThreadPool()->WaitTaskFinish(); + heap_->GetSweeper()->EnsureAllTaskFinish(); auto compressSpace = const_cast(heap_->GetCompressSpace()); if (compressSpace->GetCommittedSize() == 0) { compressSpace->Initialize(); @@ -70,8 +72,6 @@ void CompressCollector::InitializePhase() FreeListAllocator compressAllocator(compressSpace); oldSpaceAllocator_.Swap(compressAllocator); fromSpaceAllocator_.Reset(fromSpace); - auto heapManager = heap_->GetHeapManager(); - nonMovableAllocator_.Swap(heapManager->GetNonMovableSpaceAllocator()); auto callback = [](Region *current) { // ensure mark bitmap @@ -116,7 +116,6 @@ void CompressCollector::FinishPhase() workList_->Finish(youngAndOldAliveSize_); auto heapManager = heap_->GetHeapManager(); heapManager->GetOldSpaceAllocator().Swap(oldSpaceAllocator_); - heapManager->GetNonMovableSpaceAllocator().Swap(nonMovableAllocator_); heapManager->GetNewSpaceAllocator().Swap(fromSpaceAllocator_); } @@ -230,60 +229,7 @@ void CompressCollector::SweepPhases() heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak); heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak); - SweepSpace(const_cast(heap_->GetNonMovableSpace()), nonMovableAllocator_); - SweepSpace(const_cast(heap_->GetHugeObjectSpace())); -} - -void CompressCollector::SweepSpace(HugeObjectSpace *space) -{ - Region *currentRegion = space->GetRegionList().GetFirst(); - while (currentRegion != nullptr) { - Region *next = currentRegion->GetNext(); - auto markBitmap = currentRegion->GetMarkBitmap(); - bool isMarked = false; - markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; }); - if (!isMarked) { - space->GetRegionList().RemoveNode(currentRegion); - space->ClearAndFreeRegion(currentRegion); - } - currentRegion = next; - } -} - -void CompressCollector::SweepSpace(Space *space, FreeListAllocator &allocator) -{ - allocator.RebuildFreeList(); - space->EnumerateRegions([this, &allocator](Region *current) { - auto markBitmap = current->GetMarkBitmap(); - ASSERT(markBitmap != nullptr); - uintptr_t freeStart = current->GetBegin(); - markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator](void *mem) { - ASSERT(current->InRange(ToUintPtr(mem))); - auto header = reinterpret_cast(mem); - auto klass = header->GetClass(); - JSType jsType = klass->GetObjectType(); - auto size = klass->SizeFromJSHClass(jsType, header); - size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); - - uintptr_t freeEnd = ToUintPtr(mem); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - freeStart = freeEnd + size; - }); - uintptr_t freeEnd = current->GetEnd(); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - }); -} - -void CompressCollector::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, - uintptr_t freeEnd) -{ - allocator.Free(freeStart, freeEnd); - nonMoveSpaceFreeSize_ += freeEnd - freeStart; - heap_->ClearSlotsRange(current, freeStart, freeEnd); + heap_->GetSweeper()->SweepPhases(true); } uintptr_t CompressCollector::AllocateOld(size_t size) diff --git a/ecmascript/mem/compress_collector.h b/ecmascript/mem/compress_collector.h index 535a3f47a0..8cfb405ed1 100644 --- a/ecmascript/mem/compress_collector.h +++ b/ecmascript/mem/compress_collector.h @@ -61,7 +61,6 @@ private: os::memory::Mutex mtx_; BumpPointerAllocator fromSpaceAllocator_{}; FreeListAllocator oldSpaceAllocator_{}; - FreeListAllocator nonMovableAllocator_{}; size_t youngAndOldAliveSize_ = 0; size_t nonMoveSpaceFreeSize_ = 0; diff --git a/ecmascript/mem/concurrent_sweeper.cpp b/ecmascript/mem/concurrent_sweeper.cpp new file mode 100644 index 0000000000..6430f4d50f --- /dev/null +++ b/ecmascript/mem/concurrent_sweeper.cpp @@ -0,0 +1,257 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/mem/concurrent_sweeper.h" + +#include "ecmascript/js_hclass-inl.h" +#include "ecmascript/mem/allocator-inl.h" +#include "ecmascript/mem/ecma_heap_manager.h" +#include "ecmascript/mem/free_object_list.h" +#include "ecmascript/mem/heap.h" +#include "ecmascript/platform/platform.h" + +namespace panda::ecmascript { +ConcurrentSweeper::ConcurrentSweeper(Heap *heap, bool concurrentSweep) + : heap_(heap), concurrentSweep_(concurrentSweep) +{ +} + +void ConcurrentSweeper::SweepPhases(bool compressGC) +{ + if (concurrentSweep_) { + // Add all region to region list. Ensure all task finish + trace::ScopedTrace scoped_trace("ConcurrentSweeper::SweepPhases"); + if (!compressGC) { + heap_->GetOldSpace()->EnumerateRegions([this](Region *current) { AddRegion(OLD_SPACE, current); }); + } + heap_->GetNonMovableSpace()->EnumerateRegions([this](Region *current) { AddRegion(NON_MOVABLE, current); }); + heap_->GetMachineCodeSpace()->EnumerateRegions([this](Region *current) { AddRegion(MACHINE_CODE_SPACE, current); }); + + // Prepare + isSweeping_ = true; + startSpaceType_ = compressGC ? NON_MOVABLE : OLD_SPACE; + for (int type = startSpaceType_; type < FREE_LIST_NUM; type++) { + auto spaceType = static_cast(type); + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(spaceType); + remainderTaskNum_[type] = FREE_LIST_NUM - startSpaceType_; + allocator.SetSweeping(true); + allocator.RebuildFreeList(); + } + + if (!compressGC) { + Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, OLD_SPACE)); + } + Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, NON_MOVABLE)); + Platform::GetCurrentPlatform()->PostTask(std::make_unique(this, MACHINE_CODE_SPACE)); + } else { + if (!compressGC) { + SweepSpace(const_cast(heap_->GetOldSpace()), heap_->GetHeapManager()->GetOldSpaceAllocator()); + } + SweepSpace(const_cast(heap_->GetNonMovableSpace()), + heap_->GetHeapManager()->GetNonMovableSpaceAllocator()); + SweepSpace(const_cast(heap_->GetMachineCodeSpace()), + heap_->GetHeapManager()->GetMachineCodeSpaceAllocator()); + } + SweepHugeSpace(); +} + +void ConcurrentSweeper::SweepSpace(MemSpaceType type, bool isMain) +{ + trace::ScopedTrace scoped_trace("Sweeper::SweepSpace"); + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type); + Region *current = GetRegionSafe(type); + while (current != nullptr) { + FreeRegion(current, allocator, isMain); + // Main thread sweeping region is added; + if (!isMain) { + AddSweptRegionSafe(type, current); + } + current = GetRegionSafe(type); + } + + if (!isMain) { + os::memory::LockHolder holder(mutexs_[type]); + remainderTaskNum_[type]--; + if (remainderTaskNum_[type] == 0) { + cvs_[type].SignalAll(); + } + } +} + +void ConcurrentSweeper::SweepSpace(Space *space, FreeListAllocator &allocator) +{ + allocator.RebuildFreeList(); + space->EnumerateRegions([this, &allocator](Region *current) { FreeRegion(current, allocator); }); +} + +void ConcurrentSweeper::SweepHugeSpace() +{ + trace::ScopedTrace scoped_trace("SweepSpace HugeObject"); + HugeObjectSpace *space = const_cast(heap_->GetHugeObjectSpace()); + Region *currentRegion = space->GetRegionList().GetFirst(); + + while (currentRegion != nullptr) { + Region *next = currentRegion->GetNext(); + auto markBitmap = currentRegion->GetMarkBitmap(); + bool isMarked = false; + markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; }); + if (!isMarked) { + space->GetRegionList().RemoveNode(currentRegion); + space->ClearAndFreeRegion(currentRegion); + } + currentRegion = next; + } +} + +void ConcurrentSweeper::FreeRegion(Region *current, FreeListAllocator &allocator, bool isMain) +{ + auto markBitmap = current->GetMarkBitmap(); + ASSERT(markBitmap != nullptr); + uintptr_t freeStart = current->GetBegin(); + markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator, isMain](void *mem) { + ASSERT(current->InRange(ToUintPtr(mem))); + auto header = reinterpret_cast(mem); + auto klass = header->GetClass(); + JSType jsType = klass->GetObjectType(); + auto size = klass->SizeFromJSHClass(jsType, header); + size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); + + uintptr_t freeEnd = ToUintPtr(mem); + if (freeStart != freeEnd) { + FreeLiveRange(allocator, current, freeStart, freeEnd, isMain); + } + freeStart = freeEnd + size; + }); + uintptr_t freeEnd = current->GetEnd(); + if (freeStart != freeEnd) { + FreeLiveRange(allocator, current, freeStart, freeEnd, isMain); + } +} + +void ConcurrentSweeper::FillSweptRegion(MemSpaceType type) +{ + trace::ScopedTrace scoped_trace("Sweeper::FillSweptRegion"); + if (sweptList_[type].empty()) { + return; + } + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type); + Region *region = nullptr; + while ((region = GetSweptRegionSafe(type)) != nullptr) { + region->EnumerateKinds([&allocator](FreeObjectKind *kind) { + if (kind == nullptr || kind->Empty()) { + return; + } + allocator.FillFreeList(kind); + }); + } +} + +void ConcurrentSweeper::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, + uintptr_t freeEnd, bool isMain) +{ + allocator.Free(freeStart, freeEnd, isMain); + heap_->ClearSlotsRange(current, freeStart, freeEnd); +} + +void ConcurrentSweeper::AddRegion(MemSpaceType type, Region *region) +{ + sweepingList_[type].emplace_back(region); +} + +Region *ConcurrentSweeper::GetRegionSafe(MemSpaceType type) +{ + os::memory::LockHolder holder(mutexs_[type]); + Region *region = nullptr; + if (!sweepingList_[type].empty()) { + region = sweepingList_[type].back(); + sweepingList_[type].pop_back(); + } + return region; +} + +void ConcurrentSweeper::AddSweptRegionSafe(MemSpaceType type, Region *region) +{ + os::memory::LockHolder holder(mutexs_[type]); + sweptList_[type].emplace_back(region); +} + +Region *ConcurrentSweeper::GetSweptRegionSafe(MemSpaceType type) +{ + os::memory::LockHolder holder(mutexs_[type]); + Region *region = nullptr; + if (!sweptList_[type].empty()) { + region = sweptList_[type].back(); + sweptList_[type].pop_back(); + } + return region; +} + +void ConcurrentSweeper::EnsureAllTaskFinish() +{ + if (!isSweeping_) { + return; + } + for (int i = startSpaceType_; i < FREE_LIST_NUM; i++) { + WaitingTaskFinish(static_cast(i)); + } + isSweeping_ = false; +} + +void ConcurrentSweeper::WaitingTaskFinish(MemSpaceType type) +{ + if (remainderTaskNum_[type] > 0) { + SweepSpace(type); + { + os::memory::LockHolder holder(mutexs_[type]); + while (remainderTaskNum_[type] > 0) { + cvs_[type].Wait(&mutexs_[type]); + } + } + } + FinishSweeping(type); +} + +void ConcurrentSweeper::ParallelSweepSpace(MemSpaceType type) +{ + if (remainderTaskNum_[type] > 0) { + SweepSpace(type); + } + + if (remainderTaskNum_[type] <= 0) { + FinishSweeping(type); + } else { + FillSweptRegion(type); + } +} + +void ConcurrentSweeper::FinishSweeping(MemSpaceType type) +{ + FillSweptRegion(type); + FreeListAllocator &allocator = heap_->GetHeapManager()->GetFreeListAllocator(type); + allocator.SetSweeping(false); + if (type == OLD_SPACE) { + heap_->RecomputeLimits(); + } +} + +bool ConcurrentSweeper::SweeperTask::Run() +{ + for (size_t i = 0; i < FREE_LIST_NUM - sweeper_->startSpaceType_; i++) { + auto type = static_cast((i + type_) % FREE_LIST_NUM); + sweeper_->SweepSpace(type, false); + } + return true; +} +} // namespace panda::ecmascript diff --git a/ecmascript/mem/concurrent_sweeper.h b/ecmascript/mem/concurrent_sweeper.h new file mode 100644 index 0000000000..fb83c35b25 --- /dev/null +++ b/ecmascript/mem/concurrent_sweeper.h @@ -0,0 +1,95 @@ +/* + * 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_ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H +#define PANDA_ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H + +#include +#include + +#include "ecmascript/mem/space.h" +#include "ecmascript/platform/task.h" +#include "os/mutex.h" + +namespace panda::ecmascript { +class FreeListAllocator; + +class ConcurrentSweeper { +public: + ConcurrentSweeper(Heap *heap, bool concurrentSweep); + ~ConcurrentSweeper() = default; + + NO_COPY_SEMANTIC(ConcurrentSweeper); + NO_MOVE_SEMANTIC(ConcurrentSweeper); + + void SweepPhases(bool compressGC = false); + + void EnsureAllTaskFinish(); + // Ensure task finish + void WaitingTaskFinish(MemSpaceType type); + // Parallel sweep space, does not guarantee the end of the task + void ParallelSweepSpace(MemSpaceType type); + + void FillSweptRegion(MemSpaceType type); + + bool IsConcurrentSweepEnabled() + { + return concurrentSweep_; + } + +private: + class SweeperTask : public Task { + public: + SweeperTask(ConcurrentSweeper *sweeper, MemSpaceType type) : sweeper_(sweeper), type_(type){}; + ~SweeperTask() override = default; + bool Run() override; + + NO_COPY_SEMANTIC(SweeperTask); + NO_MOVE_SEMANTIC(SweeperTask); + + private: + ConcurrentSweeper *sweeper_; + MemSpaceType type_; + }; + + void SweepSpace(MemSpaceType type, bool isMain = true); + void SweepSpace(Space *space, FreeListAllocator &allocator); + void SweepHugeSpace(); + void FinishSweeping(MemSpaceType type); + + void FreeRegion(Region *current, FreeListAllocator &allocator, bool isMain = true); + void FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, uintptr_t freeEnd, + bool isMain); + + void AddRegion(MemSpaceType type, Region *region); + Region *GetRegionSafe(MemSpaceType type); + + void AddSweptRegionSafe(MemSpaceType type, Region *region); + Region *GetSweptRegionSafe(MemSpaceType type); + + std::array mutexs_; + std::array cvs_; + std::array remainderTaskNum_ = {0, 0, 0}; + + std::array, FREE_LIST_NUM> sweepingList_; + std::array, FREE_LIST_NUM> sweptList_; + + Heap *heap_; + bool concurrentSweep_ = false; + bool isSweeping_ = false; + MemSpaceType startSpaceType_ = MemSpaceType::OLD_SPACE; +}; +} // namespace panda::ecmascript +#endif // PANDA_ECMASCRIPT_MEM_CONCURRENT_SWEEPER_H diff --git a/ecmascript/mem/ecma_heap_manager-inl.h b/ecmascript/mem/ecma_heap_manager-inl.h index 4b65d6c337..8b9f0e146b 100644 --- a/ecmascript/mem/ecma_heap_manager-inl.h +++ b/ecmascript/mem/ecma_heap_manager-inl.h @@ -83,18 +83,18 @@ TaggedObject *EcmaHeapManager::AllocateNonMovableOrHugeObject(JSHClass *hclass, if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { return AllocateHugeObject(hclass, size); } - auto object = reinterpret_cast(nonMovableAllocator_.Allocate(size)); + auto object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { if (heap_->CheckAndTriggerNonMovableGC()) { - object = reinterpret_cast(nonMovableAllocator_.Allocate(size)); + object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size)); } if (UNLIKELY(object == nullptr)) { // hclass must be nonmovable - if (!heap_->FillNonMovableSpaceAndTryGC(&nonMovableAllocator_)) { + if (!heap_->FillNonMovableSpaceAndTryGC(&GetNonMovableSpaceAllocator())) { LOG_ECMA_MEM(FATAL) << "OOM : extend failed"; UNREACHABLE(); } - object = reinterpret_cast(nonMovableAllocator_.Allocate(size)); + object = reinterpret_cast(GetNonMovableSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { heap_->ThrowOutOfMemoryError(size); UNREACHABLE(); @@ -140,18 +140,18 @@ TaggedObject *EcmaHeapManager::AllocateOldGenerationOrHugeObject(JSHClass *hclas if (size > MAX_REGULAR_HEAP_OBJECT_SIZE) { return AllocateHugeObject(hclass, size); } - auto object = reinterpret_cast(oldSpaceAllocator_.Allocate(size)); + auto object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { if (heap_->CheckAndTriggerOldGC()) { - object = reinterpret_cast(oldSpaceAllocator_.Allocate(size)); + object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size)); } if (UNLIKELY(object == nullptr)) { // hclass must nonmovable - if (!heap_->FillOldSpaceAndTryGC(&oldSpaceAllocator_)) { + if (!heap_->FillOldSpaceAndTryGC(&GetOldSpaceAllocator())) { LOG_ECMA_MEM(FATAL) << "OOM : extend failed"; UNREACHABLE(); } - object = reinterpret_cast(oldSpaceAllocator_.Allocate(size)); + object = reinterpret_cast(GetOldSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { heap_->ThrowOutOfMemoryError(size); UNREACHABLE(); @@ -186,12 +186,12 @@ TaggedObject *EcmaHeapManager::AllocateHugeObject(JSHClass *hclass, size_t size) TaggedObject *EcmaHeapManager::AllocateMachineCodeSpaceObject(JSHClass *hclass, size_t size) { - auto object = reinterpret_cast(machineCodeSpaceAllocator_.Allocate(size)); + auto object = reinterpret_cast(GetMachineCodeSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { - if (!heap_->FillMachineCodeSpaceAndTryGC(&machineCodeSpaceAllocator_)) { + if (!heap_->FillMachineCodeSpaceAndTryGC(&GetMachineCodeSpaceAllocator())) { return nullptr; } - object = reinterpret_cast(machineCodeSpaceAllocator_.Allocate(size)); + object = reinterpret_cast(GetMachineCodeSpaceAllocator().Allocate(size)); if (UNLIKELY(object == nullptr)) { heap_->ThrowOutOfMemoryError(size); return nullptr; diff --git a/ecmascript/mem/ecma_heap_manager.cpp b/ecmascript/mem/ecma_heap_manager.cpp index ea3d0b9826..4314882672 100644 --- a/ecmascript/mem/ecma_heap_manager.cpp +++ b/ecmascript/mem/ecma_heap_manager.cpp @@ -20,9 +20,8 @@ namespace panda::ecmascript { EcmaHeapManager::EcmaHeapManager(Heap *heap) : heap_(heap), newSpaceAllocator_(heap->GetNewSpace()), - nonMovableAllocator_(heap->GetNonMovableSpace()), - oldSpaceAllocator_(heap->GetOldSpace()), - machineCodeSpaceAllocator_(heap->GetMachineCodeSpace()) + freeListAllocator_ { FreeListAllocator(heap->GetOldSpace()), FreeListAllocator(heap_->GetNonMovableSpace()), + FreeListAllocator(heap->GetMachineCodeSpace()) } { ASSERT(heap != nullptr); heap->SetHeapManager(this); diff --git a/ecmascript/mem/ecma_heap_manager.h b/ecmascript/mem/ecma_heap_manager.h index 6bfd120149..82ec7bc71d 100644 --- a/ecmascript/mem/ecma_heap_manager.h +++ b/ecmascript/mem/ecma_heap_manager.h @@ -48,9 +48,14 @@ public: return heap_; } - FreeListAllocator &GetOldSpaceAllocator() + FreeListAllocator &GetFreeListAllocator(MemSpaceType type) { - return oldSpaceAllocator_; + return freeListAllocator_[type]; + } + + inline FreeListAllocator &GetOldSpaceAllocator() + { + return freeListAllocator_[OLD_SPACE]; } BumpPointerAllocator &GetNewSpaceAllocator() @@ -58,9 +63,9 @@ public: return newSpaceAllocator_; } - FreeListAllocator &GetNonMovableSpaceAllocator() + inline FreeListAllocator &GetNonMovableSpaceAllocator() { - return nonMovableAllocator_; + return freeListAllocator_[NON_MOVABLE]; } const BumpPointerAllocator &GetSnapShotSpaceAllocator() const @@ -68,18 +73,16 @@ public: return snapshotSpaceAllocator_; } - FreeListAllocator &GetMachineCodeSpaceAllocator() + inline FreeListAllocator &GetMachineCodeSpaceAllocator() { - return machineCodeSpaceAllocator_; + return freeListAllocator_[MACHINE_CODE_SPACE]; } private: Heap *heap_{nullptr}; BumpPointerAllocator newSpaceAllocator_; - FreeListAllocator nonMovableAllocator_; - FreeListAllocator oldSpaceAllocator_; + std::array freeListAllocator_; BumpPointerAllocator snapshotSpaceAllocator_; - FreeListAllocator machineCodeSpaceAllocator_; }; } // namespace panda::ecmascript diff --git a/ecmascript/mem/free_object_kind.cpp b/ecmascript/mem/free_object_kind.cpp index 951871f252..94829d653a 100644 --- a/ecmascript/mem/free_object_kind.cpp +++ b/ecmascript/mem/free_object_kind.cpp @@ -31,6 +31,9 @@ void FreeObjectKind::Rebuild() { freeObject_ = nullptr; available_ = 0; + isAdded_ = false; + next_ = nullptr; + prev_ = nullptr; } FreeObject *FreeObjectKind::SearchSmallFreeObject(size_t size) diff --git a/ecmascript/mem/free_object_kind.h b/ecmascript/mem/free_object_kind.h index 869689c5fb..057968a16d 100644 --- a/ecmascript/mem/free_object_kind.h +++ b/ecmascript/mem/free_object_kind.h @@ -27,9 +27,9 @@ class FreeObject; class FreeObjectKind { public: - FreeObjectKind(KindType type, uintptr_t begin, size_t size) : kindType_(type) + FreeObjectKind(KindType type) : kindType_(type) { - Free(begin, size); + Rebuild(); } ~FreeObjectKind() = default; @@ -60,6 +60,7 @@ private: FreeObjectKind *prev_ = nullptr; KindType kindType_ = INVALID_KIND_TYPE; size_t available_ = 0; + bool isAdded_ = false; FreeObject *freeObject_ = nullptr; friend class FreeObjectList; diff --git a/ecmascript/mem/free_object_list.cpp b/ecmascript/mem/free_object_list.cpp index 43e220f78e..e25e2880a7 100644 --- a/ecmascript/mem/free_object_list.cpp +++ b/ecmascript/mem/free_object_list.cpp @@ -20,17 +20,16 @@ #include "ecmascript/mem/mem.h" namespace panda::ecmascript { -FreeObjectList::FreeObjectList() +FreeObjectList::FreeObjectList() : kinds_(new FreeObjectKind *[NUMBER_OF_KINDS](), NUMBER_OF_KINDS) { - kinds_ = Span(new FreeObjectKind *[NUMBER_OF_KINDS](), NUMBER_OF_KINDS); + for (int i = 0; i < NUMBER_OF_KINDS; i++) { + kinds_[i] = nullptr; + } noneEmptyKindBitMap_ = 0; } FreeObjectList::~FreeObjectList() { - for (auto it : kinds_) { - delete it; - } delete[] kinds_.data(); noneEmptyKindBitMap_ = 0; } @@ -49,33 +48,39 @@ FreeObject *FreeObjectList::Allocator(size_t size) KindType lastType = type - 1; for (type = CalcNextNoneEmptyIndex(type); type > lastType && type < NUMBER_OF_KINDS; - type = CalcNextNoneEmptyIndex(type + 1)) { + type = CalcNextNoneEmptyIndex(type + 1)) { lastType = type; - FreeObjectKind *top = kinds_[type]; - if (top == nullptr || top->Available() < size) { - continue; - } - FreeObject *current = nullptr; - if (type <= SMALL_KIND_MAX_INDEX) { - current = top->SearchSmallFreeObject(size); - } else { - current = top->SearchLargeFreeObject(size); - } - if (top->Empty()) { - RemoveKind(top); - } - if (current != nullptr) { - size_t currentSize = current->Available(); - available_ -= currentSize; - if (currentSize >= size) { - return current; + FreeObjectKind *current = kinds_[type]; + while (current != nullptr) { + if (current->Available() < size) { + current = current->next_; + continue; } + FreeObjectKind *next = nullptr; + FreeObject *object = nullptr; + if (type <= SMALL_KIND_MAX_INDEX) { + object = current->SearchSmallFreeObject(size); + } else { + next = current->next_; + object = current->SearchLargeFreeObject(size); + } + if (current->Empty()) { + RemoveKind(current); + } + if (object != nullptr) { + size_t objectSize = object->Available(); + available_ -= objectSize; + if (objectSize >= size) { + return object; + } + } + current = next; } } return nullptr; } -void FreeObjectList::Free(uintptr_t start, size_t size) +void FreeObjectList::Free(uintptr_t start, size_t size, bool isAdd) { if (start == 0 || size == 0) { return; @@ -86,26 +91,28 @@ void FreeObjectList::Free(uintptr_t start, size_t size) return; } - auto kind = kinds_[type]; + Region *region = Region::ObjectAddressToRange(reinterpret_cast(start)); + auto kind = region->GetFreeObjectKind(type); if (kind == nullptr) { - kind = new FreeObjectKind(type, start, size); - if (!AddKind(kind)) { - delete kind; - return; + LOG_ECMA(FATAL) << "The kind of region is nullptr"; + return; + } + kind->Free(start, size); + + if (isAdd) { + if (kind->isAdded_) { + available_ += size; + } else { + AddKind(kind); } - } else { - kind->Free(start, size); } - available_ += size; } void FreeObjectList::Rebuild() { - for (auto kind : kinds_) { - if (kind != nullptr) { - kind->Rebuild(); - RemoveKind(kind); - } + EnumerateKinds([](FreeObjectKind *kind) { kind->Rebuild(); }); + for (int i = 0; i < NUMBER_OF_KINDS; i++) { + kinds_[i] = nullptr; } available_ = 0; noneEmptyKindBitMap_ = 0; @@ -118,20 +125,22 @@ size_t FreeObjectList::GetFreeObjectSize() const bool FreeObjectList::AddKind(FreeObjectKind *kind) { - if (kind == nullptr || kind->Empty()) { + if (kind == nullptr || kind->Empty() || kind->isAdded_) { return false; } KindType type = kind->kindType_; FreeObjectKind *top = kinds_[type]; if (kind == top) { - return true; + return false; } if (top != nullptr) { top->prev_ = kind; } + kind->isAdded_ = true; kind->next_ = top; kinds_[type] = kind; SetNoneEmptyBit(type); + available_ += kind->Available(); return true; } @@ -151,11 +160,30 @@ void FreeObjectList::RemoveKind(FreeObjectKind *kind) if (kind->next_ != nullptr) { kind->next_->prev_ = kind->prev_; } - kind->prev_ = nullptr; - kind->next_ = nullptr; if (kinds_[type] == nullptr) { ClearNoneEmptyBit(type); } - delete kind; + available_ -= kind->Available(); + kind->Rebuild(); +} + +template +void FreeObjectList::EnumerateKinds(const Callback &cb) const +{ + for (KindType i = 0; i < NUMBER_OF_KINDS; i++) { + EnumerateKinds(i, cb); + } +} + +template +void FreeObjectList::EnumerateKinds(KindType type, const Callback &cb) const +{ + FreeObjectKind *current = kinds_[type]; + while (current != nullptr) { + // maybe reset + FreeObjectKind *next = current->next_; + cb(current); + current = next; + } } } // namespace panda::ecmascript diff --git a/ecmascript/mem/free_object_list.h b/ecmascript/mem/free_object_list.h index c7db11126e..553dd5d4c4 100644 --- a/ecmascript/mem/free_object_list.h +++ b/ecmascript/mem/free_object_list.h @@ -29,15 +29,30 @@ public: FreeObject *Allocator(size_t size); - void Free(uintptr_t start, size_t size); + void Free(uintptr_t start, size_t size, bool isAdd = true); void Rebuild(); + bool AddKind(FreeObjectKind *kind); + + void RemoveKind(FreeObjectKind *kind); + + template + void EnumerateKinds(const Callback &cb) const; + + template + void EnumerateKinds(KindType type, const Callback &cb) const; + NO_COPY_SEMANTIC(FreeObjectList); NO_MOVE_SEMANTIC(FreeObjectList); size_t GetFreeObjectSize() const; + static int NumberOfKinds() + { + return NUMBER_OF_KINDS; + } + private: static constexpr int NUMBER_OF_KINDS = 39; static constexpr size_t MIN_SIZE = 16; @@ -58,9 +73,6 @@ private: inline void ClearNoneEmptyBit(KindType type); inline size_t CalcNextNoneEmptyIndex(KindType start); - bool AddKind(FreeObjectKind *kind); - void RemoveKind(FreeObjectKind *kind); - size_t available_ = 0; uint64_t noneEmptyKindBitMap_; Span kinds_ {}; diff --git a/ecmascript/mem/heap.cpp b/ecmascript/mem/heap.cpp index 9294b26735..bfc7d90674 100644 --- a/ecmascript/mem/heap.cpp +++ b/ecmascript/mem/heap.cpp @@ -20,6 +20,7 @@ #include "ecmascript/ecma_vm.h" #include "ecmascript/mem/assert_scope-inl.h" #include "ecmascript/mem/compress_collector.h" +#include "ecmascript/mem/concurrent_sweeper.h" #include "ecmascript/mem/ecma_heap_manager.h" #include "ecmascript/mem/mark_stack.h" #include "ecmascript/mem/mem_controller.h" @@ -63,12 +64,15 @@ void Heap::Initialize() pool_ = new ThreadPool(numThread); semiSpaceCollector_ = new SemiSpaceCollector(this, true); compressCollector_ = new CompressCollector(this, true); + oldSpaceCollector_ = new OldSpaceCollector(this, true); } else { pool_ = new ThreadPool(1); semiSpaceCollector_ = new SemiSpaceCollector(this, false); compressCollector_ = new CompressCollector(this, false); + oldSpaceCollector_ = new OldSpaceCollector(this, false); } - oldSpaceCollector_ = new OldSpaceCollector(this); + bool concurrentSweep = ecmaVm_->GetOptions().IsEnableConcurrentSweepGc(); + sweeper_ = new ConcurrentSweeper(this, concurrentSweep); } void Heap::FlipNewSpace() @@ -87,6 +91,7 @@ void Heap::FlipCompressSpace() void Heap::Destroy() { pool_->WaitTaskFinish(); + sweeper_->EnsureAllTaskFinish(); toSpace_->Destroy(); delete toSpace_; toSpace_ = nullptr; @@ -156,18 +161,18 @@ void Heap::CollectGarbage(TriggerGCType gcType) } break; case TriggerGCType::OLD_GC: - if (oldSpace_->GetHeapObjectSize() < OLD_SPACE_LIMIT_BEGIN) { - oldSpaceCollector_->RunPhases(); - } else { - compressCollector_->RunPhases(); + oldSpaceCollector_->RunPhases(); + if (!sweeper_->IsConcurrentSweepEnabled()) { + RecomputeLimits(); } - RecomputeLimits(); break; case TriggerGCType::NON_MOVE_GC: case TriggerGCType::HUGE_GC: case TriggerGCType::MACHINE_CODE_GC: oldSpaceCollector_->RunPhases(); - RecomputeLimits(); + if (!sweeper_->IsConcurrentSweepEnabled()) { + RecomputeLimits(); + } break; case TriggerGCType::COMPRESS_FULL_GC: compressCollector_->RunPhases(); diff --git a/ecmascript/mem/heap.h b/ecmascript/mem/heap.h index bc112f2f87..a15c9cfe0a 100644 --- a/ecmascript/mem/heap.h +++ b/ecmascript/mem/heap.h @@ -31,6 +31,7 @@ class FreeListAllocator; class RegionFactory; class HeapTracker; class MemController; +class ConcurrentSweeper; class Heap { public: @@ -118,6 +119,11 @@ public: return compressCollector_; } + ConcurrentSweeper *GetSweeper() const + { + return sweeper_; + } + EcmaVM *GetEcmaVM() const { return ecmaVm_; @@ -276,6 +282,7 @@ private: SemiSpaceCollector *semiSpaceCollector_ {nullptr}; OldSpaceCollector *oldSpaceCollector_ {nullptr}; CompressCollector *compressCollector_ {nullptr}; + ConcurrentSweeper *sweeper_ {nullptr}; EcmaHeapManager *heapManager_ {nullptr}; RegionFactory *regionFactory_ {nullptr}; HeapTracker *tracker_ {nullptr}; diff --git a/ecmascript/mem/old_space_collector-inl.h b/ecmascript/mem/old_space_collector-inl.h index a8f88de559..f5e4a958de 100644 --- a/ecmascript/mem/old_space_collector-inl.h +++ b/ecmascript/mem/old_space_collector-inl.h @@ -24,14 +24,13 @@ #include "ecmascript/js_hclass-inl.h" namespace panda::ecmascript { -void OldSpaceCollector::MarkObject(TaggedObject *object) +void OldSpaceCollector::MarkObject(uint64_t threadId, TaggedObject *object) { Region *objectRegion = Region::ObjectAddressToRange(object); auto markBitmap = objectRegion->GetMarkBitmap(); - if (!markBitmap->Test(object)) { - markBitmap->Set(object); - markStack_.PushBack(object); + if (!markBitmap->AtomicTestAndSet(object)) { + workList_->Push(threadId, object); } } @@ -42,14 +41,6 @@ void OldSpaceCollector::RecordWeakReference(JSTaggedType *ref) weakProcessQueue_.PushBack(ref); } } - -void OldSpaceCollector::FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, - uintptr_t freeEnd) -{ - allocator.Free(freeStart, freeEnd); - freeSize_ += freeEnd - freeStart; - heap_->ClearSlotsRange(current, freeStart, freeEnd); -} } // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_SEMI_SAPACE_COLLECTOR_INL_H diff --git a/ecmascript/mem/old_space_collector.cpp b/ecmascript/mem/old_space_collector.cpp index 3572760030..a2a693a1f5 100644 --- a/ecmascript/mem/old_space_collector.cpp +++ b/ecmascript/mem/old_space_collector.cpp @@ -15,6 +15,8 @@ #include "ecmascript/mem/old_space_collector-inl.h" +#include "sys/time.h" + #include "ecmascript/ecma_vm.h" #include "ecmascript/mem/clock_scope.h" #include "ecmascript/mem/ecma_heap_manager.h" @@ -27,7 +29,11 @@ #include "ecmascript/vmstat/runtime_stat.h" namespace panda::ecmascript { -OldSpaceCollector::OldSpaceCollector(Heap *heap) : heap_(heap), rootManager_(heap->GetEcmaVM()) {} +OldSpaceCollector::OldSpaceCollector(Heap *heap, bool parallelGc) : + heap_(heap), rootManager_(heap->GetEcmaVM()), paralledGC_(parallelGc) +{ + workList_ = new OldGCWorker(heap_, heap_->GetThreadPool()->GetThreadNum()); +} void OldSpaceCollector::RunPhases() { @@ -45,12 +51,9 @@ void OldSpaceCollector::RunPhases() void OldSpaceCollector::InitializePhase() { + heap_->GetThreadPool()->WaitTaskFinish(); markStack_.BeginMarking(heap_, heap_->GetMarkStack()); weakProcessQueue_.BeginMarking(heap_, heap_->GetProcessQueue()); - auto heapManager = heap_->GetHeapManager(); - oldSpaceAllocator_.Swap(heapManager->GetOldSpaceAllocator()); - nonMovableAllocator_.Swap(heapManager->GetNonMovableSpaceAllocator()); - machineCodeSpaceAllocator_.Swap(heapManager->GetMachineCodeSpaceAllocator()); heap_->EnumerateRegions([](Region *current) { // ensure mark bitmap auto bitmap = current->GetMarkBitmap(); @@ -60,6 +63,7 @@ void OldSpaceCollector::InitializePhase() bitmap->ClearAllBits(); } }); + workList_->Initialize(); freeSize_ = 0; hugeSpaceFreeSize_ = 0; oldSpaceCommitSize_ = heap_->GetOldSpace()->GetCommittedSize(); @@ -69,12 +73,9 @@ void OldSpaceCollector::InitializePhase() void OldSpaceCollector::FinishPhase() { // swap - markStack_.FinishMarking(heap_->GetMarkStack()); weakProcessQueue_.FinishMarking(heap_->GetProcessQueue()); - auto heapManager = heap_->GetHeapManager(); - heapManager->GetOldSpaceAllocator().Swap(oldSpaceAllocator_); - heapManager->GetNonMovableSpaceAllocator().Swap(nonMovableAllocator_); - heapManager->GetMachineCodeSpaceAllocator().Swap(machineCodeSpaceAllocator_); + size_t aliveSize = 0; + workList_->Finish(aliveSize); } void OldSpaceCollector::MarkingPhase() @@ -83,35 +84,38 @@ void OldSpaceCollector::MarkingPhase() RootVisitor gcMarkYoung = [this]([[maybe_unused]] Root type, ObjectSlot slot) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsHeapObject()) { - MarkObject(value.GetTaggedObject()); + MarkObject(0, value.GetTaggedObject()); } }; RootRangeVisitor gcMarkRangeYoung = [this]([[maybe_unused]] Root type, ObjectSlot start, ObjectSlot end) { for (ObjectSlot slot = start; slot < end; slot++) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsHeapObject()) { - MarkObject(value.GetTaggedObject()); + MarkObject(0, value.GetTaggedObject()); } } }; rootManager_.VisitVMRoots(gcMarkYoung, gcMarkRangeYoung); - ProcessMarkStack(); + ProcessMarkStack(0); + if (paralledGC_) { + heap_->GetThreadPool()->WaitTaskFinish(); + } } -void OldSpaceCollector::ProcessMarkStack() +void OldSpaceCollector::ProcessMarkStack(uint64_t threadId) { while (true) { - auto obj = markStack_.PopBack(); - if (UNLIKELY(obj == nullptr)) { + TaggedObject *obj = nullptr; + if (!workList_->Pop(threadId, &obj)) { break; } auto jsHclass = obj->GetClass(); // mark dynClass - MarkObject(jsHclass); + MarkObject(threadId, jsHclass); rootManager_.MarkObjectBody( - obj, jsHclass, [this]([[maybe_unused]] TaggedObject *root, ObjectSlot start, ObjectSlot end) { + obj, jsHclass, [this, &threadId]([[maybe_unused]] TaggedObject *root, ObjectSlot start, ObjectSlot end) { for (ObjectSlot slot = start; slot < end; slot++) { JSTaggedValue value(slot.GetTaggedType()); if (value.IsWeak()) { @@ -119,59 +123,13 @@ void OldSpaceCollector::ProcessMarkStack() continue; } if (value.IsHeapObject()) { - MarkObject(value.GetTaggedObject()); + MarkObject(threadId, value.GetTaggedObject()); } } }); } } -void OldSpaceCollector::SweepSpace(Space *space, FreeListAllocator &allocator) -{ - allocator.RebuildFreeList(); - space->EnumerateRegions([this, &allocator](Region *current) { - auto markBitmap = current->GetMarkBitmap(); - ASSERT(markBitmap != nullptr); - uintptr_t freeStart = current->GetBegin(); - markBitmap->IterateOverMarkedChunks([this, ¤t, &freeStart, &allocator](void *mem) { - ASSERT(current->InRange(ToUintPtr(mem))); - auto header = reinterpret_cast(mem); - auto klass = header->GetClass(); - JSType jsType = klass->GetObjectType(); - auto size = klass->SizeFromJSHClass(jsType, header); - size = AlignUp(size, static_cast(MemAlignment::MEM_ALIGN_OBJECT)); - - uintptr_t freeEnd = ToUintPtr(mem); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - freeStart = freeEnd + size; - }); - uintptr_t freeEnd = current->GetEnd(); - if (freeStart != freeEnd) { - FreeLiveRange(allocator, current, freeStart, freeEnd); - } - }); -} - -void OldSpaceCollector::SweepSpace(HugeObjectSpace *space) -{ - Region *currentRegion = space->GetRegionList().GetFirst(); - - while (currentRegion != nullptr) { - Region *next = currentRegion->GetNext(); - auto markBitmap = currentRegion->GetMarkBitmap(); - bool isMarked = false; - markBitmap->IterateOverMarkedChunks([&isMarked]([[maybe_unused]] void *mem) { isMarked = true; }); - if (!isMarked) { - space->GetRegionList().RemoveNode(currentRegion); - hugeSpaceFreeSize_ += currentRegion->GetCapacity(); - space->ClearAndFreeRegion(currentRegion); - } - currentRegion = next; - } -} - void OldSpaceCollector::SweepPhases() { trace::ScopedTrace scoped_trace("OldSpaceCollector::SweepPhases"); @@ -209,9 +167,6 @@ void OldSpaceCollector::SweepPhases() heap_->GetEcmaVM()->GetJSThread()->IterateWeakEcmaGlobalStorage(gcUpdateWeak); heap_->GetEcmaVM()->ProcessReferences(gcUpdateWeak); - SweepSpace(const_cast(heap_->GetOldSpace()), oldSpaceAllocator_); - SweepSpace(const_cast(heap_->GetNonMovableSpace()), nonMovableAllocator_); - SweepSpace(const_cast(heap_->GetHugeObjectSpace())); - SweepSpace(const_cast(heap_->GetMachineCodeSpace()), machineCodeSpaceAllocator_); + heap_->GetSweeper()->SweepPhases(); } } // namespace panda::ecmascript diff --git a/ecmascript/mem/old_space_collector.h b/ecmascript/mem/old_space_collector.h index 64940351b6..cab6403afc 100644 --- a/ecmascript/mem/old_space_collector.h +++ b/ecmascript/mem/old_space_collector.h @@ -21,6 +21,7 @@ #include "ecmascript/mem/allocator.h" #include "ecmascript/mem/mark_stack-inl.h" #include "ecmascript/mem/mark_word.h" +#include "ecmascript/mem/semi_space_worker.h" #include "ecmascript/mem/slots.h" #include "ecmascript/mem/heap_roots.h" #include "ecmascript/mem/remembered_set.h" @@ -33,7 +34,7 @@ class JSHClass; class OldSpaceCollector : public GarbageCollector { public: - explicit OldSpaceCollector(Heap *heap); + explicit OldSpaceCollector(Heap *heap, bool parallelGc); ~OldSpaceCollector() override = default; NO_COPY_SEMANTIC(OldSpaceCollector); NO_MOVE_SEMANTIC(OldSpaceCollector); @@ -50,26 +51,24 @@ private: void SweepPhases(); void FinishPhase(); - void ProcessMarkStack(); + void ProcessMarkStack(uint64_t threadId); void MarkObjectBody(TaggedObject *object, JSHClass *klass, const EcmaObjectRangeVisitor &visitor); - inline void MarkObject(TaggedObject *object); - inline void FreeLiveRange(FreeListAllocator &allocator, Region *current, uintptr_t freeStart, uintptr_t freeEnd); + inline void MarkObject(uint64_t threadId, TaggedObject *object); inline void RecordWeakReference(JSTaggedType *ref); - void SweepSpace(Space *space, FreeListAllocator &allocator); - void SweepSpace(HugeObjectSpace *space); // Only sweep huge space. Heap *heap_; HeapRootManager rootManager_; MarkStack markStack_; + bool paralledGC_{false}; + OldGCWorker *workList_{nullptr}; ProcessQueue weakProcessQueue_; - FreeListAllocator oldSpaceAllocator_ {}; - FreeListAllocator nonMovableAllocator_ {}; - FreeListAllocator machineCodeSpaceAllocator_ {}; size_t freeSize_{0}; size_t hugeSpaceFreeSize_ = 0; size_t oldSpaceCommitSize_ = 0; size_t nonMoveSpaceCommitSize_ = 0; + + friend class OldGCWorker; }; } // namespace ecmascript } // namespace panda diff --git a/ecmascript/mem/region.h b/ecmascript/mem/region.h index c80d1a9c01..fb6d71324c 100644 --- a/ecmascript/mem/region.h +++ b/ecmascript/mem/region.h @@ -16,6 +16,7 @@ #ifndef ECMASCRIPT_MEM_REGION_H #define ECMASCRIPT_MEM_REGION_H +#include "ecmascript/mem/free_object_list.h" #include "ecmascript/mem/mem.h" #include "mem/gc/bitmap.h" @@ -41,9 +42,11 @@ enum RegionFlags { // NOLINTNEXTLINE(hicpp-signed-bitwise) IS_IN_OLD_GENERATION = 1 << 6, // NOLINTNEXTLINE(hicpp-signed-bitwise) + IS_IN_NON_MOVABLE_GENERATION = 1 << 7, + // NOLINTNEXTLINE(hicpp-signed-bitwise) IS_IN_YOUNG_OR_OLD_GENERATION = IS_IN_YOUNG_GENERATION | IS_IN_OLD_GENERATION, // NOLINTNEXTLINE(hicpp-signed-bitwise) - IS_INVALID = 1 << 7, + IS_INVALID = 1 << 8, }; class Region { @@ -220,6 +223,36 @@ public: return res; } + void InitializeKind() + { + kinds_ = Span(new FreeObjectKind *[FreeObjectList::NumberOfKinds()](), + FreeObjectList::NumberOfKinds()); + for (int i = 0; i < FreeObjectList::NumberOfKinds(); i++) { + kinds_[i] = new FreeObjectKind(i); + } + } + + void DestoryKind() + { + for (auto kind : kinds_) { + delete kind; + } + delete[] kinds_.data(); + } + + FreeObjectKind *GetFreeObjectKind(KindType type) + { + return kinds_[type]; + } + + template + void EnumerateKinds(Callback cb) + { + for (auto kind : kinds_) { + cb(kind); + } + } + private: Space *space_; uintptr_t flags_; // Memory alignment, only low 32bits are used now @@ -232,6 +265,7 @@ private: RangeBitmap *markBitmap_{nullptr}; RememberedSet *crossRegionSet_{nullptr}; RememberedSet *oldToNewSet_{nullptr}; + Span kinds_; friend class SnapShot; }; } // namespace ecmascript diff --git a/ecmascript/mem/semi_space_collector.cpp b/ecmascript/mem/semi_space_collector.cpp index ef6975066f..0cc31fd8f1 100644 --- a/ecmascript/mem/semi_space_collector.cpp +++ b/ecmascript/mem/semi_space_collector.cpp @@ -59,7 +59,7 @@ void SemiSpaceCollector::RunPhases() void SemiSpaceCollector::InitializePhase() { heap_->GetThreadPool()->WaitTaskFinish(); - gcTime_++; + heap_->GetSweeper()->EnsureAllTaskFinish(); auto fromSpace = heap_->GetFromSpace(); if (fromSpace->GetCommittedSize() == 0) { heap_->InitializeFromSpace(); diff --git a/ecmascript/mem/semi_space_collector.h b/ecmascript/mem/semi_space_collector.h index 6e5a31f624..3a76149e5c 100644 --- a/ecmascript/mem/semi_space_collector.h +++ b/ecmascript/mem/semi_space_collector.h @@ -91,7 +91,6 @@ private: size_t semiCopiedSize_{0}; size_t commitSize_ = 0; uintptr_t ageMark_{0}; - size_t gcTime_{0}; friend class TlabAllocator; friend class SemiSpaceWorker; friend class SemiSpaceMarker; diff --git a/ecmascript/mem/semi_space_worker.cpp b/ecmascript/mem/semi_space_worker.cpp index dbaa62b623..0df831f442 100644 --- a/ecmascript/mem/semi_space_worker.cpp +++ b/ecmascript/mem/semi_space_worker.cpp @@ -19,6 +19,7 @@ #include "ecmascript/mem/compress_collector.h" #include "ecmascript/mem/heap.h" #include "ecmascript/mem/mark_stack.h" +#include "ecmascript/mem/old_space_collector.h" #include "ecmascript/mem/region_factory.h" #include "ecmascript/mem/tlab_allocator-inl.h" @@ -197,4 +198,32 @@ void CompressGCWorker::Initialize() holder.aliveSize_ = 0; } } + +void OldGCWorker::Initialize() +{ + spaceTop_ = markSpace_; + markSpaceEnd_ = markSpace_ + SPACE_SIZE; + for (uint32_t i = 0; i < threadNum_; i++) { + WorkNodeHolder &holder = workList_[i]; + holder.pushNode_ = AllocalWorkNode(); + holder.popNode_ = AllocalWorkNode(); + holder.weakQueue_ = new ProcessQueue(); + holder.weakQueue_->BeginMarking(heap_, continuousQueue_[i]); + } +} + +void OldGCWorker::PushWorkNodeToGlobal(uint32_t threadId) +{ + WorkNode *&pushNode = workList_[threadId].pushNode_; + if (!pushNode->IsEmpty()) { + globalWork_.Push(pushNode); + pushNode = AllocalWorkNode(); + + auto pool = heap_->GetThreadPool(); + if (pool->GetTaskCount() < pool->GetThreadNum() - 1) { + pool->Submit(std::bind(&OldSpaceCollector::ProcessMarkStack, heap_->GetOldSpaceCollector(), + std::placeholders::_1)); + } + } +} } // namespace panda::ecmascript diff --git a/ecmascript/mem/semi_space_worker.h b/ecmascript/mem/semi_space_worker.h index 2572c475e1..0a88f31f0e 100644 --- a/ecmascript/mem/semi_space_worker.h +++ b/ecmascript/mem/semi_space_worker.h @@ -233,6 +233,19 @@ public: NO_COPY_SEMANTIC(CompressGCWorker); NO_MOVE_SEMANTIC(CompressGCWorker); }; -} // namespace panda::ecmascript +class OldGCWorker : public Worker { +public: + OldGCWorker() = delete; + OldGCWorker(Heap *heap, uint32_t threadNum) : Worker(heap, threadNum) {} + + ~OldGCWorker() override = default; + + void PushWorkNodeToGlobal(uint32_t threadId) override; + void Initialize() override; + + NO_COPY_SEMANTIC(OldGCWorker); + NO_MOVE_SEMANTIC(OldGCWorker); +}; +} // namespace panda::ecmascript #endif // ECMASCRIPT_MEM_SEMI_SPACE_WORKER_H diff --git a/ecmascript/mem/space.cpp b/ecmascript/mem/space.cpp index cb83b9416c..452b358ac6 100644 --- a/ecmascript/mem/space.cpp +++ b/ecmascript/mem/space.cpp @@ -19,6 +19,7 @@ #include "ecmascript/mem/region_factory.h" #include "ecmascript/mem/remembered_set.h" #include "ecmascript/mem/space-inl.h" +#include "ecmascript/mem/space.h" #include "libpandabase/utils/logger.h" namespace panda::ecmascript { @@ -37,11 +38,16 @@ void Space::Initialize() } else if (spaceType_ == MemSpaceType::SNAPSHOT_SPACE) { region->SetFlag(RegionFlags::IS_IN_SNAPSHOT_GENERATION); } else if (spaceType_ == MemSpaceType::OLD_SPACE) { + region->InitializeKind(); region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION); } else if (spaceType_ == MemSpaceType::MACHINE_CODE_SPACE) { + region->InitializeKind(); region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION); int res = region->SetCodeExecutableAndReadable(); LOG_ECMA_MEM(DEBUG) << "Initialize SetCodeExecutableAndReadable" << res; + } else if (spaceType_ == MemSpaceType::NON_MOVABLE) { + region->InitializeKind(); + region->SetFlag(RegionFlags::IS_IN_NON_MOVABLE_GENERATION); } AddRegion(region); @@ -75,6 +81,11 @@ void Space::ClearAndFreeRegion(Region *region) delete rememberedSet; } DecrementCommitted(region->GetCapacity()); + if (spaceType_ == MemSpaceType::OLD_SPACE || + spaceType_ == MemSpaceType::NON_MOVABLE || + spaceType_ == MemSpaceType::MACHINE_CODE_SPACE) { + region->DestoryKind(); + } const_cast(heap_->GetRegionFactory())->FreeRegion(region); } @@ -177,6 +188,7 @@ bool OldSpace::Expand() Region *region = const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE); region->SetFlag(RegionFlags::IS_IN_OLD_GENERATION); + region->InitializeKind(); AddRegion(region); return true; } @@ -231,8 +243,7 @@ size_t OldSpace::GetHeapObjectSize() const { size_t result; size_t availableSize = GetHeap()->GetHeapManager()->GetOldSpaceAllocator().GetAvailableSize(); - size_t regionSize = GetRegionList().GetLength() * DEFAULT_REGION_SIZE; - result = regionSize - availableSize; + result = GetCommittedSize() - availableSize; result += GetHeap()->GetHugeObjectSpace()->GetHeapObjectSize(); return result; } @@ -250,6 +261,8 @@ bool NonMovableSpace::Expand() } Region *region = const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE); + region->SetFlag(IS_IN_NON_MOVABLE_GENERATION); + region->InitializeKind(); AddRegion(region); return true; } @@ -382,6 +395,12 @@ uintptr_t HugeObjectSpace::Allocate(size_t objectSize) return region->GetBegin(); } +void HugeObjectSpace::Free(Region *region) +{ + GetRegionList().RemoveNode(region); + ClearAndFreeRegion(region); +} + bool HugeObjectSpace::ContainObject(TaggedObject *object) const { auto region = GetRegionList().GetFirst(); @@ -401,12 +420,7 @@ bool HugeObjectSpace::IsLive(TaggedObject *object) const size_t HugeObjectSpace::GetHeapObjectSize() const { - size_t result = 0; - EnumerateRegions([&result](Region *current) { - auto obj = reinterpret_cast(current->GetBegin()); - result += obj->GetObjectSize(); - }); - return result; + return GetCommittedSize(); } void HugeObjectSpace::IterateOverObjects(const std::function &objectVisitor) const @@ -430,6 +444,7 @@ bool MachineCodeSpace::Expand() } Region *region = const_cast(GetHeap()->GetRegionFactory())->AllocateAlignedRegion(this, DEFAULT_REGION_SIZE); + region->InitializeKind(); AddRegion(region); int res = region->SetCodeExecutableAndReadable(); LOG_ECMA_MEM(DEBUG) << "MachineCodeSpace::Expand() SetCodeExecutableAndReadable" << res; diff --git a/ecmascript/mem/space.h b/ecmascript/mem/space.h index 7e6012f538..25f353e253 100644 --- a/ecmascript/mem/space.h +++ b/ecmascript/mem/space.h @@ -29,13 +29,16 @@ class Heap; class Program; enum MemSpaceType { - SEMI_SPACE, - OLD_SPACE, + OLD_SPACE = 0, NON_MOVABLE, + MACHINE_CODE_SPACE, HUGE_OBJECT_SPACE, + SEMI_SPACE, SNAPSHOT_SPACE, - MACHINE_CODE_SPACE, - SPACE_TYPE_LAST // Count of different types + COMPRESS_SPACE, + SPACE_TYPE_LAST, // Count of different types + + FREE_LIST_NUM = MACHINE_CODE_SPACE - OLD_SPACE + 1, }; enum TriggerGCType { @@ -238,6 +241,7 @@ public: NO_COPY_SEMANTIC(HugeObjectSpace); NO_MOVE_SEMANTIC(HugeObjectSpace); uintptr_t Allocate(size_t objectSize); + void Free(Region *region); size_t GetHeapObjectSize() const; bool ContainObject(TaggedObject *object) const; bool IsLive(TaggedObject *object) const; diff --git a/ecmascript/mem/tlab_allocator-inl.h b/ecmascript/mem/tlab_allocator-inl.h index 3a36d26b60..d269822c4d 100644 --- a/ecmascript/mem/tlab_allocator-inl.h +++ b/ecmascript/mem/tlab_allocator-inl.h @@ -24,7 +24,7 @@ #include "ecmascript/mem/tlab_allocator.h" namespace panda::ecmascript { -static constexpr size_t SEMIGC_YOUNG_BUFFER_SIZE = 32 * 1024; +static constexpr size_t SEMIGC_YOUNG_BUFFER_SIZE = 31 * 1024; static constexpr size_t OLD_BUFFER_SIZE = 255 * 1024; TlabAllocator::TlabAllocator(Heap *heap, TriggerGCType gcType) diff --git a/ecmascript/object_factory.cpp b/ecmascript/object_factory.cpp index 0e4ed0a300..4bcc0fa3ac 100644 --- a/ecmascript/object_factory.cpp +++ b/ecmascript/object_factory.cpp @@ -794,10 +794,12 @@ FreeObject *ObjectFactory::FillFreeObject(uintptr_t address, size_t size, Remove if (size >= FreeObject::SIZE_OFFSET && size < FreeObject::SIZE) { object = reinterpret_cast(address); object->SetClass(freeObjectWithOneFieldClass_); + object->SetNext(nullptr); } else if (size >= FreeObject::SIZE) { object = reinterpret_cast(address); object->SetClass(freeObjectWithTwoFieldClass_); object->SetAvailable(size); + object->SetNext(nullptr); } else if (size == FreeObject::NEXT_OFFSET) { object = reinterpret_cast(address); object->SetClass(freeObjectWithNoneFieldClass_); diff --git a/ecmascript/platform/platform.cpp b/ecmascript/platform/platform.cpp new file mode 100644 index 0000000000..f589f3807e --- /dev/null +++ b/ecmascript/platform/platform.cpp @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/platform/platform.h" + +#include "sys/sysinfo.h" + +namespace panda::ecmascript { +void Platform::Initialize(int threadNum) +{ + os::memory::LockHolder lock(mutex_); + if (isInitialized_++ <= 0) { + runner_ = std::make_unique(TheMostSuitableThreadNum(threadNum)); + } +} + +void Platform::Destory() +{ + os::memory::LockHolder lock(mutex_); + if (--isInitialized_ <= 0) { + runner_->Terminate(); + } +} + +int Platform::TheMostSuitableThreadNum(int threadNum) const +{ + if (threadNum > 0) { + return std::min(threadNum, MAX_PLATFORM_THREAD_NUM); + } + int numOfCpuCore = get_nprocs() - 1; + return std::min(numOfCpuCore, MAX_PLATFORM_THREAD_NUM); +} +} // namespace panda::ecmascript diff --git a/ecmascript/platform/platform.h b/ecmascript/platform/platform.h new file mode 100644 index 0000000000..46411111fa --- /dev/null +++ b/ecmascript/platform/platform.h @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PANDA_ECMASCRIPT_PALTFORM_PLATFORM_H +#define PANDA_ECMASCRIPT_PALTFORM_PLATFORM_H + +#include + +#include "ecmascript/platform/runner.h" +#include "os/mutex.h" + +namespace panda::ecmascript { +class Platform { +public: + static Platform *GetCurrentPlatform() + { + static Platform platform; + return &platform; + } + + Platform() = default; + ~Platform() = default; + + NO_COPY_SEMANTIC(Platform); + NO_MOVE_SEMANTIC(Platform); + + void Initialize(int threadNum = DEFAULT_PLATFORM_THREAD_NUM); + void Destory(); + + void PostTask(std::unique_ptr task) const + { + ASSERT(isInitialized_ > 0); + runner_->PostTask(std::move(task)); + } + +private: + static constexpr uint32_t MAX_PLATFORM_THREAD_NUM = 7; + static constexpr uint32_t DEFAULT_PLATFORM_THREAD_NUM = 0; + + int TheMostSuitableThreadNum(int threadNum) const; + + std::unique_ptr runner_; + int isInitialized_ = 0; + os::memory::Mutex mutex_; +}; +} // namespace panda::ecmascript +#endif // PANDA_ECMASCRIPT_PALTFORM_PLATFORM_H diff --git a/ecmascript/platform/runner.cpp b/ecmascript/platform/runner.cpp new file mode 100644 index 0000000000..12d7dcfcda --- /dev/null +++ b/ecmascript/platform/runner.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/platform/runner.h" + +#include +#include + +#include "os/thread.h" + +namespace panda::ecmascript { +Runner::Runner(int threadNum) +{ + for (int i = 0; i < threadNum; i++) { + std::unique_ptr thread = std::make_unique(&Runner::Run, this); + os::thread::SetThreadName(thread->native_handle(), "GC_WorkerThread"); + threadPool_.emplace_back(std::move(thread)); + } +} + +void Runner::Terminate() +{ + taskQueue_.Terminate(); + int threadNum = threadPool_.size(); + for (int i = 0; i < threadNum; i++) { + threadPool_.at(i)->join(); + } + threadPool_.clear(); +} + +void Runner::Run() +{ + while (std::unique_ptr task = taskQueue_.PopTask()) { + task->Run(); + } +} +} // namespace panda::ecmascript diff --git a/ecmascript/platform/runner.h b/ecmascript/platform/runner.h new file mode 100644 index 0000000000..eea822ecf0 --- /dev/null +++ b/ecmascript/platform/runner.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PANDA_ECMASCRIPT_PLATFORM_RUNNER_H +#define PANDA_ECMASCRIPT_PLATFORM_RUNNER_H + +#include +#include +#include + +#include "ecmascript/platform/task_queue.h" + +namespace panda::ecmascript { +class Runner { +public: + explicit Runner(int threadNum); + ~Runner() = default; + + NO_COPY_SEMANTIC(Runner); + NO_MOVE_SEMANTIC(Runner); + + void PostTask(std::unique_ptr task) + { + taskQueue_.PostTask(std::move(task)); + } + + void Terminate(); + +private: + void Run(); + + std::vector> threadPool_ {}; + TaskQueue taskQueue_ {}; +}; +} // namespace panda::ecmascript +#endif // PANDA_ECMASCRIPT_PLATFORM_RUNNER_H diff --git a/ecmascript/platform/task.h b/ecmascript/platform/task.h new file mode 100644 index 0000000000..e2bcc7b5f2 --- /dev/null +++ b/ecmascript/platform/task.h @@ -0,0 +1,32 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PANDA_ECMASCRIPT_PLATFORM_TASK_H +#define PANDA_ECMASCRIPT_PLATFORM_TASK_H + +#include "macros.h" + +namespace panda::ecmascript { +class Task { +public: + Task() = default; + virtual ~Task() = default; + virtual bool Run() = 0; + + NO_COPY_SEMANTIC(Task); + NO_MOVE_SEMANTIC(Task); +}; +} // namespace panda::ecmascript +#endif // PANDA_ECMASCRIPT_PLATFORM_TASK_H diff --git a/ecmascript/platform/task_queue.cpp b/ecmascript/platform/task_queue.cpp new file mode 100644 index 0000000000..b90c205569 --- /dev/null +++ b/ecmascript/platform/task_queue.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/platform/task_queue.h" + +namespace panda::ecmascript { +void TaskQueue::PostTask(std::unique_ptr task) +{ + os::memory::LockHolder holder(mtx_); + ASSERT(!terminate_); + tasks_.push(std::move(task)); + cv_.Signal(); +} + +std::unique_ptr TaskQueue::PopTask() +{ + os::memory::LockHolder holder(mtx_); + while (true) { + if (!tasks_.empty()) { + std::unique_ptr task = std::move(tasks_.front()); + tasks_.pop(); + return task; + } + if (terminate_) { + cv_.SignalAll(); + return nullptr; + } + cv_.Wait(&mtx_); + } +} + +void TaskQueue::Terminate() +{ + os::memory::LockHolder holder(mtx_); + terminate_ = true; + cv_.SignalAll(); +} +} // namespace panda::ecmascript diff --git a/ecmascript/platform/task_queue.h b/ecmascript/platform/task_queue.h new file mode 100644 index 0000000000..121eb7cc51 --- /dev/null +++ b/ecmascript/platform/task_queue.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef PANDA_ECMASCRIPT_PLATFORM_TASK_QUEUE_H +#define PANDA_ECMASCRIPT_PLATFORM_TASK_QUEUE_H + +#include +#include +#include +#include + +#include "ecmascript/platform/task.h" +#include "os/mutex.h" + +namespace panda::ecmascript { +class TaskQueue { +public: + TaskQueue() = default; + ~TaskQueue() = default; + + NO_COPY_SEMANTIC(TaskQueue); + NO_MOVE_SEMANTIC(TaskQueue); + + void PostTask(std::unique_ptr task); + std::unique_ptr PopTask(); + + void Terminate(); + +private: + std::queue> tasks_; + + std::atomic_bool terminate_ = false; + os::memory::Mutex mtx_; + os::memory::ConditionVariable cv_; +}; +} // namespace panda::ecmascript +#endif // PANDA_ECMASCRIPT_PLATFORM_TASK_QUEUE_H diff --git a/ecmascript/tests/BUILD.gn b/ecmascript/tests/BUILD.gn index d87cbea2d3..61227b4cd8 100644 --- a/ecmascript/tests/BUILD.gn +++ b/ecmascript/tests/BUILD.gn @@ -660,6 +660,7 @@ host_unittest_action("GcTest") { sources = [ # test file "gc_test.cpp", + "concurrent_sweep_test.cpp", ] configs = [ diff --git a/ecmascript/tests/concurrent_sweep_test.cpp b/ecmascript/tests/concurrent_sweep_test.cpp new file mode 100644 index 0000000000..6759428f34 --- /dev/null +++ b/ecmascript/tests/concurrent_sweep_test.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/tests/test_helper.h" + +#include "ecmascript/ecma_vm.h" +#include "ecmascript/global_env.h" +#include "ecmascript/js_handle.h" + +using namespace panda::ecmascript; + +namespace panda::test { +class ConcurrentSweepTest : public testing::Test { +public: + static void SetUpTestCase() + { + GTEST_LOG_(INFO) << "SetUpTestCase"; + } + + static void TearDownTestCase() + { + GTEST_LOG_(INFO) << "TearDownCase"; + } + + void SetUp() override + { + TestHelper::CreateEcmaVMWithScope(instance, thread, scope); + } + + void TearDown() override + { + TestHelper::DestroyEcmaVMWithScope(instance, scope); + } + + PandaVM *instance {nullptr}; + EcmaHandleScope *scope {nullptr}; + JSThread *thread; +}; + +TEST_F(ConcurrentSweepTest, ConcurrentSweep) +{ + auto vm = EcmaVM::Cast(instance); + const uint8_t *utf8 = reinterpret_cast("test"); + JSHandle test1(thread, EcmaString::CreateFromUtf8(utf8, 4, vm, false)); + if (vm->IsInitialized()) { + vm->CollectGarbage(ecmascript::TriggerGCType::OLD_GC); + } + JSHandle test2(thread, EcmaString::CreateFromUtf8(utf8, 4, vm, false)); + ASSERT_EQ(test1->GetLength(), 4); + ASSERT_NE(test1.GetTaggedValue().GetHeapObject(), test2.GetTaggedValue().GetHeapObject()); +} +} // namespace panda::test -- Gitee