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 18namespace panda::ecmascript { 19 20SerializedObjectSpace 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 50void 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 60void 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 74bool 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 85bool 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 97void 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 105bool 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 130void 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 174void 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 210void 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 227void 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 250void 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 273void 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 315void 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 326void 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 338void 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