• 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 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/mem/mem.h"
20 #include "ecmascript/mem/region.h"
21 
22 namespace panda::ecmascript {
23 
GetSerializedObjectSpace(TaggedObject * object) const24 SerializedObjectSpace BaseSerializer::GetSerializedObjectSpace(TaggedObject *object) const
25 {
26     auto region = Region::ObjectAddressToRange(object);
27     if (region->InYoungOrOldSpace() || region->InAppSpawnSpace()) {
28         return SerializedObjectSpace::OLD_SPACE;
29     }
30     if (region->InNonMovableSpace() || region->InReadOnlySpace()) {
31         return SerializedObjectSpace::NON_MOVABLE_SPACE;
32     }
33     if (region->InMachineCodeSpace()) {
34         return SerializedObjectSpace::MACHINE_CODE_SPACE;
35     }
36     if (region->InHugeObjectSpace()) {
37         return SerializedObjectSpace::HUGE_SPACE;
38     }
39     LOG_ECMA(FATAL) << "this branch is unreachable";
40     UNREACHABLE();
41 }
42 
WriteMultiRawData(uintptr_t beginAddr,size_t fieldSize)43 void BaseSerializer::WriteMultiRawData(uintptr_t beginAddr, size_t fieldSize)
44 {
45     if (fieldSize > 0) {
46         data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
47         data_->WriteUint32(fieldSize);
48         data_->WriteRawData(reinterpret_cast<uint8_t *>(beginAddr), fieldSize);
49     }
50 }
51 
52 // Write JSTaggedValue could be either a pointer to a HeapObject or a value
SerializeJSTaggedValue(JSTaggedValue value)53 void BaseSerializer::SerializeJSTaggedValue(JSTaggedValue value)
54 {
55     DISALLOW_GARBAGE_COLLECTION;
56     if (!value.IsHeapObject()) {
57         data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
58         data_->WriteJSTaggedValue(value);
59     } else {
60         TaggedObject *object = nullptr;
61         bool isWeak = value.IsWeak();
62         object = isWeak ? value.GetWeakReferent() : value.GetTaggedObject();
63         SerializeObjectImpl(object, isWeak);
64     }
65 }
66 
SerializeReference(TaggedObject * object)67 bool BaseSerializer::SerializeReference(TaggedObject *object)
68 {
69     if (referenceMap_.find(object) != referenceMap_.end()) {
70         uint32_t objectIndex = referenceMap_.find(object)->second;
71         data_->WriteEncodeFlag(EncodeFlag::REFERENCE);
72         data_->WriteUint32(objectIndex);
73         return true;
74     }
75     return false;
76 }
77 
SerializeRootObject(TaggedObject * object)78 bool BaseSerializer::SerializeRootObject(TaggedObject *object)
79 {
80     size_t index = vm_->GetSnapshotEnv()->FindEnvObjectIndex(ToUintPtr(object));
81     if (index != SnapshotEnv::MAX_UINT_32) {
82         data_->WriteEncodeFlag(EncodeFlag::ROOT_OBJECT);
83         data_->WriteUint32(index);
84         return true;
85     }
86 
87     return false;
88 }
89 
SerializeSpecialObjIndividually(JSType objectType,TaggedObject * root,ObjectSlot start,ObjectSlot end)90 bool BaseSerializer::SerializeSpecialObjIndividually(JSType objectType, TaggedObject *root,
91                                                      ObjectSlot start, ObjectSlot end)
92 {
93     switch (objectType) {
94         case JSType::HCLASS:
95             SerializeHClassFieldIndividually(root, start, end);
96             return true;
97         case JSType::LEXICAL_ENV:
98             SerializeLexicalEnvFieldIndividually(root, start, end);
99             return true;
100         case JSType::JS_SHARED_FUNCTION:
101             SerializeSFunctionFieldIndividually(root, start, end);
102             return true;
103         case JSType::JS_ASYNC_FUNCTION:
104             SerializeAsyncFunctionFieldIndividually(root, start, end);
105             return true;
106         case JSType::METHOD:
107             SerializeMethodFieldIndividually(root, start, end);
108             return true;
109         default:
110             return false;
111     }
112 }
113 
SerializeHClassFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)114 void BaseSerializer::SerializeHClassFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
115 {
116     ASSERT(root->GetClass()->IsHClass());
117     ObjectSlot slot = start;
118     while (slot < end) {
119         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
120         switch (fieldOffset) {
121             case JSHClass::PROTOTYPE_OFFSET: {
122                 JSHClass *kclass = reinterpret_cast<JSHClass *>(root);
123                 JSTaggedValue proto = kclass->GetPrototype();
124                 JSType type = kclass->GetObjectType();
125                 if ((serializeSharedEvent_ > 0) &&
126                     (type == JSType::JS_SHARED_OBJECT || type == JSType::JS_SHARED_FUNCTION)) {
127                     SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
128                 } else {
129                     SerializeObjectProto(kclass, proto);
130                 }
131                 slot++;
132                 break;
133             }
134             case JSHClass::TRANSTIONS_OFFSET:
135             case JSHClass::PARENT_OFFSET:
136             case JSHClass::VTABLE_OFFSET: {
137                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
138                 data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
139                 slot++;
140                 break;
141             }
142             case JSHClass::PROTO_CHANGE_MARKER_OFFSET:
143             case JSHClass::PROTO_CHANGE_DETAILS_OFFSET:
144             case JSHClass::ENUM_CACHE_OFFSET: {
145                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
146                 data_->WriteJSTaggedValue(JSTaggedValue::Null());
147                 slot++;
148                 break;
149             }
150             case JSHClass::SUPERS_OFFSET: {
151                 auto globalConst = const_cast<GlobalEnvConstants *>(thread_->GlobalConstants());
152                 data_->WriteEncodeFlag(EncodeFlag::ROOT_OBJECT);
153                 data_->WriteUint32(globalConst->GetEmptyArrayIndex());
154                 slot++;
155                 break;
156             }
157             default: {
158                 SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
159                 slot++;
160                 break;
161             }
162         }
163     }
164 }
165 
SerializeSFunctionFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)166 void BaseSerializer::SerializeSFunctionFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
167 {
168     ASSERT(root->GetClass()->GetObjectType() == JSType::JS_SHARED_FUNCTION);
169     ObjectSlot slot = start;
170     while (slot < end) {
171         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
172         switch (fieldOffset) {
173             case JSFunction::WORK_NODE_POINTER_OFFSET: {
174                 data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
175                 data_->WriteUint32(sizeof(uintptr_t));
176                 data_->WriteRawData(reinterpret_cast<uint8_t *>(slot.SlotAddress()), sizeof(uintptr_t));
177                 break;
178             }
179             default: {
180                 SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
181                 slot++;
182                 break;
183             }
184         }
185     }
186 }
187 
SerializeLexicalEnvFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)188 void BaseSerializer::SerializeLexicalEnvFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
189 {
190     ASSERT(root->GetClass()->GetObjectType() == JSType::LEXICAL_ENV);
191     ObjectSlot slot = start;
192     while (slot < end) {
193         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
194         switch (fieldOffset) {
195             case PARENT_ENV_SLOT:
196             case SCOPE_INFO_SLOT: {
197                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
198                 data_->WriteJSTaggedValue(JSTaggedValue::Hole());
199                 slot++;
200                 break;
201             }
202             default: {
203                 SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
204                 slot++;
205                 break;
206             }
207         }
208     }
209 }
210 
SerializeAsyncFunctionFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)211 void BaseSerializer::SerializeAsyncFunctionFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
212 {
213     ASSERT(root->GetClass()->GetObjectType() == JSType::JS_ASYNC_FUNCTION);
214     ObjectSlot slot = start;
215     while (slot < end) {
216         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
217         switch (fieldOffset) {
218             // hash filed
219             case sizeof(TaggedObject): {
220                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
221                 data_->WriteJSTaggedValue(JSTaggedValue(0)); // 0: reset hash filed
222                 slot++;
223                 break;
224             }
225             case JSFunction::PROTO_OR_DYNCLASS_OFFSET:
226             case JSFunction::LEXICAL_ENV_OFFSET:
227             case JSFunction::HOME_OBJECT_OFFSET: {
228                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
229                 data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
230                 slot++;
231                 break;
232             }
233             case JSFunction::WORK_NODE_POINTER_OFFSET: {
234                 data_->WriteEncodeFlag(EncodeFlag::MULTI_RAW_DATA);
235                 data_->WriteUint32(sizeof(uintptr_t));
236                 data_->WriteRawData(reinterpret_cast<uint8_t *>(slot.SlotAddress()), sizeof(uintptr_t));
237                 slot++;
238                 break;
239             }
240             default: {
241                 SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
242                 slot++;
243                 break;
244             }
245         }
246     }
247 }
248 
SerializeMethodFieldIndividually(TaggedObject * root,ObjectSlot start,ObjectSlot end)249 void BaseSerializer::SerializeMethodFieldIndividually(TaggedObject *root, ObjectSlot start, ObjectSlot end)
250 {
251     ASSERT(root->GetClass()->IsMethod());
252     ObjectSlot slot = start;
253     while (slot < end) {
254         size_t fieldOffset = slot.SlotAddress() - ToUintPtr(root);
255         switch (fieldOffset) {
256             case Method::CONSTANT_POOL_OFFSET:
257             case Method::PROFILE_TYPE_INFO_OFFSET:
258             case Method::ECMA_MODULE_OFFSET: {
259                 data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
260                 data_->WriteJSTaggedValue(JSTaggedValue::Undefined());
261                 slot++;
262                 break;
263             }
264             default: {
265                 SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
266                 slot++;
267                 break;
268             }
269         }
270     }
271 }
272 
SerializeObjectProto(JSHClass * kclass,JSTaggedValue proto)273 void BaseSerializer::SerializeObjectProto(JSHClass *kclass, JSTaggedValue proto)
274 {
275     if (!proto.IsHeapObject()) {
276         data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
277         data_->WriteJSTaggedValue(proto);
278     } else if (!SerializeReference(proto.GetTaggedObject()) && !SerializeRootObject(proto.GetTaggedObject())) {
279         data_->WriteEncodeFlag(EncodeFlag::OBJECT_PROTO);
280         data_->WriteUint8(static_cast<uint8_t>(kclass->GetObjectType()));
281     }
282 }
283 
SerializeTaggedObjField(SerializeType serializeType,TaggedObject * root,ObjectSlot start,ObjectSlot end)284 void BaseSerializer::SerializeTaggedObjField(SerializeType serializeType, TaggedObject *root,
285                                              ObjectSlot start, ObjectSlot end)
286 {
287     JSType objectType = root->GetClass()->GetObjectType();
288     if (serializeType != SerializeType::VALUE_SERIALIZE
289         || !SerializeSpecialObjIndividually(objectType, root, start, end)) {
290         for (ObjectSlot slot = start; slot < end; slot++) {
291             SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
292         }
293     }
294 }
295 
SerializeInObjField(TaggedObject * object,ObjectSlot start,ObjectSlot end)296 void BaseSerializer::SerializeInObjField(TaggedObject *object, ObjectSlot start, ObjectSlot end)
297 {
298     auto hclass = object->GetClass();
299     auto layout = LayoutInfo::Cast(hclass->GetLayout().GetTaggedObject());
300     size_t index = 0;
301     for (ObjectSlot slot = start; slot < end; slot++) {
302         auto attr = layout->GetAttr(index++);
303         if (attr.GetRepresentation() == Representation::DOUBLE || attr.GetRepresentation() == Representation::INT) {
304             auto fieldAddr = slot.SlotAddress();
305             data_->WriteEncodeFlag(EncodeFlag::PRIMITIVE);
306             data_->WriteRawData(reinterpret_cast<uint8_t *>(fieldAddr), sizeof(JSTaggedType));
307         } else {
308             SerializeJSTaggedValue(JSTaggedValue(slot.GetTaggedType()));
309         }
310     }
311 }
312 }  // namespace panda::ecmascript
313 
314