1 /*
2 * Copyright (c) 2025 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #ifndef ECMASCRIPT_MEM_DYNAMIC_OBJECT_OPERATOR_H
17 #define ECMASCRIPT_MEM_DYNAMIC_OBJECT_OPERATOR_H
18
19 #include "common_interfaces/objects/base_object.h"
20 #include "common_interfaces/objects/base_object_operator.h"
21 #include "ecmascript/free_object.h"
22 #include "ecmascript/js_hclass-inl.h"
23 #include "ecmascript/mem/tagged_object.h"
24 #include "libpandabase/macros.h"
25
26 namespace panda::ecmascript {
27 class RefFieldObjectVisitor final : public BaseObjectVisitor<RefFieldObjectVisitor> {
28 public:
RefFieldObjectVisitor(const common::RefFieldVisitor & visitor)29 inline explicit RefFieldObjectVisitor(const common::RefFieldVisitor &visitor): visitor_(visitor) {};
30 ~RefFieldObjectVisitor() override = default;
31
32 void VisitObjectRangeImpl(BaseObject *root, uintptr_t start, uintptr_t end,
33 VisitObjectArea area) override;
34
35 void VisitObjectHClassImpl(BaseObject *hclass) override;
36
37 void VisitAllRefFields(TaggedObject *obj);
38
39 private:
40 void visit(ObjectSlot slot);
41
42 template <class Callback>
VisitBodyInObj(TaggedObject * root,ObjectSlot start,ObjectSlot end,Callback && cb)43 void VisitBodyInObj(TaggedObject *root, ObjectSlot start, ObjectSlot end, Callback &&cb)
44 {
45 JSHClass *hclass = root->SynchronizedGetClass();
46 ASSERT(!hclass->IsAllTaggedProp());
47 auto thread = JSThread::GetCurrent();
48 LayoutInfo *layout;
49 if (thread == nullptr) {
50 // gc thread
51 if (g_isEnableCMCGC) {
52 layout = LayoutInfo::UncheckCast(hclass->GetLayout<RBMode::FAST_CMC_RB>(thread).GetTaggedObject());
53 } else {
54 layout = LayoutInfo::UncheckCast(hclass->GetLayout<RBMode::FAST_NO_RB>(thread).GetTaggedObject());
55 }
56 } else {
57 // serialization
58 layout = LayoutInfo::UncheckCast(hclass->GetLayout(thread).GetTaggedObject());
59 }
60 ObjectSlot realEnd = start;
61 realEnd += layout->GetPropertiesCapacity(); // only += operator is supported
62 end = std::min(end, realEnd);
63
64 int index = 0;
65 for (ObjectSlot slot = start; slot < end; slot++) {
66 PropertyAttributes attr;
67 if (thread == nullptr) {
68 if (g_isEnableCMCGC) {
69 attr = layout->GetAttr<RBMode::FAST_CMC_RB>(thread, index++);
70 } else {
71 attr = layout->GetAttr<RBMode::FAST_NO_RB>(thread, index++);
72 }
73 } else {
74 attr = layout->GetAttr(thread, index++);
75 }
76 if (attr.IsTaggedRep()) {
77 cb(slot);
78 }
79 }
80 }
81
82 const common::RefFieldVisitor &visitor_;
83 };
84
85 static constexpr uint64_t TAG_MARK_BIT = 0x02ULL;
GetHeader(const BaseObject * obj)86 static uint64_t GetHeader(const BaseObject* obj)
87 {
88 return (*((uint64_t*)obj));
89 }
90
91 class DynamicObjectOperator : public common::BaseObjectOperatorInterfaces {
92 public:
93 static void Initialize();
94
IsValidObject(const BaseObject * object)95 bool IsValidObject([[maybe_unused]] const BaseObject *object) const override
96 {
97 auto taggedObject = TaggedObject::Cast(object);
98 auto hclass = taggedObject->GetClass();
99
100 return hclass->GetClass()->IsHClass();
101 }
102
ForEachRefField(const BaseObject * object,const common::RefFieldVisitor & visitor)103 void ForEachRefField(const BaseObject *object, const common::RefFieldVisitor &visitor) const override
104 {
105 auto freeObject = FreeObject::Cast(reinterpret_cast<uintptr_t>(object));
106 if (!freeObject->IsFreeObject()) {
107 RefFieldObjectVisitor refFieldObjectVisitor(visitor);
108 refFieldObjectVisitor.VisitAllRefFields(TaggedObject::Cast(object));
109 }
110 }
111
GetSize(const BaseObject * object)112 size_t GetSize(const BaseObject *object) const override
113 {
114 ASSERT(!g_isEnableCMCGC || !object->IsForwarded());
115 auto freeObject = FreeObject::Cast(reinterpret_cast<uintptr_t>(object));
116 if (freeObject->IsFreeObject()) {
117 return freeObject->Available();
118 }
119 auto taggedObject = TaggedObject::Cast(object);
120 JSHClass *jsHclass = taggedObject->GetClass();
121 size_t size = jsHclass->SizeFromJSHClass(taggedObject);
122 return AlignUp<size_t>(size, 8); // 8 Byte alignment
123 }
124
GetForwardingPointer(const BaseObject * object)125 BaseObject *GetForwardingPointer(const BaseObject *object) const override
126 {
127 return TaggedObject::Cast(object)->GetForwardingPointer();
128 }
129
SetForwardingPointerAfterExclusive(BaseObject * object,BaseObject * fwdPtr)130 void SetForwardingPointerAfterExclusive(BaseObject *object, BaseObject *fwdPtr) override
131 {
132 TaggedObject::Cast(object)->SetForwardingPointerAfterExclusive(fwdPtr);
133 }
134
135 private:
136 static DynamicObjectOperator dynOperator_;
137 };
138 } // namespace panda::ecmascript
139 #endif // ECMASCRIPT_MEM_DYNAMIC_OBJECT_OPERATOR_H
140