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