/* * Copyright (c) 2025 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ECMASCRIPT_BASE_GC_HELPER_H #define ECMASCRIPT_BASE_GC_HELPER_H #include "ecmascript/mem/barriers.h" #include "ecmascript/js_function.h" #include "ecmascript/js_generator_object.h" #include "ecmascript/mem/tagged_object.h" #include "ecmascript/tagged_array.h" namespace panda::ecmascript::base { class GCHelper { public: static inline void CopyCallTarget(const JSThread *thread, void *callTargetToRef) { if (!JSTaggedValue(static_cast(ToUintPtr(callTargetToRef))).IsHeapObject()) { return; } Barriers::UpdateSlot(thread, callTargetToRef, TaggedObject::HCLASS_OFFSET); if (JSTaggedValue(reinterpret_cast(callTargetToRef)).IsJSProxy()) { // JSProxy TaggedObject *methodToRef = reinterpret_cast(Barriers::UpdateSlot(thread, callTargetToRef, JSProxy::METHOD_OFFSET)); Barriers::UpdateSlot(thread, methodToRef, Method::CONSTANT_POOL_OFFSET); } else if (JSTaggedValue(reinterpret_cast(callTargetToRef)).IsJSFunctionBase()) { // JSFunctionBase TaggedObject *methodToRef = reinterpret_cast( Barriers::UpdateSlot(thread, callTargetToRef, JSFunctionBase::METHOD_OFFSET)); Barriers::UpdateSlot(thread, methodToRef, Method::CONSTANT_POOL_OFFSET); // JSFunction : FunctionBase if (JSTaggedValue(reinterpret_cast(callTargetToRef)).IsJSFunction()) { TaggedObject *profileTypeInfoToRef = reinterpret_cast( Barriers::UpdateSlot(thread, callTargetToRef, JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET)); Barriers::UpdateSlot(thread, profileTypeInfoToRef, ProfileTypeInfoCell::VALUE_OFFSET); Barriers::UpdateSlot(thread, callTargetToRef, JSFunction::LEXICAL_ENV_OFFSET); } // BoundFunction : FunctionBase if (JSTaggedValue(reinterpret_cast(callTargetToRef)).IsBoundFunction()) { auto toTaggedArray = reinterpret_cast( Barriers::UpdateSlot(thread, callTargetToRef, JSBoundFunction::BOUND_ARGUMENTS_OFFSET)); auto boundTargetToRef = reinterpret_cast( Barriers::UpdateSlot(thread, callTargetToRef, JSBoundFunction::BOUND_TARGET_OFFSET)); Barriers::UpdateSlot(thread, callTargetToRef, JSBoundFunction::BOUND_THIS_OFFSET); CopyCallTarget(thread, boundTargetToRef); uintptr_t argvAddr = ToUintPtr(toTaggedArray) + TaggedArray::DATA_OFFSET; void *argvToRef = reinterpret_cast(argvAddr); uint64_t argc = static_cast(Barriers::GetPrimitive(toTaggedArray, TaggedArray::LENGTH_OFFSET)); CopyArgvArray(thread, argvToRef, argc); } } else { ASSERT(!JSTaggedValue(reinterpret_cast(callTargetToRef)).IsCallable()); } } static inline void CopyArgvArray(const JSThread *thread, void *argvToRef, uint64_t argc) { for (uint64_t i = 0; i < argc; i++) { size_t offset = i * sizeof(JSTaggedType); Barriers::UpdateSlot(thread, argvToRef, offset); } } static inline void CopyGeneratorContext(const JSThread *thread, void *contextToRef) { Barriers::UpdateSlot(thread, contextToRef, GeneratorContext::GENERATOR_METHOD_OFFSET); Barriers::UpdateSlot(thread, contextToRef, GeneratorContext::GENERATOR_THIS_OFFSET); Barriers::UpdateSlot(thread, contextToRef, GeneratorContext::GENERATOR_LEXICALENV_OFFSET); Barriers::UpdateSlot(thread, contextToRef, GeneratorContext::GENERATOR_ACC_OFFSET); TaggedObject *toTaggedArray = reinterpret_cast( Barriers::UpdateSlot(thread, contextToRef, GeneratorContext::GENERATOR_REGS_ARRAY_OFFSET)); uintptr_t argvAddr = ToUintPtr(toTaggedArray) + TaggedArray::DATA_OFFSET; void *argvToRef = reinterpret_cast(argvAddr); uint64_t argc = static_cast( Barriers::GetPrimitive(contextToRef, GeneratorContext::GENERATOR_NREGS_OFFSET)); CopyArgvArray(thread, argvToRef, argc); } }; } #endif // ECMASCRIPT_BASE_GC_HELPER_H