• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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/snapshot/mem/snapshot.h"
17 
18 #include <cerrno>
19 #include <fcntl.h>
20 #include <sys/mman.h>
21 #include <unistd.h>
22 
23 #include "ecmascript/jspandafile/program_object.h"
24 #include "ecmascript/ecma_vm.h"
25 #include "ecmascript/global_env.h"
26 #include "ecmascript/jobs/micro_job_queue.h"
27 #include "ecmascript/js_hclass.h"
28 #include "ecmascript/js_thread.h"
29 #include "ecmascript/mem/c_containers.h"
30 #include "ecmascript/mem/heap.h"
31 #include "ecmascript/object_factory.h"
32 #include "ecmascript/snapshot/mem/snapshot_serialize.h"
33 #include "libpandabase/mem/mem.h"
34 
35 namespace panda::ecmascript {
36 constexpr uint32_t PANDA_FILE_ALIGNMENT = 4096;
37 
MakeSnapShotProgramObject(Program * program,const panda_file::File * pf,const CString & fileName)38 void SnapShot::MakeSnapShotProgramObject(Program *program, const panda_file::File *pf, const CString &fileName)
39 {
40     std::fstream write;
41     std::pair<bool, CString> filePath = VerifyFilePath(fileName);
42     if (!filePath.first) {
43         LOG(ERROR, RUNTIME) << "snapshot file path error";
44         return;
45     }
46     write.open(filePath.second.c_str(), std::ios::out | std::ios::binary | std::ios::trunc);
47     if (!write.good()) {
48         LOG(DEBUG, RUNTIME) << "snapshot open file failed";
49         return;
50     }
51 
52     SnapShotSerialize serialize(vm_, true);
53 
54     std::unordered_map<uint64_t, SlotBit> data;
55     CQueue<TaggedObject *> objectQueue;
56 
57     serialize.RegisterNativeMethod();
58 
59     // handle GlobalEnvConstants
60     auto constant = const_cast<GlobalEnvConstants *>(vm_->GetJSThread()->GlobalConstants());
61     constant->VisitRangeSlot([&objectQueue, &data](Root type, ObjectSlot start, ObjectSlot end) {
62         SerializeHelper::AddTaggedObjectRangeToData(start, end, &objectQueue, &data);
63     });
64 
65     vm_->Iterate([&objectQueue, &data](Root type, ObjectSlot object) {
66         SerializeHelper::AddObjectHeaderToData(object.GetTaggedObjectHeader(), &objectQueue, &data);
67     });
68 
69     while (!objectQueue.empty()) {
70         auto taggedObject = objectQueue.front();
71         if (taggedObject == nullptr) {
72             break;
73         }
74         objectQueue.pop();
75 
76         serialize.Serialize(taggedObject, &objectQueue, &data);
77     }
78 
79     serialize.SetProgramSerializeStart();
80 
81     // handle program
82     if (program != nullptr) {
83         SerializeHelper::AddObjectHeaderToData(program, &objectQueue, &data);
84     }
85 
86     while (!objectQueue.empty()) {
87         auto taggedObject = objectQueue.front();
88         if (taggedObject == nullptr) {
89             break;
90         }
91         objectQueue.pop();
92         serialize.Serialize(taggedObject, &objectQueue, &data);
93     }
94 
95     serialize.SerializePandaFileMethod();
96 
97     vm_->GetHeap()->GetSnapShotSpace()->Stop();
98 
99     // write to file
100     SnapShotSpace *space = vm_->GetHeap()->GetSnapShotSpace();
101     size_t defaultSnapshotSpaceCapacity = vm_->GetJSOptions().DefaultSnapshotSpaceCapacity();
102     uint32_t snapshot_size = space->GetRegionCount() * defaultSnapshotSpaceCapacity;
103     uint32_t panda_file_begin = RoundUp(snapshot_size + sizeof(Header), PANDA_FILE_ALIGNMENT);
104     Header hdr {snapshot_size, panda_file_begin};
105     write.write(reinterpret_cast<char *>(&hdr), sizeof(hdr));
106 
107     space->EnumerateRegions([&write, &defaultSnapshotSpaceCapacity](Region *current) {
108         write.write(reinterpret_cast<char *>(current), defaultSnapshotSpaceCapacity);
109         write.flush();
110     });
111     space->ReclaimRegions();
112     ASSERT(static_cast<size_t>(write.tellp()) == snapshot_size + sizeof(Header));
113 
114     write.seekp(panda_file_begin);
115     write.write(reinterpret_cast<const char *>(pf->GetBase()), pf->GetHeader()->file_size);
116     write.close();
117 }
118 
DeserializeGlobalEnvAndProgram(const CString & fileName)119 std::unique_ptr<const panda_file::File> SnapShot::DeserializeGlobalEnvAndProgram(const CString &fileName)
120 {
121     SnapShotSerialize serialize(vm_, false);
122 
123     serialize.GeneratedNativeMethod();
124 
125     std::pair<bool, CString> filePath = VerifyFilePath(fileName);
126     if (!filePath.first) {
127         LOG(ERROR, RUNTIME) << "snapshot file path error";
128         return std::unique_ptr<const panda_file::File>();
129     }
130 
131     int fd = open(filePath.second.c_str(), O_CLOEXEC);  // NOLINT(cppcoreguidelines-pro-type-vararg)
132     if (UNLIKELY(fd == -1)) {
133         LOG_ECMA(FATAL) << "open file failed";
134         UNREACHABLE();
135     }
136     size_t file_size = lseek(fd, 0, SEEK_END);
137     auto readFile = ToUintPtr(mmap(nullptr, file_size, PROT_READ, MAP_PRIVATE, fd, 0));
138     auto hdr = *ToNativePtr<const Header>(readFile);
139     size_t defaultSnapshotSpaceCapacity = vm_->GetJSOptions().DefaultSnapshotSpaceCapacity();
140     if (hdr.snapshot_size % defaultSnapshotSpaceCapacity != 0) {
141         LOG_ECMA(FATAL) << "Invalid snapshot file";
142         UNREACHABLE();
143     }
144     SnapShotSpace *space = vm_->GetHeap()->GetSnapShotSpace();
145 
146     uintptr_t snapshot_begin = readFile + sizeof(Header);
147     for (size_t i = 0; i < hdr.snapshot_size / defaultSnapshotSpaceCapacity; i++) {
148         Region *region = const_cast<HeapRegionAllocator *>(vm_->GetHeap()->GetHeapRegionAllocator())
149                             ->AllocateAlignedRegion(space, defaultSnapshotSpaceCapacity);
150         auto fileRegion = ToNativePtr<Region>(snapshot_begin + i * defaultSnapshotSpaceCapacity);
151 
152         uint64_t base = region->allocateBase_;
153         uint64_t begin = (fileRegion->begin_) % defaultSnapshotSpaceCapacity;
154         uint64_t waterMark = (fileRegion->highWaterMark_) % defaultSnapshotSpaceCapacity;
155 
156         if (memcpy_s(region, defaultSnapshotSpaceCapacity, fileRegion, defaultSnapshotSpaceCapacity) != EOK) {
157             LOG_ECMA(FATAL) << "memcpy_s failed";
158             UNREACHABLE();
159         }
160 
161         // allocate_base_
162         region->allocateBase_ = base;
163         // begin_
164         region->begin_ = ToUintPtr(region) + begin;
165         // end_
166         region->end_ = ToUintPtr(region) + defaultSnapshotSpaceCapacity;
167         // high_water_mark_
168         region->highWaterMark_ = ToUintPtr(region) + waterMark;
169         // prev_
170         region->prev_ = nullptr;
171         // next_
172         region->next_ = nullptr;
173         // mark_bitmap_
174         region->markBitmap_ = nullptr;
175         // cross_region_set_
176         region->crossRegionSet_ = nullptr;
177         // old_to_new_set_
178         region->oldToNewSet_ = nullptr;
179 
180         space->AddRegion(region);
181     }
182     munmap(ToNativePtr<void>(readFile), hdr.panda_file_begin);
183     uintptr_t panda_file_mem = readFile + hdr.panda_file_begin;
184     auto pf =
185         panda_file::File::OpenFromMemory(os::mem::ConstBytePtr(ToNativePtr<std::byte>(panda_file_mem),
186                                                                file_size - hdr.panda_file_begin, os::mem::MmapDeleter),
187                                          fileName);
188     close(fd);
189     // redirect object field
190     serialize.RedirectSlot(pf.get());
191     return pf;
192 }
193 
AlignUpPageSize(size_t spaceSize)194 size_t SnapShot::AlignUpPageSize(size_t spaceSize)
195 {
196     if (spaceSize % PAGE_SIZE_ALIGN_UP == 0) {
197         return spaceSize;
198     }
199     return PAGE_SIZE_ALIGN_UP * (spaceSize / PAGE_SIZE_ALIGN_UP + 1);
200 }
201 
VerifyFilePath(const CString & filePath)202 std::pair<bool, CString> SnapShot::VerifyFilePath(const CString &filePath)
203 {
204     if (filePath.size() > PATH_MAX) {
205         return std::make_pair(false, "");
206     }
207     CVector<char> resolvedPath(PATH_MAX);
208     auto result = realpath(filePath.c_str(), resolvedPath.data());
209     if (result == resolvedPath.data() || errno == ENOENT) {
210         return std::make_pair(true, CString(resolvedPath.data()));
211     }
212     return std::make_pair(false, "");
213 }
214 }  // namespace panda::ecmascript
215