• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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