* 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_MEM_DYNAMIC_OBJECT_OPERATOR_H
#define ECMASCRIPT_MEM_DYNAMIC_OBJECT_OPERATOR_H
#include "objects/base_object.h"
#include "objects/base_object_operator.h"
#include "ecmascript/free_object.h"
#include "ecmascript/js_hclass-inl.h"
#include "ecmascript/mem/tagged_object.h"
#include "libpandabase/macros.h"
namespace panda::ecmascript {
class RefFieldObjectVisitor final : public BaseObjectVisitor<RefFieldObjectVisitor> {
public:
inline explicit RefFieldObjectVisitor(const common::RefFieldVisitor &visitor): visitor_(visitor) {};
~RefFieldObjectVisitor() override = default;
void VisitObjectRangeImpl(BaseObject *root, uintptr_t start, uintptr_t end,
VisitObjectArea area) override;
void VisitObjectHClassImpl(BaseObject *hclass) override;
void VisitAllRefFields(TaggedObject *obj);
private:
void visit(ObjectSlot slot);
template <class Callback>
void VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback &&cb)
{
JSHClass *hclass = root->SynchronizedGetClass();
ASSERT(!hclass->IsAllTaggedProp());
auto thread = JSThread::GetCurrent();
LayoutInfo *layout;
if (thread == nullptr) {
if (g_isEnableCMCGC) {
layout = LayoutInfo::UncheckCast(hclass->GetLayout<RBMode::FAST_CMC_RB>(thread).GetTaggedObject());
} else {
layout = LayoutInfo::UncheckCast(hclass->GetLayout<RBMode::FAST_NO_RB>(thread).GetTaggedObject());
}
} else {
layout = LayoutInfo::UncheckCast(hclass->GetLayout(thread).GetTaggedObject());
}
ObjectSlot realEnd = start;
realEnd += layout->GetPropertiesCapacity();
end = std::min(end, realEnd);
int index = 0;
for (ObjectSlot slot = start; slot < end; slot++) {
PropertyAttributes attr;
if (thread == nullptr) {
if (g_isEnableCMCGC) {
attr = layout->GetAttr<RBMode::FAST_CMC_RB>(thread, index++);
} else {
attr = layout->GetAttr<RBMode::FAST_NO_RB>(thread, index++);
}
} else {
attr = layout->GetAttr(thread, index++);
}
if (attr.IsTaggedRep()) {
cb(slot);
}
}
}
const common::RefFieldVisitor &visitor_;
};
static constexpr uint64_t TAG_MARK_BIT = 0x02ULL;
static uint64_t GetHeader(const BaseObject* obj)
{
return (*((uint64_t*)obj));
}
class DynamicObjectOperator : public common::BaseObjectOperatorInterfaces {
public:
static void Initialize();
bool IsValidObject([[maybe_unused]] const BaseObject *object) const override
{
auto taggedObject = TaggedObject::Cast(object);
auto hclass = taggedObject->GetClass();
return hclass->GetClass()->IsHClass();
}
void ForEachRefFieldSkipReferent(const BaseObject *object, const common::RefFieldVisitor &visitor) const override
{
ForEachRefField(object, visitor);
}
void ForEachRefField(const BaseObject *object, const common::RefFieldVisitor &visitor) const override
{
auto freeObject = FreeObject::Cast(reinterpret_cast<uintptr_t>(object));
if (!freeObject->IsFreeObject()) {
RefFieldObjectVisitor refFieldObjectVisitor(visitor);
refFieldObjectVisitor.VisitAllRefFields(TaggedObject::Cast(object));
}
}
size_t ForEachRefFieldAndGetSize(const BaseObject *object, const common::RefFieldVisitor &visitor) const override
{
auto obj = TaggedObject::Cast(object);
auto klass = obj->GetClass();
auto size = klass->SizeFromJSHClass(obj);
RefFieldObjectVisitor refFieldObjectVisitor(visitor);
refFieldObjectVisitor.VisitAllRefFields(obj);
return size;
}
void IterateXRef(const BaseObject *object, const common::RefFieldVisitor &visitor) const override;
size_t GetSize(const BaseObject *object) const override
{
ASSERT(!g_isEnableCMCGC || !object->IsForwarded());
auto freeObject = FreeObject::Cast(reinterpret_cast<uintptr_t>(object));
if (freeObject->IsFreeObject()) {
return freeObject->Available();
}
auto taggedObject = TaggedObject::Cast(object);
JSHClass *jsHclass = taggedObject->GetClass();
size_t size = jsHclass->SizeFromJSHClass(taggedObject);
return AlignUp<size_t>(size, 8);
}
BaseObject *GetForwardingPointer(const BaseObject *object) const override
{
return TaggedObject::Cast(object)->GetForwardingPointer();
}
void SetForwardingPointerAfterExclusive(BaseObject *object, BaseObject *fwdPtr) override
{
TaggedObject::Cast(object)->SetForwardingPointerAfterExclusive(fwdPtr);
}
private:
static DynamicObjectOperator dynOperator_;
};
}
#endif