1 /*
2 * Copyright (c) 2022 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/jspandafile/js_pandafile_manager.h"
17 #include "ecmascript/jspandafile/program_object-inl.h"
18
19 namespace panda::ecmascript {
20 static const size_t MALLOC_SIZE_LIMIT = 2147483648; // Max internal memory used by the VM declared in options
21
~JSPandaFileManager()22 JSPandaFileManager::~JSPandaFileManager()
23 {
24 os::memory::LockHolder lock(jsPandaFileLock_);
25 auto iter = loadedJSPandaFiles_.begin();
26 while (iter != loadedJSPandaFiles_.end()) {
27 const JSPandaFile *jsPandaFile = iter->first;
28 ReleaseJSPandaFile(jsPandaFile);
29 iter = loadedJSPandaFiles_.erase(iter);
30 }
31 }
32
LoadPfAbc(const std::string & filename)33 const JSPandaFile *JSPandaFileManager::LoadPfAbc(const std::string &filename)
34 {
35 ECMA_BYTRACE_NAME(BYTRACE_TAG_ARK, "JSPandaFileManager::LoadJSPandaFile");
36 CString desc = ConvertToString(filename);
37 {
38 os::memory::LockHolder lock(jsPandaFileLock_);
39 const JSPandaFile *jsPandaFile = FindJSPandaFileUnlocked(desc);
40 if (jsPandaFile != nullptr) {
41 IncreaseRefJSPandaFileUnlocked(jsPandaFile);
42 return jsPandaFile;
43 }
44 }
45
46 auto pf = panda_file::OpenPandaFileOrZip(filename, panda_file::File::READ_WRITE);
47 if (pf == nullptr) {
48 LOG_ECMA(ERROR) << "open file " << filename << " error";
49 return nullptr;
50 }
51
52 return CreateJSPandaFile(pf.release(), desc);
53 }
54
LoadBufferAbc(const std::string & filename,const void * buffer,size_t size)55 const JSPandaFile *JSPandaFileManager::LoadBufferAbc(const std::string &filename, const void *buffer, size_t size)
56 {
57 if (buffer == nullptr || size == 0) {
58 return nullptr;
59 }
60
61 CString desc = ConvertToString(filename);
62 {
63 os::memory::LockHolder lock(jsPandaFileLock_);
64 const JSPandaFile *jsPandaFile = FindJSPandaFileUnlocked(desc);
65 if (jsPandaFile != nullptr) {
66 IncreaseRefJSPandaFileUnlocked(jsPandaFile);
67 return jsPandaFile;
68 }
69 }
70
71 auto pf = panda_file::OpenPandaFileFromMemory(buffer, size);
72 if (pf == nullptr) {
73 return nullptr;
74 }
75 return CreateJSPandaFile(pf.release(), desc);
76 }
77
GenerateProgram(EcmaVM * vm,const JSPandaFile * jsPandaFile)78 JSHandle<Program> JSPandaFileManager::GenerateProgram(EcmaVM *vm, const JSPandaFile *jsPandaFile)
79 {
80 ECMA_BYTRACE_NAME(BYTRACE_TAG_ARK, "JSPandaFileManager::GenerateProgram");
81 LOG_ECMA(INFO) << "GenerateProgram " << jsPandaFile->GetPandaFile()->GetFilename();
82 ASSERT(GetJSPandaFile(jsPandaFile->GetPandaFile()) != nullptr);
83
84 PandaFileTranslator translator(vm, jsPandaFile);
85 auto result = translator.GenerateProgram();
86 JSThread *thread = vm->GetJSThread();
87 return JSHandle<Program>(thread, result);
88 }
89
FindJSPandaFileUnlocked(const CString & filename)90 const JSPandaFile *JSPandaFileManager::FindJSPandaFileUnlocked(const CString &filename)
91 {
92 if (filename.empty()) {
93 return nullptr;
94 }
95 for (const auto &iter : loadedJSPandaFiles_) {
96 const JSPandaFile *pf = iter.first;
97 if (pf->GetJSPandaFileDesc() == filename) {
98 return pf;
99 }
100 }
101 return nullptr;
102 }
103
GetJSPandaFile(const panda_file::File * pf)104 const JSPandaFile *JSPandaFileManager::GetJSPandaFile(const panda_file::File *pf)
105 {
106 os::memory::LockHolder lock(jsPandaFileLock_);
107 for (const auto &iter : loadedJSPandaFiles_) {
108 const JSPandaFile *jsPandafile = iter.first;
109 if (jsPandafile->GetPandaFile() == pf) {
110 return jsPandafile;
111 }
112 }
113 return nullptr;
114 }
115
InsertJSPandaFile(const JSPandaFile * jsPandaFile)116 void JSPandaFileManager::InsertJSPandaFile(const JSPandaFile *jsPandaFile)
117 {
118 LOG_ECMA(INFO) << "InsertJSPandaFile " << jsPandaFile->GetPandaFile()->GetFilename();
119
120 os::memory::LockHolder lock(jsPandaFileLock_);
121 ASSERT(loadedJSPandaFiles_.find(jsPandaFile) == loadedJSPandaFiles_.end());
122 loadedJSPandaFiles_[jsPandaFile] = 1;
123 }
124
IncreaseRefJSPandaFileUnlocked(const JSPandaFile * jsPandaFile)125 void JSPandaFileManager::IncreaseRefJSPandaFileUnlocked(const JSPandaFile *jsPandaFile)
126 {
127 LOG_ECMA(INFO) << "IncreaseRefJSPandaFile " << jsPandaFile->GetPandaFile()->GetFilename();
128
129 ASSERT(loadedJSPandaFiles_.find(jsPandaFile) != loadedJSPandaFiles_.end());
130 loadedJSPandaFiles_[jsPandaFile]++;
131 }
132
DecreaseRefJSPandaFile(const JSPandaFile * jsPandaFile)133 void JSPandaFileManager::DecreaseRefJSPandaFile(const JSPandaFile *jsPandaFile)
134 {
135 LOG_ECMA(INFO) << "DecreaseRefJSPandaFile " << jsPandaFile->GetPandaFile()->GetFilename();
136
137 os::memory::LockHolder lock(jsPandaFileLock_);
138 auto iter = loadedJSPandaFiles_.find(jsPandaFile);
139 if (iter != loadedJSPandaFiles_.end()) {
140 if (iter->second > 1) {
141 iter->second--;
142 return;
143 }
144 loadedJSPandaFiles_.erase(iter);
145 }
146 ReleaseJSPandaFile(jsPandaFile);
147 }
148
ReleaseJSPandaFile(const JSPandaFile * jsPandaFile)149 void JSPandaFileManager::ReleaseJSPandaFile(const JSPandaFile *jsPandaFile)
150 {
151 if (jsPandaFile == nullptr) {
152 return;
153 }
154 LOG_ECMA(INFO) << "ReleaseJSPandaFile " << jsPandaFile->GetPandaFile()->GetFilename();
155 delete jsPandaFile;
156 }
157
GetJSPtExtractor(const JSPandaFile * pf)158 tooling::JSPtExtractor *JSPandaFileManager::GetJSPtExtractor(const JSPandaFile *pf)
159 {
160 if (pf == nullptr) {
161 return nullptr;
162 }
163 return const_cast<JSPandaFile *>(pf)->GetJSPtExtractor();
164 }
165
CreateJSPandaFile(const panda_file::File * pf,const CString & desc)166 const JSPandaFile *JSPandaFileManager::CreateJSPandaFile(const panda_file::File *pf, const CString &desc)
167 {
168 ASSERT(GetJSPandaFile(pf) == nullptr);
169
170 JSPandaFile *newJsPandaFile = new JSPandaFile(pf, desc);
171 PandaFileTranslator::TranslateClasses(newJsPandaFile, ENTRY_FUNCTION_NAME);
172
173 {
174 os::memory::LockHolder lock(jsPandaFileLock_);
175 const JSPandaFile *jsPandaFile = FindJSPandaFileUnlocked(desc);
176 if (jsPandaFile != nullptr) {
177 IncreaseRefJSPandaFileUnlocked(jsPandaFile);
178 ReleaseJSPandaFile(newJsPandaFile);
179 return jsPandaFile;
180 }
181 InsertJSPandaFile(newJsPandaFile);
182 }
183
184 return newJsPandaFile;
185 }
186
AllocateBuffer(size_t size)187 void *JSPandaFileManager::AllocateBuffer(size_t size)
188 {
189 return JSPandaFileAllocator::AllocateBuffer(size);
190 }
191
AllocateBuffer(size_t size)192 void *JSPandaFileManager::JSPandaFileAllocator::AllocateBuffer(size_t size)
193 {
194 if (size == 0) {
195 LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0";
196 UNREACHABLE();
197 }
198 if (size >= MALLOC_SIZE_LIMIT) {
199 LOG_ECMA_MEM(FATAL) << "size must be less than the maximum";
200 UNREACHABLE();
201 }
202 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
203 void *ptr = malloc(size);
204 if (ptr == nullptr) {
205 LOG_ECMA_MEM(FATAL) << "malloc failed";
206 UNREACHABLE();
207 }
208 #if ECMASCRIPT_ENABLE_ZAP_MEM
209 if (memset_s(ptr, size, INVALID_VALUE, size) != EOK) {
210 LOG_ECMA_MEM(FATAL) << "memset failed";
211 UNREACHABLE();
212 }
213 #endif
214 return ptr;
215 }
216
FreeBuffer(void * mem)217 void JSPandaFileManager::FreeBuffer(void *mem)
218 {
219 JSPandaFileAllocator::FreeBuffer(mem);
220 }
221
FreeBuffer(void * mem)222 void JSPandaFileManager::JSPandaFileAllocator::FreeBuffer(void *mem)
223 {
224 if (mem == nullptr) {
225 return;
226 }
227 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
228 free(mem);
229 }
230
RemoveJSPandaFile(void * pointer,void * data)231 void JSPandaFileManager::RemoveJSPandaFile(void *pointer, void *data)
232 {
233 if (pointer == nullptr || data == nullptr) {
234 return;
235 }
236 auto jsPandaFile = reinterpret_cast<JSPandaFile *>(pointer);
237 LOG_ECMA(INFO) << "RemoveJSPandaFile " << jsPandaFile->GetPandaFile()->GetFilename();
238 // dec ref in filemanager
239 JSPandaFileManager *jsPandaFileManager = static_cast<JSPandaFileManager *>(data);
240 jsPandaFileManager->DecreaseRefJSPandaFile(jsPandaFile);
241 }
242 } // namespace panda::ecmascript
243