diff --git a/BUILD.gn b/BUILD.gn index a749a091..6c5afc23 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -370,6 +370,7 @@ ecma_source = [ "ecmascript/mem/space.cpp", "ecmascript/mem/verification.cpp", "ecmascript/napi/jsnapi.cpp", + "ecmascript/napi/dfx_jsnapi.cpp", "ecmascript/object_factory.cpp", "ecmascript/object_operator.cpp", "ecmascript/platform/platform.cpp", diff --git a/ecmascript/base/error_helper.cpp b/ecmascript/base/error_helper.cpp index 05dcc8af..07474e75 100644 --- a/ecmascript/base/error_helper.cpp +++ b/ecmascript/base/error_helper.cpp @@ -230,4 +230,13 @@ CString ErrorHelper::BuildNativeEcmaStackTrace(JSThread *thread) return data; } + +std::string ErrorHelper::BuildNativeAndJsBackStackTrace(JSThread *thread) +{ + CString data = BuildNativeEcmaStackTrace(thread); + std::string temp = CstringConvertToString(data); + std::string result = nullptr; + result += temp; + return result; +} } // namespace panda::ecmascript::base diff --git a/ecmascript/base/error_helper.h b/ecmascript/base/error_helper.h index 4c680db5..00567a12 100644 --- a/ecmascript/base/error_helper.h +++ b/ecmascript/base/error_helper.h @@ -33,6 +33,7 @@ public: static CString BuildNativeEcmaStackTrace(JSThread *thread); + static std::string BuildNativeAndJsBackStackTrace(JSThread *thread); private: static CString DecodeFunctionName(const CString &name); static JSHandle BuildEcmaStackTrace(JSThread *thread); diff --git a/ecmascript/cpu_profiler/cpu_profiler.cpp b/ecmascript/cpu_profiler/cpu_profiler.cpp index 5278acbf..8b1d202a 100644 --- a/ecmascript/cpu_profiler/cpu_profiler.cpp +++ b/ecmascript/cpu_profiler/cpu_profiler.cpp @@ -285,7 +285,7 @@ bool CpuProfiler::CheckFileName(const std::string &fileName, std::string &absolu CVector resolvedPath(PATH_MAX); realpath(fileName.c_str(), resolvedPath.data()); - std::ifstream file(resolvedPath.data()); + std::ofstream file(resolvedPath.data()); if (!file.good()) { return false; } diff --git a/ecmascript/hprof/heap_profiler.cpp b/ecmascript/hprof/heap_profiler.cpp index 90774e0d..10526e32 100644 --- a/ecmascript/hprof/heap_profiler.cpp +++ b/ecmascript/hprof/heap_profiler.cpp @@ -34,7 +34,7 @@ HeapProfiler::~HeapProfiler() jsonSerializer_ = nullptr; } -bool HeapProfiler::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &filePath, bool isVmMode) +bool HeapProfiler::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const std::string &filePath, bool isVmMode) { [[maybe_unused]] bool heapClean = ForceFullGC(thread); ASSERT(heapClean); @@ -68,7 +68,7 @@ bool HeapProfiler::StartHeapTracking(JSThread *thread, double timeInterval, bool return true; } -bool HeapProfiler::StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const CString &path) +bool HeapProfiler::StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const std::string &path) { if (heapTracker_ == nullptr) { return false; @@ -93,7 +93,7 @@ bool HeapProfiler::StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, con return jsonSerializer_->Serialize(snapShot, realPath.second); } -std::pair HeapProfiler::FilePathValid(const CString &filePath) +std::pair HeapProfiler::FilePathValid(const std::string &filePath) { if (filePath.size() > PATH_MAX) { return std::make_pair(false, ""); @@ -106,7 +106,7 @@ std::pair HeapProfiler::FilePathValid(const CString &filePath) return std::make_pair(false, ""); } -CString HeapProfiler::GenDumpFileName(DumpFormat dumpFormat) +std::string HeapProfiler::GenDumpFileName(DumpFormat dumpFormat) { CString filename("hprof_"); switch (dumpFormat) { @@ -124,7 +124,7 @@ CString HeapProfiler::GenDumpFileName(DumpFormat dumpFormat) break; } filename.append(".heapsnapshot"); - return filename; + return CstringConvertToString(filename); } CString HeapProfiler::GetTimeStamp() diff --git a/ecmascript/hprof/heap_profiler.h b/ecmascript/hprof/heap_profiler.h index 25102472..55696535 100644 --- a/ecmascript/hprof/heap_profiler.h +++ b/ecmascript/hprof/heap_profiler.h @@ -44,11 +44,11 @@ public: /** * dump the specific snapshot in target format */ - bool DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const CString &path, bool isVmMode = true); + bool DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, const std::string &path, bool isVmMode = true); void AddSnapShot(HeapSnapShot *snapshot); bool StartHeapTracking(JSThread *thread, double timeInterval, bool isVmMode = true) override; - bool StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const CString &filePath) override; + bool StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const std::string &filePath) override; private: /** @@ -60,8 +60,8 @@ private: * make a new heap snapshot and put it into a container eg, vector */ HeapSnapShot *MakeHeapSnapShot(JSThread *thread, SampleType sampleType, bool isVmMode = true); - std::pair FilePathValid(const CString &filePath); - CString GenDumpFileName(DumpFormat dumpFormat); + std::pair FilePathValid(const std::string &filePath); + std::string GenDumpFileName(DumpFormat dumpFormat); CString GetTimeStamp(); void ClearSnapShot(); diff --git a/ecmascript/hprof/heap_profiler_interface.cpp b/ecmascript/hprof/heap_profiler_interface.cpp index 43736b5d..0a103911 100644 --- a/ecmascript/hprof/heap_profiler_interface.cpp +++ b/ecmascript/hprof/heap_profiler_interface.cpp @@ -18,8 +18,17 @@ #include "ecmascript/mem/heap.h" namespace panda::ecmascript { +HeapProfilerInterface *HeapProfilerInterface::heapProfile_ = nullptr; +HeapProfilerInterface *HeapProfilerInterface::GetInstance(JSThread *thread) +{ + if (HeapProfilerInterface::heapProfile_ == nullptr) { + heapProfile_ = HeapProfilerInterface::CreateHeapProfiler(thread); + } + return HeapProfilerInterface::heapProfile_; +} + void HeapProfilerInterface::DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, - const CString &filePath, bool isVmMode) + const std::string &filePath, bool isVmMode) { LOG(ERROR, RUNTIME) << "HeapProfilerInterface::DumpHeapSnapshot"; const Heap *heap = thread->GetEcmaVM()->GetHeap(); diff --git a/ecmascript/hprof/heap_profiler_interface.h b/ecmascript/hprof/heap_profiler_interface.h index 66cd3e00..a731a648 100644 --- a/ecmascript/hprof/heap_profiler_interface.h +++ b/ecmascript/hprof/heap_profiler_interface.h @@ -24,8 +24,9 @@ enum class DumpFormat { JSON, BINARY, OTHER }; class HeapProfilerInterface { public: + static HeapProfilerInterface *GetInstance(JSThread *thread); static void DumpHeapSnapShot(JSThread *thread, DumpFormat dumpFormat, - const CString &filePath, bool isVmMode = true); + const std::string &filePath, bool isVmMode = true); static HeapProfilerInterface *CreateHeapProfiler(JSThread *thread); static void Destroy(JSThread *thread, HeapProfilerInterface *heapProfiler); @@ -34,10 +35,12 @@ public: virtual ~HeapProfilerInterface() = default; virtual bool StartHeapTracking(JSThread *thread, double timeInterval, bool isVmMode = true) = 0; - virtual bool StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const CString &filePath) = 0; + virtual bool StopHeapTracking(JSThread *thread, DumpFormat dumpFormat, const std::string &filePath) = 0; NO_MOVE_SEMANTIC(HeapProfilerInterface); NO_COPY_SEMANTIC(HeapProfilerInterface); +private: + static HeapProfilerInterface *heapProfile_; }; } // namespace panda::ecmascript #endif // ECMASCRIPT_HPROF_HEAP_PROFILER_INTERFACE_H diff --git a/ecmascript/mem/c_string.cpp b/ecmascript/mem/c_string.cpp index a5eb91d2..5c370961 100644 --- a/ecmascript/mem/c_string.cpp +++ b/ecmascript/mem/c_string.cpp @@ -123,4 +123,14 @@ CString ConvertToString(JSTaggedValue key) return ConvertToString(EcmaString::ConstCast(desc.GetTaggedObject())); } + +std::string CstringConvertToString(const CString &str) +{ + std::string res; + res.reserve(str.size()); + for (auto c : str) { + res.push_back(c); + } + return res; +} } // namespace panda::ecmascript diff --git a/ecmascript/mem/c_string.h b/ecmascript/mem/c_string.h index 194b5ca3..0ed8fa75 100644 --- a/ecmascript/mem/c_string.h +++ b/ecmascript/mem/c_string.h @@ -39,6 +39,7 @@ float CStringToF(const CString &str); double CStringToD(const CString &str); CString ConvertToString(const std::string &str); +std::string CstringConvertToString(const CString &str); // '\u0000' is skip according to holdZero CString ConvertToString(const ecmascript::EcmaString *s, StringConvertedUsage usage = StringConvertedUsage::PRINT); diff --git a/ecmascript/napi/dfx_jsnapi.cpp b/ecmascript/napi/dfx_jsnapi.cpp new file mode 100644 index 00000000..ec811349 --- /dev/null +++ b/ecmascript/napi/dfx_jsnapi.cpp @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "ecmascript/napi/include/dfx_jsnapi.h" +#include "ecmascript/ecma_module.h" +#include "ecmascript/ecma_vm.h" +#include "ecmascript/hprof/heap_profiler.h" +namespace panda { +using ecmascript::CString; +using ecmascript::EcmaString; +using ecmascript::JSTaggedValue; +template +using JSHandle = ecmascript::JSHandle; + +void DFXJSNApi::DumpHeapSnapShot(EcmaVM *vm, int dumpFormat, const std::string &path, bool isVmMode) +{ + if (dumpFormat == 0) { + ecmascript::HeapProfilerInterface::DumpHeapSnapShot(vm->GetJSThread(), ecmascript::DumpFormat::JSON, + path, isVmMode); + } else if (dumpFormat == 1) { + ecmascript::HeapProfilerInterface::DumpHeapSnapShot(vm->GetJSThread(), ecmascript::DumpFormat::BINARY, + path, isVmMode); + } else if (dumpFormat == 2) { // 2: enum is 2 + ecmascript::HeapProfilerInterface::DumpHeapSnapShot(vm->GetJSThread(), ecmascript::DumpFormat::OTHER, + path, isVmMode); + } +} + +std::string DFXJSNApi::BuildNativeAndJsBackStackTrace(EcmaVM *vm) +{ + std::string result = ecmascript::base::ErrorHelper::BuildNativeAndJsBackStackTrace(vm->GetJSThread()); + return result; +} + +bool DFXJSNApi::StartHeapTracking(EcmaVM *vm, double timeInterval, bool isVmMode) +{ + ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(vm->GetJSThread()); + return heapProfile->StartHeapTracking(vm->GetJSThread(), timeInterval, isVmMode); +} + +bool DFXJSNApi::StopHeapTracking(EcmaVM *vm, int dumpFormat, const std::string &filePath) +{ + bool result = false; + ecmascript::HeapProfilerInterface *heapProfile = ecmascript::HeapProfilerInterface::GetInstance(vm->GetJSThread()); + if (dumpFormat == 0) { + result = heapProfile->StopHeapTracking(vm->GetJSThread(), ecmascript::DumpFormat::JSON, filePath); + } + if (dumpFormat == 1) { + result = heapProfile->StopHeapTracking(vm->GetJSThread(), ecmascript::DumpFormat::BINARY, filePath); + } + if (dumpFormat == 2) { // 2: enum is 2 + result = heapProfile->StopHeapTracking(vm->GetJSThread(), ecmascript::DumpFormat::OTHER, filePath); + } + const ecmascript::Heap *heap = vm->GetJSThread()->GetEcmaVM()->GetHeap(); + const_cast(heap->GetRegionFactory())->Delete(heapProfile); + return result; +} +} diff --git a/ecmascript/napi/include/dfx_jsnapi.h b/ecmascript/napi/include/dfx_jsnapi.h new file mode 100644 index 00000000..d81ecb5d --- /dev/null +++ b/ecmascript/napi/include/dfx_jsnapi.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2021 Huawei Device Co., Ltd. + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ECMASCRIPT_NAPI_INCLUDE_DFX_JSNAPI_H +#define ECMASCRIPT_NAPI_INCLUDE_DFX_JSNAPI_H + +#include +#include +#include +#include + +#include "ecmascript/common.h" +#include "libpandabase/macros.h" + +namespace panda { +namespace ecmascript { +class EcmaVM; +} +class DFXJSNApi; +using EcmaVM = ecmascript::EcmaVM; + +class PUBLIC_API DFXJSNApi { +public: + static void DumpHeapSnapShot(EcmaVM *vm, int dumpFormat, const std::string &path, bool isVmMode = true); + static std::string BuildNativeAndJsBackStackTrace(EcmaVM *vm); + static bool StartHeapTracking(EcmaVM *vm, double timeInterval, bool isVmMode = true); + static bool StopHeapTracking(EcmaVM *vm, int dumpFormat, const std::string &filePath); +}; +} +#endif \ No newline at end of file