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