• 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_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