1 /* 2 * Copyright (c) 2021-2024 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 #ifndef ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_PROCESSOR_H 17 #define ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_PROCESSOR_H 18 19 #include <iostream> 20 #include <fstream> 21 #include <sstream> 22 23 #include "common_components/serialize/serialize_utils.h" 24 #include "ecmascript/serializer/serialize_data.h" 25 #include "ecmascript/snapshot/mem/encode_bit.h" 26 #include "ecmascript/jspandafile/method_literal.h" 27 #include "ecmascript/js_tagged_value.h" 28 #include "ecmascript/mem/object_xray.h" 29 30 #include "libpandabase/macros.h" 31 32 namespace panda::ecmascript { 33 class EcmaVM; 34 class JSPandaFile; 35 class AOTFileManager; 36 37 enum class SnapshotType { 38 VM_ROOT, 39 BUILTINS, 40 AI 41 }; 42 43 struct SnapshotRegionHeadInfo { 44 size_t regionIndex_ {0}; 45 size_t aliveObjectSize_ {0}; 46 RegionHeadInfoSizeSnapshotRegionHeadInfo47 static constexpr size_t RegionHeadInfoSize() 48 { 49 return sizeof(SnapshotRegionHeadInfo); 50 } 51 }; 52 53 using ObjectEncode = std::pair<uint64_t, ecmascript::EncodeBit>; 54 55 class SnapshotProcessor final { 56 public: SnapshotProcessor(EcmaVM * vm)57 explicit SnapshotProcessor(EcmaVM *vm) 58 : vm_(vm), sHeap_(SharedHeap::GetInstance()) {} 59 ~SnapshotProcessor(); 60 61 struct AllocResult { 62 uintptr_t address; 63 size_t offset; 64 size_t regionIndex; 65 }; 66 67 void Initialize(); 68 void StopAllocate(); 69 void WriteObjectToFile(std::fstream &write); 70 std::vector<size_t> StatisticsObjectSize(); 71 void ProcessObjectQueue(CQueue<TaggedObject *> *queue, std::unordered_map<uint64_t, ObjectEncode> *data); 72 void SerializeObject(TaggedObject *objectHeader, CQueue<TaggedObject *> *queue, 73 std::unordered_map<uint64_t, ObjectEncode> *data); 74 void Relocate(SnapshotType type, const JSPandaFile *jsPandaFile, 75 uint64_t rootObjSize); 76 void RelocateSpaceObject(std::vector<std::pair<uintptr_t, size_t>> ®ions, SnapshotType type, 77 MethodLiteral* methods, size_t methodNums, size_t rootObjSize); 78 void RelocateSpaceObject(Space* space, SnapshotType type, MethodLiteral* methods, 79 size_t methodNums, size_t rootObjSize); 80 void SerializePandaFileMethod(); 81 AllocResult GetNewObj(size_t objectSize, TaggedObject *objectHeader); 82 uintptr_t GetNewObjAddress(size_t objectSize, TaggedObject *objectHeader); 83 EncodeBit EncodeTaggedObject(TaggedObject *objectHeader, CQueue<TaggedObject *> *queue, 84 std::unordered_map<uint64_t, ObjectEncode> *data); 85 EncodeBit GetObjectEncode(JSTaggedValue object, CQueue<TaggedObject *> *queue, 86 std::unordered_map<uint64_t, ObjectEncode> *data); 87 void EncodeTaggedObjectRange(ObjectSlot start, ObjectSlot end, CQueue<TaggedObject *> *queue, 88 std::unordered_map<uint64_t, ObjectEncode> *data); 89 void DeserializeObjectExcludeString(uintptr_t regularObjBegin, size_t regularObjSize, size_t pinnedObjSize, 90 size_t largeObjSize); 91 void DeserializeObjectExcludeString(uintptr_t oldSpaceBegin, size_t oldSpaceObjSize, size_t nonMovableObjSize, 92 size_t machineCodeObjSize, size_t snapshotObjSize, size_t hugeSpaceObjSize); 93 void DeserializeString(uintptr_t stringBegin, uintptr_t stringEnd); 94 95 // ONLY used in UT to get the deserialize value result GetDeserializeResultForUT()96 JSTaggedValue GetDeserializeResultForUT() const 97 { 98 return root_; 99 } 100 101 void AddRootObjectToAOTFileManager(SnapshotType type, const CString &fileName); 102 SetProgramSerializeStart()103 void SetProgramSerializeStart() 104 { 105 programSerialize_ = true; 106 } 107 SetBuiltinsSerializeStart()108 void SetBuiltinsSerializeStart() 109 { 110 builtinsSerialize_ = true; 111 } 112 SetBuiltinsDeserializeStart()113 void SetBuiltinsDeserializeStart() 114 { 115 builtinsDeserialize_ = true; 116 } 117 GetStringVector()118 const CVector<uintptr_t> GetStringVector() const 119 { 120 return stringVector_; 121 } 122 123 size_t GetNativeTableSize() const; 124 125 private: 126 class SerializeObjectVisitor final : public BaseObjectVisitor<SerializeObjectVisitor> { 127 public: 128 explicit SerializeObjectVisitor(SnapshotProcessor *processor, uintptr_t snapshotObj, 129 CQueue<TaggedObject *> *queue, std::unordered_map<uint64_t, ObjectEncode> *data); 130 ~SerializeObjectVisitor() override = default; 131 132 void VisitObjectRangeImpl(BaseObject *rootObject, uintptr_t startAddr, 133 uintptr_t endAddr, VisitObjectArea area) override; 134 private: 135 SnapshotProcessor *processor_ {nullptr}; 136 uintptr_t snapshotObj_ {-1}; 137 CQueue<TaggedObject *> *queue_ {nullptr}; 138 std::unordered_map<uint64_t, ObjectEncode> *data_{nullptr}; 139 }; 140 141 class DeserializeFieldVisitor final : public BaseObjectVisitor<DeserializeFieldVisitor> { 142 public: 143 explicit DeserializeFieldVisitor(SnapshotProcessor *processor); 144 ~DeserializeFieldVisitor() override = default; 145 146 void VisitObjectRangeImpl(BaseObject *rootObject, uintptr_t startAddr, uintptr_t endAddr, 147 VisitObjectArea area) override; 148 private: 149 SnapshotProcessor *processor_ {nullptr}; 150 }; GetMarkGCBitSetSize()151 size_t GetMarkGCBitSetSize() const 152 { 153 return GCBitset::SizeOfGCBitset(DEFAULT_REGION_SIZE - 154 AlignUp(sizeof(Region), static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION))); 155 } 156 157 bool VisitObjectBodyWithRep(TaggedObject *root, ObjectSlot slot, uintptr_t obj, int index, VisitObjectArea area); 158 void SetObjectEncodeField(uintptr_t obj, size_t offset, uint64_t value); 159 160 EncodeBit SerializeObjectHeader(TaggedObject *objectHeader, size_t objectType, CQueue<TaggedObject *> *queue, 161 std::unordered_map<uint64_t, ObjectEncode> *data); 162 uint64_t SerializeTaggedField(JSTaggedType *tagged, CQueue<TaggedObject *> *queue, 163 std::unordered_map<uint64_t, ObjectEncode> *data); 164 void DeserializeField(TaggedObject *objectHeader); 165 void DeserializeTaggedField(uint64_t *value, TaggedObject *root); 166 void DeserializeNativePointer(uint64_t *value); 167 void DeserializeClassWord(TaggedObject *object); 168 void DeserializePandaMethod(uintptr_t begin, uintptr_t end, MethodLiteral *methods, 169 size_t &methodNums, size_t &others); 170 void DeserializeSpaceObject(uintptr_t beginAddr, size_t objSize, SerializedObjectSpace spaceType); 171 void DeserializeSpaceObject(uintptr_t beginAddr, Space* space, size_t spaceObjSize); 172 void DeserializeHugeSpaceObject(uintptr_t beginAddr, HugeObjectSpace* space, size_t hugeSpaceObjSize); 173 void HandleRootObject(SnapshotType type, uintptr_t rootObjectAddr, size_t objType, size_t &constSpecialIndex); 174 175 EncodeBit NativePointerToEncodeBit(void *nativePointer); 176 size_t SearchNativeMethodIndex(void *nativePointer); 177 uintptr_t TaggedObjectEncodeBitToAddr(EncodeBit taggedBit); 178 void WriteSpaceObjectToFile(Space* space, std::fstream &write); 179 void WriteHugeObjectToFile(HugeObjectSpace* space, std::fstream &writer); 180 size_t StatisticsSpaceObjectSize(Space* space); 181 size_t StatisticsHugeObjectSize(HugeObjectSpace* space); 182 uintptr_t AllocateObjectToLocalSpace(Space *space, size_t objectSize); 183 SnapshotRegionHeadInfo GenerateRegionHeadInfo(Region *region); 184 void ResetRegionUnusedRange(Region *region); 185 186 EcmaVM *vm_ {nullptr}; 187 SharedHeap* sHeap_ {nullptr}; 188 class RegionProxy { 189 public: 190 RegionProxy() = default; 191 ~RegionProxy() = default; 192 IsEmpty()193 bool IsEmpty() const 194 { 195 return begin_ == 0; 196 } 197 Allocate(size_t size)198 AllocResult Allocate(size_t size) 199 { 200 if (top_ + size <= end_) { 201 uintptr_t addr = top_; 202 top_ += size; 203 return {addr, addr - begin_, regionIndex_}; 204 } 205 return {0, 0, -1}; 206 } 207 Reset(uintptr_t begin,uintptr_t end,size_t regionIndex)208 void Reset(uintptr_t begin, uintptr_t end, size_t regionIndex) 209 { 210 begin_ = begin; 211 top_ = begin; 212 end_ = end; 213 regionIndex_ = regionIndex; 214 } 215 GetBegin()216 uintptr_t GetBegin() const 217 { 218 return begin_; 219 } 220 GetTop()221 uintptr_t GetTop() const 222 { 223 return top_; 224 } 225 GetEnd()226 uintptr_t GetEnd() const 227 { 228 return end_; 229 } 230 GetRegionIndex()231 size_t GetRegionIndex() const 232 { 233 return regionIndex_; 234 } 235 private: 236 uintptr_t begin_ {0}; 237 uintptr_t top_ {0}; 238 uintptr_t end_ {0}; 239 size_t regionIndex_ {-1}; 240 }; 241 242 class AllocateProxy { 243 public: AllocateProxy(SerializedObjectSpace spaceType)244 AllocateProxy(SerializedObjectSpace spaceType) : spaceType_(spaceType) {} ~AllocateProxy()245 ~AllocateProxy() 246 { 247 for (RegionProxy &proxy : regions_) { 248 ASSERT(!proxy.IsEmpty()); 249 void *ptr = reinterpret_cast<void*>(proxy.GetBegin()); 250 free(ptr); 251 } 252 } 253 254 void Initialize(size_t commonRegionSize); 255 256 AllocResult Allocate(size_t size, uintptr_t ®ionIndex); 257 258 void StopAllocate(SharedHeap *sHeap); 259 GetAllocatedSize()260 size_t GetAllocatedSize() const 261 { 262 return allocatedSize_; 263 } 264 265 void WriteToFile(std::fstream &writer); 266 private: 267 void AllocateNewRegion(size_t size, uintptr_t ®ionIndex); 268 std::vector<RegionProxy> regions_ {}; 269 RegionProxy currentRegion_ {}; 270 SerializedObjectSpace spaceType_ {SerializedObjectSpace::OTHER}; 271 size_t allocatedSize_ {0}; 272 size_t commonRegionSize_ {0}; 273 }; 274 AllocateProxy regularObjAllocator_ {SerializedObjectSpace::REGULAR_SPACE}; 275 AllocateProxy pinnedObjAllocator_ {SerializedObjectSpace::PIN_SPACE}; 276 AllocateProxy largeObjAllocator_ {SerializedObjectSpace::LARGE_SPACE}; 277 size_t commonRegionSize_ {0}; 278 LocalSpace *oldLocalSpace_ {nullptr}; 279 LocalSpace *nonMovableLocalSpace_ {nullptr}; 280 LocalSpace *machineCodeLocalSpace_ {nullptr}; 281 SnapshotSpace *snapshotLocalSpace_ {nullptr}; 282 HugeObjectSpace *hugeObjectLocalSpace_ {nullptr}; 283 bool programSerialize_ {false}; 284 bool builtinsSerialize_ {false}; 285 bool builtinsDeserialize_ {false}; 286 CVector<uintptr_t> pandaMethod_; 287 CVector<uintptr_t> stringVector_; 288 /** 289 * In deserialize, RuntimeLock for string table may cause a SharedGC, making strings just created invalid, 290 * so use handle to protect. 291 */ 292 CVector<JSHandle<EcmaString>> deserializeStringVector_; 293 std::unordered_map<size_t, uintptr_t> regionIndexMap_; 294 size_t regionIndex_ {0}; 295 bool isRootObjRelocate_ {false}; 296 JSTaggedValue root_ {JSTaggedValue::Hole()}; 297 std::vector<std::pair<uintptr_t, size_t>> regularRegions_ {}; 298 std::vector<std::pair<uintptr_t, size_t>> pinnedRegions_ {}; 299 std::vector<std::pair<uintptr_t, size_t>> largeRegions_ {}; 300 301 NO_COPY_SEMANTIC(SnapshotProcessor); 302 NO_MOVE_SEMANTIC(SnapshotProcessor); 303 }; 304 305 class SnapshotHelper { 306 public: 307 // when snapshot serialize, huge obj size is writed to region snapshotData_ high 32 bits EncodeHugeObjectSize(uint64_t objSize)308 static inline uint64_t EncodeHugeObjectSize(uint64_t objSize) 309 { 310 return objSize << Constants::UINT_32_BITS_COUNT; 311 } 312 313 // get huge object size which is saved in region snapshotData_ high 32 bits GetHugeObjectSize(uint64_t snapshotData)314 static inline size_t GetHugeObjectSize(uint64_t snapshotData) 315 { 316 return snapshotData >> Constants::UINT_32_BITS_COUNT; 317 } 318 319 // get huge object region index which is saved in region snapshotMark_ low 32 bits GetHugeObjectRegionIndex(uint64_t snapshotData)320 static inline size_t GetHugeObjectRegionIndex(uint64_t snapshotData) 321 { 322 return snapshotData & Constants::MAX_UINT_32; 323 } 324 }; 325 } // namespace panda::ecmascript 326 327 #endif // ECMASCRIPT_SNAPSHOT_MEM_SNAPSHOT_PROCESSOR_H 328