• 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/napi/include/dfx_jsnapi.h"
17 
18 #include "ecmascript/base/block_hook_scope.h"
19 #include "ecmascript/dfx/hprof/heap_profiler.h"
20 #include "ecmascript/dfx/stackinfo/js_stackinfo.h"
21 #include "ecmascript/ecma_vm.h"
22 #include "ecmascript/mem/c_string.h"
23 #include "ecmascript/mem/heap-inl.h"
24 #include "ecmascript/mem/gc_stats.h"
25 #include "ecmascript/dfx/hprof/file_stream.h"
26 
27 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
28 #include "ecmascript/dfx/cpu_profiler/cpu_profiler.h"
29 #include "ecmascript/dfx/cpu_profiler/samples_record.h"
30 #endif
31 #if defined(ENABLE_DUMP_IN_FAULTLOG)
32 #include "include/faultloggerd_client.h"
33 #endif
34 
35 namespace panda {
36 using ecmascript::CString;
37 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
38 using ecmascript::CpuProfiler;
39 #endif
40 using ecmascript::EcmaString;
41 using ecmascript::JSTaggedValue;
42 using ecmascript::GCStats;
43 template<typename T>
44 using JSHandle = ecmascript::JSHandle<T>;
45 using ecmascript::FileStream;
46 using ecmascript::FileDescriptorStream;
47 using ecmascript::Stream;
48 using ecmascript::CMap;
49 
DumpHeapSnapshot(const EcmaVM * vm,int dumpFormat,const std::string & path,bool isVmMode,bool isPrivate)50 void DFXJSNApi::DumpHeapSnapshot(const EcmaVM *vm, int dumpFormat,
51                                  const std::string &path, bool isVmMode, bool isPrivate)
52 {
53     FileStream stream(path);
54     DumpHeapSnapshot(vm, dumpFormat, &stream, nullptr, isVmMode, isPrivate);
55 }
56 
DumpHeapSnapshot(const EcmaVM * vm,int dumpFormat,Stream * stream,Progress * progress,bool isVmMode,bool isPrivate)57 void DFXJSNApi::DumpHeapSnapshot(const EcmaVM *vm, int dumpFormat, Stream *stream, Progress *progress,
58                                  bool isVmMode, bool isPrivate)
59 {
60     ecmascript::base::BlockHookScope blockScope;
61     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
62         const_cast<EcmaVM *>(vm));
63     heapProfile->DumpHeapSnapshot(ecmascript::DumpFormat(dumpFormat), stream, progress, isVmMode, isPrivate);
64     ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm));
65 }
66 
DumpHeapSnapshot(const EcmaVM * vm,int dumpFormat,bool isVmMode,bool isPrivate)67 void DFXJSNApi::DumpHeapSnapshot([[maybe_unused]] const EcmaVM *vm, [[maybe_unused]] int dumpFormat,
68                                  [[maybe_unused]] bool isVmMode, [[maybe_unused]] bool isPrivate)
69 {
70 #if defined(ENABLE_DUMP_IN_FAULTLOG)
71 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
72     DFXJSNApi::StopCpuProfilerForFile(vm);
73 #endif
74     auto &options = const_cast<EcmaVM *>(vm)->GetJSOptions();
75     options.SwitchStartGlobalLeakCheck();
76     if (options.EnableGlobalLeakCheck() && options.IsStartGlobalLeakCheck()) {
77         int32_t stackTraceFd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_STACKTRACE));
78         if (stackTraceFd < 0) {
79             options.SwitchStartGlobalLeakCheck();
80         } else {
81             vm->GetJSThread()->SetStackTraceFd(stackTraceFd);
82         }
83     }
84     // Write in faultlog for heap leak.
85     int32_t fd = RequestFileDescriptor(static_cast<int32_t>(FaultLoggerType::JS_HEAP_SNAPSHOT));
86     if (fd < 0) {
87         LOG_ECMA(ERROR) << "Write FD failed, fd" << fd;
88         return;
89     }
90     FileDescriptorStream stream(fd);
91     DumpHeapSnapshot(vm, dumpFormat, &stream, nullptr, isVmMode, isPrivate);
92 #endif
93 }
94 
BuildNativeAndJsStackTrace(const EcmaVM * vm,std::string & stackTraceStr)95 bool DFXJSNApi::BuildNativeAndJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr)
96 {
97     LOG_ECMA(INFO) <<"BuildJsStackInfoList start";
98     std::vector<JsFrameInfo> jf = ecmascript::JsStackInfo::BuildJsStackInfo(vm->GetAssociatedJSThread());
99     LOG_ECMA(INFO) <<"BuildJsStackInfoList JsFrameInfo";
100     for (uint32_t i = 0; i < jf.size(); ++i) {
101         std::string functionname = jf[i].functionName;
102         std::string filename = jf[i].fileName;
103         std::string pos = jf[i].pos;
104         uintptr_t *nativepointer = jf[i].nativePointer;
105         LOG_ECMA(INFO) << "BuildJsStackInfoList functionname: " << functionname;
106         LOG_ECMA(INFO) << "BuildJsStackInfoList filenaem: " << filename;
107         LOG_ECMA(INFO) << "BuildJsStackInfoList pos: " << pos;
108         LOG_ECMA(INFO) << "BuildJsStackInfoList nativepointer: " << nativepointer;
109     }
110     stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(vm->GetAssociatedJSThread(), true);
111     if (stackTraceStr.empty()) {
112         return false;
113     }
114     return true;
115 }
116 
BuildJsStackTrace(const EcmaVM * vm,std::string & stackTraceStr)117 bool DFXJSNApi::BuildJsStackTrace(const EcmaVM *vm, std::string &stackTraceStr)
118 {
119     stackTraceStr = ecmascript::JsStackInfo::BuildJsStackTrace(vm->GetAssociatedJSThread(), false);
120     if (stackTraceStr.empty()) {
121         return false;
122     }
123     return true;
124 }
125 
StartHeapTracking(const EcmaVM * vm,double timeInterval,bool isVmMode,Stream * stream,bool traceAllocation,bool newThread)126 bool DFXJSNApi::StartHeapTracking(const EcmaVM *vm, double timeInterval, bool isVmMode,
127                                   Stream *stream, bool traceAllocation, bool newThread)
128 {
129     ecmascript::base::BlockHookScope blockScope;
130     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
131         const_cast<EcmaVM *>(vm));
132     return heapProfile->StartHeapTracking(timeInterval, isVmMode, stream, traceAllocation, newThread);
133 }
134 
UpdateHeapTracking(const EcmaVM * vm,Stream * stream)135 bool DFXJSNApi::UpdateHeapTracking(const EcmaVM *vm, Stream *stream)
136 {
137     ecmascript::base::BlockHookScope blockScope;
138     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
139         const_cast<EcmaVM *>(vm));
140     return heapProfile->UpdateHeapTracking(stream);
141 }
142 
StopHeapTracking(const EcmaVM * vm,const std::string & filePath,bool newThread)143 bool DFXJSNApi::StopHeapTracking(const EcmaVM *vm, const std::string &filePath, bool newThread)
144 {
145     FileStream stream(filePath);
146     return StopHeapTracking(vm, &stream, nullptr, newThread);
147 }
148 
StopHeapTracking(const EcmaVM * vm,Stream * stream,Progress * progress,bool newThread)149 bool DFXJSNApi::StopHeapTracking(const EcmaVM *vm, Stream* stream, Progress *progress, bool newThread)
150 {
151     ecmascript::base::BlockHookScope blockScope;
152     bool result = false;
153     ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(
154         const_cast<EcmaVM *>(vm));
155     result = heapProfile->StopHeapTracking(stream, progress, newThread);
156     ecmascript::HeapProfilerInterface::Destroy(const_cast<EcmaVM *>(vm));
157     return result;
158 }
159 
PrintStatisticResult(const EcmaVM * vm)160 void DFXJSNApi::PrintStatisticResult(const EcmaVM *vm)
161 {
162     ecmascript::GCStats gcstats(vm->GetHeap());
163     gcstats.PrintStatisticResult(true);
164 }
165 
StartRuntimeStat(EcmaVM * vm)166 void DFXJSNApi::StartRuntimeStat(EcmaVM *vm)
167 {
168     vm->SetRuntimeStatEnable(true);
169 }
170 
StopRuntimeStat(EcmaVM * vm)171 void DFXJSNApi::StopRuntimeStat(EcmaVM *vm)
172 {
173     vm->SetRuntimeStatEnable(false);
174 }
175 
GetArrayBufferSize(const EcmaVM * vm)176 size_t DFXJSNApi::GetArrayBufferSize(const EcmaVM *vm)
177 {
178     return vm->GetHeap()->GetArrayBufferSize();
179 }
180 
GetHeapTotalSize(const EcmaVM * vm)181 size_t DFXJSNApi::GetHeapTotalSize(const EcmaVM *vm)
182 {
183     return vm->GetHeap()->GetCommittedSize();
184 }
185 
GetHeapUsedSize(const EcmaVM * vm)186 size_t DFXJSNApi::GetHeapUsedSize(const EcmaVM *vm)
187 {
188     return vm->GetHeap()->GetHeapObjectSize();
189 }
190 
NotifyApplicationState(EcmaVM * vm,bool inBackground)191 void DFXJSNApi::NotifyApplicationState(EcmaVM *vm, bool inBackground)
192 {
193     const_cast<ecmascript::Heap *>(vm->GetHeap())->ChangeGCParams(inBackground);
194 }
195 
NotifyIdleTime(const EcmaVM * vm,int idleMicroSec)196 void DFXJSNApi::NotifyIdleTime(const EcmaVM *vm, int idleMicroSec)
197 {
198     const_cast<ecmascript::Heap *>(vm->GetHeap())->TriggerIdleCollection(idleMicroSec);
199 }
200 
NotifyMemoryPressure(EcmaVM * vm,bool inHighMemoryPressure)201 void DFXJSNApi::NotifyMemoryPressure(EcmaVM *vm, bool inHighMemoryPressure)
202 {
203     const_cast<ecmascript::Heap *>(vm->GetHeap())->NotifyMemoryPressure(inHighMemoryPressure);
204 }
205 #if defined(ECMASCRIPT_SUPPORT_CPUPROFILER)
StartCpuProfilerForFile(const EcmaVM * vm,const std::string & fileName,const int interval)206 void DFXJSNApi::StartCpuProfilerForFile(const EcmaVM *vm, const std::string &fileName, const int interval)
207 {
208     if (vm == nullptr) {
209         return;
210     }
211     CpuProfiler *profiler = vm->GetProfiler();
212     if (profiler == nullptr) {
213         profiler = new CpuProfiler(vm, interval);
214         const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
215     }
216     profiler->StartCpuProfilerForFile(fileName);
217 }
218 
StopCpuProfilerForFile(const EcmaVM * vm)219 void DFXJSNApi::StopCpuProfilerForFile(const EcmaVM *vm)
220 {
221     if (vm == nullptr) {
222         return;
223     }
224     CpuProfiler *profiler = vm->GetProfiler();
225     if (profiler == nullptr) {
226         return;
227     }
228     profiler->StopCpuProfilerForFile();
229     delete profiler;
230     profiler = nullptr;
231     const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
232 }
233 
StartCpuProfilerForInfo(const EcmaVM * vm,const int interval)234 void DFXJSNApi::StartCpuProfilerForInfo(const EcmaVM *vm, const int interval)
235 {
236     if (vm == nullptr) {
237         return;
238     }
239     CpuProfiler *profiler = vm->GetProfiler();
240     if (profiler == nullptr) {
241         profiler = new CpuProfiler(vm, interval);
242         const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
243     }
244     profiler->StartCpuProfilerForInfo();
245 }
246 
StopCpuProfilerForInfo(const EcmaVM * vm)247 std::unique_ptr<ProfileInfo> DFXJSNApi::StopCpuProfilerForInfo(const EcmaVM *vm)
248 {
249     if (vm == nullptr) {
250         return nullptr;
251     }
252     CpuProfiler *profiler = vm->GetProfiler();
253     if (profiler == nullptr) {
254         return nullptr;
255     }
256     auto profile = profiler->StopCpuProfilerForInfo();
257     if (profile == nullptr) {
258         LOG_DEBUGGER(ERROR) << "Transfer CpuProfiler::StopCpuProfilerImpl is failure";
259     }
260     delete profiler;
261     profiler = nullptr;
262     const_cast<EcmaVM *>(vm)->SetProfiler(nullptr);
263     return profile;
264 }
265 
SetCpuSamplingInterval(const EcmaVM * vm,int interval)266 void DFXJSNApi::SetCpuSamplingInterval(const EcmaVM *vm, int interval)
267 {
268     LOG_ECMA(INFO) << "SetCpuProfilerSamplingInterval, Sampling interval is: " << interval;
269     if (vm == nullptr) {
270         return;
271     }
272     CpuProfiler *profiler = vm->GetProfiler();
273     if (profiler == nullptr) {
274         profiler = new CpuProfiler(vm, interval);
275         const_cast<EcmaVM *>(vm)->SetProfiler(profiler);
276         return;
277     }
278     profiler->SetCpuSamplingInterval(interval);
279 }
280 #endif
281 
SuspendVM(const EcmaVM * vm)282 bool DFXJSNApi::SuspendVM(const EcmaVM *vm)
283 {
284     ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
285     return vmThreadControl->NotifyVMThreadSuspension();
286 }
287 
ResumeVM(const EcmaVM * vm)288 void DFXJSNApi::ResumeVM(const EcmaVM *vm)
289 {
290     ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
291     vmThreadControl->ResumeVM();
292 }
293 
IsSuspended(const EcmaVM * vm)294 bool DFXJSNApi::IsSuspended(const EcmaVM *vm)
295 {
296     ecmascript::VmThreadControl* vmThreadControl = vm->GetAssociatedJSThread()->GetVmThreadControl();
297     return vmThreadControl->IsSuspended();
298 }
299 
CheckSafepoint(const EcmaVM * vm)300 bool DFXJSNApi::CheckSafepoint(const EcmaVM *vm)
301 {
302     ecmascript::JSThread* thread = vm->GetJSThread();
303     return  thread->CheckSafepoint();
304 }
305 
BuildJsStackInfoList(const EcmaVM * hostVm,uint32_t tid,std::vector<JsFrameInfo> & jsFrames)306 bool DFXJSNApi::BuildJsStackInfoList(const EcmaVM *hostVm, uint32_t tid, std::vector<JsFrameInfo>& jsFrames)
307 {
308     EcmaVM *vm;
309     if (hostVm->GetAssociatedJSThread()->GetThreadId() == tid) {
310         vm = const_cast<EcmaVM*>(hostVm);
311     } else {
312         vm = hostVm->GetWorkerVm(tid);
313         if (vm == nullptr) {
314             LOG_ECMA(INFO) << "WorkerVm is nullptr or has been damaged!";
315             return false;
316         }
317     }
318     jsFrames = ecmascript::JsStackInfo::BuildJsStackInfo(vm->GetAssociatedJSThread());
319     if (jsFrames.size() > 0) {
320         return true;
321     }
322     return false;
323 }
324 } // namespace panda
325