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