• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "common_components/serialize/serialize_utils.h"
17 #include "ecmascript/serializer/base_serializer-inl.h"
18 
19 namespace panda::ecmascript {
20 
GetSerializedObjectSpace(TaggedObject * object) const21 SerializedObjectSpace BaseSerializer::GetSerializedObjectSpace(TaggedObject *object) const
22 {
23     if (g_isEnableCMCGC) {
24         SerializedObjectSpace spaceType =
25             SerializedObjectSpace(static_cast<int>(common::SerializeUtils::GetSerializeObjectSpace(ToUintPtr(object))));
26         if (spaceType == SerializedObjectSpace::OTHER) {
27             LOG_ECMA(FATAL) << "unsupported space type";
28         }
29         return spaceType;
30     } else {
31         auto region = Region::ObjectAddressToRange(object);
32         auto flag = region->GetRegionSpaceFlag();
33         switch (flag) {
34             case RegionSpaceFlag::IN_OLD_SPACE:
35             case RegionSpaceFlag::IN_YOUNG_SPACE:
36             case RegionSpaceFlag::IN_APPSPAWN_SPACE:
37                 return SerializedObjectSpace::OLD_SPACE;
38             case RegionSpaceFlag::IN_NON_MOVABLE_SPACE:
39             case RegionSpaceFlag::IN_READ_ONLY_SPACE:
40                 return SerializedObjectSpace::NON_MOVABLE_SPACE;
41             case RegionSpaceFlag::IN_MACHINE_CODE_SPACE:
42                 return SerializedObjectSpace::MACHINE_CODE_SPACE;
43             case RegionSpaceFlag::IN_HUGE_OBJECT_SPACE:
44                 return SerializedObjectSpace::HUGE_SPACE;
45             case RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE:
46             case RegionSpaceFlag::IN_SHARED_OLD_SPACE:
47             case RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE:
48                 return SerializedObjectSpace::SHARED_OLD_SPACE;
49             case RegionSpaceFlag::IN_SHARED_NON_MOVABLE:
50                 return SerializedObjectSpace::SHARED_NON_MOVABLE_SPACE;
51             case RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE:
52                 return SerializedObjectSpace::SHARED_HUGE_SPACE;
53             default:
54                 LOG_ECMA(FATAL) << "this branch is unreachable, the fault flag is: " << static_cast<uint32_t>(flag);
55                 UNREACHABLE();
56         }
57     }
58 }
59 
WriteMultiRawData(uintptr_t beginAddr,size_t fieldSize)60 void BaseSerializer::WriteMultiRawData(uintptr_t beginAddr, size_t fieldSize)
61 {
62     if (fieldSize > 0) {
63         data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
64         data_->WriteUint32(fieldSize);
65         data_->WriteRawData(reinterpret_cast<uint8_t *>(beginAddr), fieldSize);
66     }
67 }
68 
69 // Write JSTaggedValue could be either a pointer to a HeapObject or a value
SerializeJSTaggedValue(JSTaggedValue value)70 void BaseSerializer::SerializeJSTaggedValue(JSTaggedValue value)
71 {
72     DISALLOW_GARBAGE_COLLECTION;
73     if (!value.IsHeapObject()) {
74         data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
75         data_->WriteJSTaggedValue(value);
76     } else {
77         TaggedObject *object = nullptr;
78         bool isWeak = value.IsWeak();
79         object = isWeak ? value.GetWeakReferent() : value.GetTaggedObject();
80         SerializeObjectImpl(object, isWeak);
81     }
82 }
83 
SerializeReference(TaggedObject * object)84 bool BaseSerializer::SerializeReference(TaggedObject *object)
85 {
86     if (referenceMap_.find(object) != referenceMap_.end()) {
87         uint32_t objectIndex = referenceMap_.find(object)->second;
88         data_->WriteEncodeFlag(EncodeFlag::REFERENCE);
89         data_->WriteUint32(objectIndex);
90         return true;
91     }
92     return false;
93 }
94 
SerializeRootObject(TaggedObject * object)95 bool BaseSerializer::SerializeRootObject(TaggedObject *object)
96 {
97     size_t index = vm_->GetSnapshotEnv()->FindEnvObjectIndex(ToUintPtr(object));
98     if (index != SnapshotEnv::MAX_UINT_32) {
99         data_->WriteEncodeFlag(EncodeFlag::ROOT_OBJECT);
100         data_->WriteUint32(index);
101         return true;
102     }
103 
104     return false;
105 }
106 
SerializeSharedObject(TaggedObject * object)107 void BaseSerializer::SerializeSharedObject(TaggedObject *object)
108 {
109     data_->WriteEncodeFlag(EncodeFlag::SHARED_OBJECT);
110     data_->WriteUint32(sharedObjChunk_->Size());
111     referenceMap_.emplace(object, objectIndex_++);
112     sharedObjChunk_->Emplace(static_cast<JSTaggedType>(ToUintPtr(object)));
113 }
114 
SerializeSpecialObjIndividually(JSType objectType,TaggedObject * root,ObjectSlot start,ObjectSlot end)115 bool BaseSerializer::SerializeSpecialObjIndividually(JSType objectType, TaggedObject *root,
116                                                      ObjectSlot start, ObjectSlot end)
117 {
118     switch (objectType) {
119         case JSType::HCLASS:
120             SerializeHClassFieldIndividually(root, start, end);
121             return true;
122         case JSType::LEXICAL_ENV:
123             SerializeLexicalEnvFieldIndividually(root, start, end);
124             return true;
125         case JSType::SFUNCTION_ENV:
126             SerializeSFunctionEnvFieldIndividually(root, start, end);
127             return true;
128         case JSType::SENDABLE_ENV:
129             SerializeSendableEnvFieldIndividually(root, start, end);
130             return true;
131         case JSType::JS_SHARED_FUNCTION:
132         case JSType::JS_SHARED_ASYNC_FUNCTION:
133             SerializeSFunctionFieldIndividually(root, start, end);
134             return true;
135         case JSType::JS_ASYNC_FUNCTION:
136             SerializeAsyncFunctionFieldIndividually(root, start, end);
137             return true;
138         default:
139             return false;
140     }
141 }
142 
SerializeHClassFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)143 void BaseSerializer::SerializeHClassFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
144 {
145     ASSERT(root->GetClass()->IsHClass());
146     ObjectSlot slot = start;
147     while (slot < end) {
148         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
149         switch (fieldOffset) {
150             case JSHClass::PROTOTYPE_OFFSET: {
151                 JSHClass *kclass = reinterpret_cast<JSHClass *>(root);
152                 JSTaggedValue proto = kclass->GetPrototype(thread_);
153                 JSType type = kclass->GetObjectType();
154                 if ((serializeSharedEvent_ > 0) &&
155                     (type == JSType::JS_SHARED_OBJECT || type == JSType::JS_SHARED_FUNCTION)) {
156                     SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
157                 } else {
158                     SerializeObjectProto(kclass, proto);
159                 }
160                 slot++;
161                 break;
162             }
163             case JSHClass::TRANSTIONS_OFFSET:
164             case JSHClass::PARENT_OFFSET: {
165                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
166                 data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
167                 slot++;
168                 break;
169             }
170             case JSHClass::PROTO_CHANGE_MARKER_OFFSET:
171             case JSHClass::PROTO_CHANGE_DETAILS_OFFSET:
172             case JSHClass::ENUM_CACHE_OFFSET: {
173                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
174                 data_->WriteJSTaggedValue(JSTaggedValue::Null());
175                 slot++;
176                 break;
177             }
178             default: {
179                 SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
180                 slot++;
181                 break;
182             }
183         }
184     }
185 }
186 
SerializeSFunctionFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)187 void BaseSerializer::SerializeSFunctionFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
188 {
189     ASSERT(root->GetClass()->GetObjectType() == JSType::JS_SHARED_FUNCTION ||
190         root->GetClass()->GetObjectType() == JSType::JS_SHARED_ASYNC_FUNCTION);
191     ObjectSlot slot = start;
192     while (slot < end) {
193         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
194         switch (fieldOffset) {
195             case JSFunction::MACHINECODE_OFFSET:
196             case JSFunction::BASELINECODE_OFFSET:
197             case JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET: {
198                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
199                 data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
200                 slot++;
201                 break;
202             }
203             case JSFunction::ECMA_MODULE_OFFSET: {
204                 SerializeSFunctionModule(JSFunction::Cast(root));
205                 slot++;
206                 break;
207             }
208             case JSFunction::WORK_NODE_POINTER_OFFSET: {
209                 data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
210                 data_->WriteUint32(sizeof(uintptr_t));
211                 data_->WriteRawData(reinterpret_cast<uint8_t *>(slot.SlotAddress()), sizeof(uintptr_t));
212                 break;
213             }
214             default: {
215                 SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
216                 slot++;
217                 break;
218             }
219         }
220     }
221 }
222 
SerializeSFunctionModule(JSFunction * func)223 void BaseSerializer::SerializeSFunctionModule(JSFunction *func)
224 {
225     JSTaggedValue moduleValue = func->GetModule(thread_);
226     if (moduleValue.IsHeapObject()) {
227         if (!moduleValue.IsInSharedHeap()) {
228             LOG_ECMA(ERROR) << "Shared function reference to local module";
229         }
230         if (!SerializeReference(moduleValue.GetTaggedObject())) {
231             // Module of shared function should write pointer directly when serialize
232             SerializeSharedObject(moduleValue.GetTaggedObject());
233         }
234     } else {
235         data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
236         data_->WriteJSTaggedValue(moduleValue);
237     }
238 }
239 
SerializeLexicalEnvFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)240 void BaseSerializer::SerializeLexicalEnvFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
241 {
242     ASSERT(root->GetClass()->GetObjectType() == JSType::LEXICAL_ENV);
243     ObjectSlot slot = start;
244     while (slot < end) {
245         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
246         switch (fieldOffset) {
247             case LEXICALENV_GLOBAL_ENV_SLOT:
248             case LEXICALENV_PARENT_ENV_SLOT:
249             case LEXICALENV_SCOPE_INFO_SLOT: {
250                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
251                 data_->WriteJSTaggedValue(JSTaggedValue::Hole());
252                 slot++;
253                 break;
254             }
255             default: {
256                 SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
257                 slot++;
258                 break;
259             }
260         }
261     }
262 }
263 
SerializeSFunctionEnvFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)264 void BaseSerializer::SerializeSFunctionEnvFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
265 {
266     ASSERT(root->GetClass()->GetObjectType() == JSType::SFUNCTION_ENV);
267     ObjectSlot slot = start;
268     while (slot < end) {
269         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
270         switch (fieldOffset) {
271             case SFUNCTIONENV_GLOBAL_ENV_SLOT:
272             case SFUNCTIONENV_CONSTRUCTOR_SLOT: {
273                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
274                 data_->WriteJSTaggedValue(JSTaggedValue::Hole());
275                 slot++;
276                 break;
277             }
278             default: {
279                 SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
280                 slot++;
281                 break;
282             }
283         }
284     }
285 }
286 
SerializeSendableEnvFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)287 void BaseSerializer::SerializeSendableEnvFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
288 {
289     ASSERT(root->GetClass()->GetObjectType() == JSType::SENDABLE_ENV);
290     ObjectSlot slot = start;
291     while (slot < end) {
292         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
293         switch (fieldOffset) {
294             case SENDABLEENV_PARENT_ENV_SLOT:
295             case SENDABLEENV_SCOPE_INFO_SLOT: {
296                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
297                 data_->WriteJSTaggedValue(JSTaggedValue::Hole());
298                 slot++;
299                 break;
300             }
301             default: {
302                 SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
303                 slot++;
304                 break;
305             }
306         }
307     }
308 }
309 
SerializeAsyncFunctionFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)310 void BaseSerializer::SerializeAsyncFunctionFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
311 {
312     ASSERT(root->GetClass()->GetObjectType() == JSType::JS_ASYNC_FUNCTION);
313     ObjectSlot slot = start;
314     while (slot < end) {
315         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
316         switch (fieldOffset) {
317             // hash filed
318             case sizeof(TaggedObject): {
319                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
320                 data_->WriteJSTaggedValue(JSTaggedValue(0)); // 0: reset hash filed
321                 slot++;
322                 break;
323             }
324             case JSFunction::PROTO_OR_DYNCLASS_OFFSET:
325             case JSFunction::MACHINECODE_OFFSET:
326             case JSFunction::BASELINECODE_OFFSET:
327             case JSFunction::RAW_PROFILE_TYPE_INFO_OFFSET:
328             case JSFunction::HOME_OBJECT_OFFSET:
329             case JSFunction::ECMA_MODULE_OFFSET: {
330                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
331                 data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
332                 slot++;
333                 break;
334             }
335             case JSFunction::LEXICAL_ENV_OFFSET:
336                 data_->WriteEncodeFlag(EncodeFlag::GLOBAL_ENV);
337                 slot++;
338                 break;
339             case JSFunction::WORK_NODE_POINTER_OFFSET: {
340                 data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
341                 data_->WriteUint32(sizeof(uintptr_t));
342                 data_->WriteRawData(reinterpret_cast<uint8_t *>(slot.SlotAddress()), sizeof(uintptr_t));
343                 slot++;
344                 break;
345             }
346             default: {
347                 SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
348                 slot++;
349                 break;
350             }
351         }
352     }
353 }
354 
SerializeObjectProto(JSHClass * kclass,JSTaggedValue proto)355 void BaseSerializer::SerializeObjectProto(JSHClass *kclass, JSTaggedValue proto)
356 {
357     if (!proto.IsHeapObject()) {
358         data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
359         data_->WriteJSTaggedValue(proto);
360     } else if (!SerializeReference(proto.GetTaggedObject()) && !SerializeRootObject(proto.GetTaggedObject())) {
361         data_->WriteEncodeFlag(EncodeFlag::OBJECT_PROTO);
362         data_->WriteUint8(static_cast<uint8_t>(kclass->GetObjectType()));
363     }
364 }
365 
SerializeTaggedObjField(SerializeType serializeType,TaggedObject * root,ObjectSlot start,ObjectSlot end)366 void BaseSerializer::SerializeTaggedObjField(SerializeType serializeType, TaggedObject *root,
367                                              ObjectSlot start, ObjectSlot end)
368 {
369     JSType objectType = root->GetClass()->GetObjectType();
370     if (serializeType != SerializeType::VALUE_SERIALIZE
371         || !SerializeSpecialObjIndividually(objectType, root, start, end)) {
372         for (ObjectSlot slot = start; slot < end; slot++) {
373             SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
374         }
375     }
376 }
377 
SerializeInObjField(TaggedObject * object,ObjectSlot start,ObjectSlot end)378 void BaseSerializer::SerializeInObjField(TaggedObject *object, ObjectSlot start, ObjectSlot end)
379 {
380     auto hclass = object->GetClass();
381     auto layout = LayoutInfo::Cast(hclass->GetLayout(thread_).GetTaggedObject());
382     size_t index = 0;
383     for (ObjectSlot slot = start; slot < end; slot++) {
384         auto attr = layout->GetAttr(thread_, index++);
385         if (attr.GetRepresentation() == Representation::DOUBLE || attr.GetRepresentation() == Representation::INT) {
386             auto fieldAddr = slot.SlotAddress();
387             data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
388             data_->WriteRawData(reinterpret_cast<uint8_t *>(fieldAddr), sizeof(JSTaggedType));
389         } else {
390             SerializeJSTaggedValue(JSTaggedValue(Barriers::GetTaggedValue(thread_, slot.SlotAddress())));
391         }
392     }
393 }
394 }  // namespace panda::ecmascript
395 
396