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