14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/snapshot/mem/snapshot.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include <cerrno> 194514f5e3Sopenharmony_ci 204514f5e3Sopenharmony_ci#include "ecmascript/compiler/pgo_type/pgo_type_manager.h" 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_cinamespace panda::ecmascript { 234514f5e3Sopenharmony_civoid Snapshot::Serialize(const CString &fileName) 244514f5e3Sopenharmony_ci{ 254514f5e3Sopenharmony_ci kungfu::AOTSnapshot &aotSnapshot = vm_->GetJSThread()->GetCurrentEcmaContext()->GetPTManager()->GetAOTSnapshot(); 264514f5e3Sopenharmony_ci JSTaggedValue root = aotSnapshot.GetSnapshotData(); 274514f5e3Sopenharmony_ci if (root == JSTaggedValue::Hole()) { 284514f5e3Sopenharmony_ci // root equals hole means no data stored. 294514f5e3Sopenharmony_ci LOG_COMPILER(ERROR) << "error: no data for ai file generation!"; 304514f5e3Sopenharmony_ci return; 314514f5e3Sopenharmony_ci } 324514f5e3Sopenharmony_ci Serialize(root.GetTaggedObject(), nullptr, fileName); 334514f5e3Sopenharmony_ci} 344514f5e3Sopenharmony_ci 354514f5e3Sopenharmony_civoid Snapshot::Serialize(TaggedObject *objectHeader, const JSPandaFile *jsPandaFile, const CString &fileName) 364514f5e3Sopenharmony_ci{ 374514f5e3Sopenharmony_ci std::string realPath; 384514f5e3Sopenharmony_ci if (!RealPath(std::string(fileName), realPath, false)) { 394514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "snapshot file path error"; 404514f5e3Sopenharmony_ci } 414514f5e3Sopenharmony_ci std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc); 424514f5e3Sopenharmony_ci if (!writer.good()) { 434514f5e3Sopenharmony_ci writer.close(); 444514f5e3Sopenharmony_ci LOG_FULL(ERROR) << "snapshot open file failed"; 454514f5e3Sopenharmony_ci return; 464514f5e3Sopenharmony_ci } 474514f5e3Sopenharmony_ci 484514f5e3Sopenharmony_ci SnapshotProcessor processor(vm_); 494514f5e3Sopenharmony_ci processor.Initialize(); 504514f5e3Sopenharmony_ci 514514f5e3Sopenharmony_ci std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data; 524514f5e3Sopenharmony_ci CQueue<TaggedObject *> objectQueue; 534514f5e3Sopenharmony_ci 544514f5e3Sopenharmony_ci if (objectHeader->GetClass()->GetObjectType() == JSType::PROGRAM) { 554514f5e3Sopenharmony_ci processor.SetProgramSerializeStart(); 564514f5e3Sopenharmony_ci } 574514f5e3Sopenharmony_ci 584514f5e3Sopenharmony_ci processor.EncodeTaggedObject(objectHeader, &objectQueue, &data); 594514f5e3Sopenharmony_ci size_t rootObjSize = objectQueue.size(); 604514f5e3Sopenharmony_ci processor.ProcessObjectQueue(&objectQueue, &data); 614514f5e3Sopenharmony_ci WriteToFile(writer, jsPandaFile, rootObjSize, processor); 624514f5e3Sopenharmony_ci} 634514f5e3Sopenharmony_ci 644514f5e3Sopenharmony_civoid Snapshot::Serialize(uintptr_t startAddr, size_t size, const CString &fileName) 654514f5e3Sopenharmony_ci{ 664514f5e3Sopenharmony_ci std::string realPath; 674514f5e3Sopenharmony_ci if (!RealPath(std::string(fileName), realPath, false)) { 684514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "snapshot file path error"; 694514f5e3Sopenharmony_ci } 704514f5e3Sopenharmony_ci std::fstream writer(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::trunc); 714514f5e3Sopenharmony_ci if (!writer.good()) { 724514f5e3Sopenharmony_ci writer.close(); 734514f5e3Sopenharmony_ci LOG_FULL(ERROR) << "snapshot open file failed"; 744514f5e3Sopenharmony_ci return; 754514f5e3Sopenharmony_ci } 764514f5e3Sopenharmony_ci 774514f5e3Sopenharmony_ci SnapshotProcessor processor(vm_); 784514f5e3Sopenharmony_ci processor.Initialize(); 794514f5e3Sopenharmony_ci 804514f5e3Sopenharmony_ci std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data; 814514f5e3Sopenharmony_ci CQueue<TaggedObject *> objectQueue; 824514f5e3Sopenharmony_ci 834514f5e3Sopenharmony_ci ObjectSlot start(startAddr); 844514f5e3Sopenharmony_ci ObjectSlot end(startAddr + size * sizeof(JSTaggedType)); 854514f5e3Sopenharmony_ci processor.EncodeTaggedObjectRange(start, end, &objectQueue, &data); 864514f5e3Sopenharmony_ci 874514f5e3Sopenharmony_ci size_t rootObjSize = objectQueue.size(); 884514f5e3Sopenharmony_ci processor.ProcessObjectQueue(&objectQueue, &data); 894514f5e3Sopenharmony_ci WriteToFile(writer, nullptr, rootObjSize, processor); 904514f5e3Sopenharmony_ci} 914514f5e3Sopenharmony_ci 924514f5e3Sopenharmony_civoid Snapshot::SerializeBuiltins(const CString &fileName) 934514f5e3Sopenharmony_ci{ 944514f5e3Sopenharmony_ci std::string realPath; 954514f5e3Sopenharmony_ci if (!RealPath(std::string(fileName), realPath, false)) { 964514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "snapshot file path error"; 974514f5e3Sopenharmony_ci } 984514f5e3Sopenharmony_ci std::fstream write(realPath.c_str(), std::ios::out | std::ios::binary | std::ios::app); 994514f5e3Sopenharmony_ci if (!write.good()) { 1004514f5e3Sopenharmony_ci write.close(); 1014514f5e3Sopenharmony_ci LOG_FULL(ERROR) << "snapshot open file failed"; 1024514f5e3Sopenharmony_ci return; 1034514f5e3Sopenharmony_ci } 1044514f5e3Sopenharmony_ci // if builtins.snapshot file has exist, return directly 1054514f5e3Sopenharmony_ci if (write.tellg()) { 1064514f5e3Sopenharmony_ci LOG_FULL(DEBUG) << "snapshot already exist"; 1074514f5e3Sopenharmony_ci write.close(); 1084514f5e3Sopenharmony_ci return; 1094514f5e3Sopenharmony_ci } 1104514f5e3Sopenharmony_ci 1114514f5e3Sopenharmony_ci SnapshotProcessor processor(vm_); 1124514f5e3Sopenharmony_ci processor.Initialize(); 1134514f5e3Sopenharmony_ci processor.SetBuiltinsSerializeStart(); 1144514f5e3Sopenharmony_ci 1154514f5e3Sopenharmony_ci std::unordered_map<uint64_t, std::pair<uint64_t, EncodeBit>> data; 1164514f5e3Sopenharmony_ci CQueue<TaggedObject *> objectQueue; 1174514f5e3Sopenharmony_ci 1184514f5e3Sopenharmony_ci auto globalEnvHandle = vm_->GetGlobalEnv(); 1194514f5e3Sopenharmony_ci auto constant = const_cast<GlobalEnvConstants *>(vm_->GetJSThread()->GlobalConstants()); 1204514f5e3Sopenharmony_ci constant->VisitRangeSlot([&objectQueue, &data, &processor]([[maybe_unused]] Root type, 1214514f5e3Sopenharmony_ci ObjectSlot start, ObjectSlot end) { 1224514f5e3Sopenharmony_ci processor.EncodeTaggedObjectRange(start, end, &objectQueue, &data); 1234514f5e3Sopenharmony_ci }); 1244514f5e3Sopenharmony_ci processor.EncodeTaggedObject(*globalEnvHandle, &objectQueue, &data); 1254514f5e3Sopenharmony_ci size_t rootObjSize = objectQueue.size(); 1264514f5e3Sopenharmony_ci processor.ProcessObjectQueue(&objectQueue, &data); 1274514f5e3Sopenharmony_ci WriteToFile(write, nullptr, rootObjSize, processor); 1284514f5e3Sopenharmony_ci} 1294514f5e3Sopenharmony_ci 1304514f5e3Sopenharmony_cibool Snapshot::DeserializeInternal(SnapshotType type, const CString &snapshotFile, SnapshotProcessor &processor, 1314514f5e3Sopenharmony_ci MemMap &fileMap) 1324514f5e3Sopenharmony_ci{ 1334514f5e3Sopenharmony_ci if (fileMap.GetOriginAddr() == nullptr) { 1344514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "file mmap failed"; 1354514f5e3Sopenharmony_ci UNREACHABLE(); 1364514f5e3Sopenharmony_ci } 1374514f5e3Sopenharmony_ci auto readFile = ToUintPtr(fileMap.GetOriginAddr()); 1384514f5e3Sopenharmony_ci auto hdr = *ToNativePtr<const SnapShotHeader>(readFile); 1394514f5e3Sopenharmony_ci if (!hdr.Verify(GetLastVersion())) { 1404514f5e3Sopenharmony_ci FileUnMap(fileMap); 1414514f5e3Sopenharmony_ci LOG_ECMA(ERROR) << "file verify failed."; 1424514f5e3Sopenharmony_ci return false; 1434514f5e3Sopenharmony_ci } 1444514f5e3Sopenharmony_ci uintptr_t oldSpaceBegin = readFile + sizeof(SnapShotHeader); 1454514f5e3Sopenharmony_ci uintptr_t stringBegin = oldSpaceBegin + hdr.oldSpaceObjSize + hdr.nonMovableObjSize + 1464514f5e3Sopenharmony_ci hdr.machineCodeObjSize + hdr.snapshotObjSize + hdr.hugeObjSize; 1474514f5e3Sopenharmony_ci uintptr_t stringEnd = stringBegin + hdr.stringSize; 1484514f5e3Sopenharmony_ci [[maybe_unused]] EcmaHandleScope stringHandleScope(vm_->GetJSThread()); 1494514f5e3Sopenharmony_ci processor.DeserializeString(stringBegin, stringEnd); 1504514f5e3Sopenharmony_ci 1514514f5e3Sopenharmony_ci processor.DeserializeObjectExcludeString(oldSpaceBegin, hdr.oldSpaceObjSize, hdr.nonMovableObjSize, 1524514f5e3Sopenharmony_ci hdr.machineCodeObjSize, hdr.snapshotObjSize, hdr.hugeObjSize); 1534514f5e3Sopenharmony_ci 1544514f5e3Sopenharmony_ci#if !defined(CROSS_PLATFORM) 1554514f5e3Sopenharmony_ci FileUnMap(MemMap(fileMap.GetOriginAddr(), hdr.pandaFileBegin)); 1564514f5e3Sopenharmony_ci#endif 1574514f5e3Sopenharmony_ci std::shared_ptr<JSPandaFile> jsPandaFile; 1584514f5e3Sopenharmony_ci if (static_cast<uint32_t>(fileMap.GetSize()) > hdr.pandaFileBegin) { 1594514f5e3Sopenharmony_ci uintptr_t pandaFileMem = readFile + hdr.pandaFileBegin; 1604514f5e3Sopenharmony_ci auto pf = panda_file::File::OpenFromMemory(os::mem::ConstBytePtr(ToNativePtr<std::byte>(pandaFileMem), 1614514f5e3Sopenharmony_ci static_cast<uint32_t>(fileMap.GetSize()) - hdr.pandaFileBegin, os::mem::MmapDeleter)); 1624514f5e3Sopenharmony_ci jsPandaFile = JSPandaFileManager::GetInstance()->NewJSPandaFile(pf.release(), ""); 1634514f5e3Sopenharmony_ci } 1644514f5e3Sopenharmony_ci // relocate object field 1654514f5e3Sopenharmony_ci processor.Relocate(type, jsPandaFile.get(), hdr.rootObjectSize); 1664514f5e3Sopenharmony_ci processor.AddRootObjectToAOTFileManager(type, snapshotFile); 1674514f5e3Sopenharmony_ci LOG_COMPILER(INFO) << "loaded ai file: " << snapshotFile.c_str(); 1684514f5e3Sopenharmony_ci return true; 1694514f5e3Sopenharmony_ci} 1704514f5e3Sopenharmony_ci 1714514f5e3Sopenharmony_cibool Snapshot::Deserialize(SnapshotType type, const CString &snapshotFile, bool isBuiltins) 1724514f5e3Sopenharmony_ci{ 1734514f5e3Sopenharmony_ci std::string realPath; 1744514f5e3Sopenharmony_ci if (!RealPath(std::string(snapshotFile), realPath, false)) { 1754514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "snapshot file path error"; 1764514f5e3Sopenharmony_ci UNREACHABLE(); 1774514f5e3Sopenharmony_ci } 1784514f5e3Sopenharmony_ci 1794514f5e3Sopenharmony_ci std::ifstream file(realPath); 1804514f5e3Sopenharmony_ci if (!file.good()) { 1814514f5e3Sopenharmony_ci return false; 1824514f5e3Sopenharmony_ci } 1834514f5e3Sopenharmony_ci file.close(); 1844514f5e3Sopenharmony_ci 1854514f5e3Sopenharmony_ci SnapshotProcessor processor(vm_); 1864514f5e3Sopenharmony_ci if (isBuiltins) { 1874514f5e3Sopenharmony_ci processor.SetBuiltinsDeserializeStart(); 1884514f5e3Sopenharmony_ci } 1894514f5e3Sopenharmony_ci 1904514f5e3Sopenharmony_ci MemMap fileMap = FileMap(realPath.c_str(), FILE_RDONLY, PAGE_PROT_READWRITE); 1914514f5e3Sopenharmony_ci return DeserializeInternal(type, snapshotFile, processor, fileMap); 1924514f5e3Sopenharmony_ci} 1934514f5e3Sopenharmony_ci 1944514f5e3Sopenharmony_ci#if defined(CROSS_PLATFORM) && defined(ANDROID_PLATFORM) 1954514f5e3Sopenharmony_cibool Snapshot::Deserialize(SnapshotType type, const CString &snapshotFile, [[maybe_unused]] std::function<bool 1964514f5e3Sopenharmony_ci (std::string fileName, uint8_t **buff, size_t *buffSize)> ReadAOTCallBack, bool isBuiltins) 1974514f5e3Sopenharmony_ci{ 1984514f5e3Sopenharmony_ci SnapshotProcessor processor(vm_); 1994514f5e3Sopenharmony_ci if (isBuiltins) { 2004514f5e3Sopenharmony_ci processor.SetBuiltinsDeserializeStart(); 2014514f5e3Sopenharmony_ci } 2024514f5e3Sopenharmony_ci 2034514f5e3Sopenharmony_ci std::string fileName = std::string(snapshotFile); 2044514f5e3Sopenharmony_ci uint8_t *buff = nullptr; 2054514f5e3Sopenharmony_ci size_t buffSize = 0; 2064514f5e3Sopenharmony_ci MemMap fileMap = {}; 2074514f5e3Sopenharmony_ci size_t found = fileName.find_last_of("/"); 2084514f5e3Sopenharmony_ci if (found != std::string::npos) { 2094514f5e3Sopenharmony_ci fileName = fileName.substr(found + 1); 2104514f5e3Sopenharmony_ci } 2114514f5e3Sopenharmony_ci 2124514f5e3Sopenharmony_ci LOG_ECMA(INFO) << "Call JsAotReader to load: " << fileName; 2134514f5e3Sopenharmony_ci if (ReadAOTCallBack(fileName, &buff, &buffSize)) { 2144514f5e3Sopenharmony_ci fileMap = MemMap(buff, buffSize); 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci 2174514f5e3Sopenharmony_ci return DeserializeInternal(type, snapshotFile, processor, fileMap); 2184514f5e3Sopenharmony_ci} 2194514f5e3Sopenharmony_ci#endif 2204514f5e3Sopenharmony_ci 2214514f5e3Sopenharmony_cisize_t Snapshot::AlignUpPageSize(size_t spaceSize) 2224514f5e3Sopenharmony_ci{ 2234514f5e3Sopenharmony_ci if (spaceSize % Constants::PAGE_SIZE_ALIGN_UP == 0) { 2244514f5e3Sopenharmony_ci return spaceSize; 2254514f5e3Sopenharmony_ci } 2264514f5e3Sopenharmony_ci return Constants::PAGE_SIZE_ALIGN_UP * (spaceSize / Constants::PAGE_SIZE_ALIGN_UP + 1); 2274514f5e3Sopenharmony_ci} 2284514f5e3Sopenharmony_ci 2294514f5e3Sopenharmony_civoid Snapshot::WriteToFile(std::fstream &writer, const JSPandaFile *jsPandaFile, 2304514f5e3Sopenharmony_ci size_t size, SnapshotProcessor &processor) 2314514f5e3Sopenharmony_ci{ 2324514f5e3Sopenharmony_ci uint32_t totalStringSize = 0U; 2334514f5e3Sopenharmony_ci CVector<uintptr_t> stringVector = processor.GetStringVector(); 2344514f5e3Sopenharmony_ci for (size_t i = 0; i < stringVector.size(); ++i) { 2354514f5e3Sopenharmony_ci auto str = reinterpret_cast<EcmaString *>(stringVector[i]); 2364514f5e3Sopenharmony_ci size_t objectSize = AlignUp(EcmaStringAccessor(str).ObjectSize(), 2374514f5e3Sopenharmony_ci static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 2384514f5e3Sopenharmony_ci totalStringSize += objectSize; 2394514f5e3Sopenharmony_ci } 2404514f5e3Sopenharmony_ci 2414514f5e3Sopenharmony_ci std::vector<uint32_t> objSizeVector = processor.StatisticsObjectSize(); 2424514f5e3Sopenharmony_ci size_t totalObjSize = totalStringSize; 2434514f5e3Sopenharmony_ci for (uint32_t objSize : objSizeVector) { 2444514f5e3Sopenharmony_ci totalObjSize += objSize; 2454514f5e3Sopenharmony_ci } 2464514f5e3Sopenharmony_ci uint32_t pandaFileBegin = RoundUp(totalObjSize + sizeof(SnapShotHeader), Constants::PAGE_SIZE_ALIGN_UP); 2474514f5e3Sopenharmony_ci SnapShotHeader hdr(GetLastVersion()); 2484514f5e3Sopenharmony_ci hdr.oldSpaceObjSize = objSizeVector[0]; // 0: oldSpaceObj 2494514f5e3Sopenharmony_ci hdr.nonMovableObjSize = objSizeVector[1]; // 1: nonMovableObj 2504514f5e3Sopenharmony_ci hdr.machineCodeObjSize = objSizeVector[2]; // 2: machineCodeObj 2514514f5e3Sopenharmony_ci hdr.snapshotObjSize = objSizeVector[3]; // 3: snapshotObj 2524514f5e3Sopenharmony_ci hdr.hugeObjSize = objSizeVector[4]; // 4: hugeObj 2534514f5e3Sopenharmony_ci hdr.stringSize = totalStringSize; 2544514f5e3Sopenharmony_ci hdr.pandaFileBegin = pandaFileBegin; 2554514f5e3Sopenharmony_ci hdr.rootObjectSize = static_cast<uint32_t>(size); 2564514f5e3Sopenharmony_ci writer.write(reinterpret_cast<char *>(&hdr), sizeof(hdr)); 2574514f5e3Sopenharmony_ci processor.WriteObjectToFile(writer); 2584514f5e3Sopenharmony_ci 2594514f5e3Sopenharmony_ci for (size_t i = 0; i < stringVector.size(); ++i) { 2604514f5e3Sopenharmony_ci auto str = reinterpret_cast<EcmaString *>(stringVector[i]); 2614514f5e3Sopenharmony_ci size_t strSize = AlignUp(EcmaStringAccessor(str).ObjectSize(), 2624514f5e3Sopenharmony_ci static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT)); 2634514f5e3Sopenharmony_ci int index = 0; // 0 represents the line string. Natural number 1 represents the constant string. 2644514f5e3Sopenharmony_ci if (EcmaStringAccessor(str).IsConstantString()) { 2654514f5e3Sopenharmony_ci index = 1; 2664514f5e3Sopenharmony_ci } 2674514f5e3Sopenharmony_ci // Write the index in the head of string. 2684514f5e3Sopenharmony_ci uint8_t headerSize = JSTaggedValue::TaggedTypeSize(); 2694514f5e3Sopenharmony_ci JSTaggedType indexHeader = JSTaggedValue(index).GetRawData(); 2704514f5e3Sopenharmony_ci writer.write(reinterpret_cast<char *>(&indexHeader), headerSize); 2714514f5e3Sopenharmony_ci writer.write(reinterpret_cast<char *>(str) + headerSize, strSize - headerSize); 2724514f5e3Sopenharmony_ci writer.flush(); 2734514f5e3Sopenharmony_ci } 2744514f5e3Sopenharmony_ci 2754514f5e3Sopenharmony_ci ASSERT(static_cast<size_t>(writer.tellp()) == totalObjSize + sizeof(SnapShotHeader)); 2764514f5e3Sopenharmony_ci if (jsPandaFile) { 2774514f5e3Sopenharmony_ci writer.seekp(pandaFileBegin); 2784514f5e3Sopenharmony_ci writer.write(static_cast<const char *>(jsPandaFile->GetHeader()), jsPandaFile->GetFileSize()); 2794514f5e3Sopenharmony_ci } 2804514f5e3Sopenharmony_ci writer.close(); 2814514f5e3Sopenharmony_ci} 2824514f5e3Sopenharmony_ci} // namespace panda::ecmascript 283