1/*
2 * Copyright (c) 2023 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#ifndef ECMASCRIPT_PGO_PROFILER_PGO_UTILS_H
17#define ECMASCRIPT_PGO_PROFILER_PGO_UTILS_H
18
19#include <list>
20#include <string>
21
22#include "ecmascript/common.h"
23#include "ecmascript/log.h"
24#include "ecmascript/log_wrapper.h"
25#include "ecmascript/platform/mutex.h"
26#include "libpandafile/file.h"
27#include "mem/mem.h"
28
29namespace panda::ecmascript::pgo {
30static constexpr Alignment ALIGN_SIZE = Alignment::LOG_ALIGN_4;
31using PGOMethodId = panda_file::File::EntityId;
32using ApEntityId = uint32_t;
33
34class DumpUtils {
35public:
36    static const std::string ELEMENT_SEPARATOR;
37    static const std::string BLOCK_SEPARATOR;
38    static const std::string TYPE_SEPARATOR;
39    static const std::string BLOCK_START;
40    static const std::string ARRAY_START;
41    static const std::string ARRAY_END;
42    static const std::string NEW_LINE;
43    static const std::string SPACE;
44    static const std::string BLOCK_AND_ARRAY_START;
45    static const std::string VERSION_HEADER;
46    static const std::string PANDA_FILE_INFO_HEADER;
47    static const uint32_t HEX_FORMAT_WIDTH_FOR_32BITS;
48};
49
50class DumpJsonUtils {
51public:
52    static inline const std::string ABC_FILE_POOL = "abcFilePool";
53    static inline const std::string ABC_FILE = "abcFile";
54    static inline const std::string RECORD_DETAIL = "recordDetail";
55    static inline const std::string MODULE_NAME = "moduleName";
56    static inline const std::string FUNCTION = "function";
57    static inline const std::string FUNCTION_NAME = "functionName";
58    static inline const std::string TYPE = "type";
59    static inline const std::string TYPE_OFFSET = "typeOffset";
60    static inline const std::string TYPE_NAME = "typeName";
61    static inline const std::string IS_ROOT = "isRoot";
62    static inline const std::string KIND = "kind";
63    static inline const std::string ABC_ID = "abcId";
64    static inline const std::string ID = "id";
65};
66
67class ApNameUtils {
68public:
69    static const std::string AP_SUFFIX;
70    static const std::string RUNTIME_AP_PREFIX;
71    static const std::string MERGED_AP_PREFIX;
72    static const std::string DEFAULT_AP_NAME;
73    static std::string PUBLIC_API GetRuntimeApName(const std::string &ohosModuleName);
74    static std::string PUBLIC_API GetMergedApName(const std::string &ohosModuleName);
75    static std::string PUBLIC_API GetOhosPkgApName(const std::string &ohosModuleName);
76
77private:
78    static std::string GetBriefApName(const std::string &ohosModuleName);
79};
80
81class ConcurrentGuardValues {
82public:
83    mutable std::atomic_int last_tid {0};
84    mutable std::atomic_int count {0};
85    static const int MAX_LOG_COUNT = 30;
86
87    void AddLog(std::string str)
88    {
89        LockHolder lock(mutex_);
90        if (log_.size() >= MAX_LOG_COUNT) {
91            log_.pop_front();
92        }
93        log_.push_back(str + ", tid: " + std::to_string(Gettid()));
94    }
95
96    void AddLogWithDebugLog(std::string str)
97    {
98        AddLog(str);
99        LOG_ECMA(DEBUG) << str;
100    }
101
102    void ClearLog()
103    {
104        LockHolder lock(mutex_);
105        log_.clear();
106    }
107
108    void PrintLog()
109    {
110        LockHolder lock(mutex_);
111        std::ostringstream os;
112        os << "concurrent guard logs: " << std::endl;
113        for (auto& str: log_) {
114            os << str << std::endl;
115        }
116        LOG_ECMA(INFO) << os.str();
117    }
118
119    int Gettid()
120    {
121        return os::thread::GetCurrentThreadId();
122    }
123
124private:
125    std::list<std::string> log_;
126    Mutex mutex_;
127};
128
129class ConcurrentGuard {
130private:
131    std::string operation_;
132
133public:
134    ConcurrentGuard(ConcurrentGuardValues& v, std::string operation = ""): operation_(operation), v_(v)
135    {
136        v_.AddLogWithDebugLog("[ConcurrentGuard] " + operation_ + " start");
137        auto tid = v_.Gettid();
138        auto except = 0;
139        // Support reenter
140        if (!v_.count.compare_exchange_strong(except, 1) && v_.last_tid != tid) {
141            v_.PrintLog();
142            LOG_ECMA(FATAL) << "[ConcurrentGuard] total thead count should be 0, but get " << except
143                            << ", current tid: " << tid << ", last tid: " << v_.last_tid;
144        }
145        v_.last_tid = tid;
146    }
147    ~ConcurrentGuard()
148    {
149        auto tid = v_.Gettid();
150        auto except = 1;
151        // Support reenter
152        if (!v_.count.compare_exchange_strong(except, 0) && v_.last_tid != tid) {
153            v_.PrintLog();
154            LOG_ECMA(FATAL) << "[ConcurrentGuard] total thead count should be 1, but get " << except
155                            << ", current tid: " << tid << ", last tid: " << v_.last_tid;
156        }
157        v_.AddLogWithDebugLog("[ConcurrentGuard] " + operation_ + " end");
158    };
159
160private:
161    ConcurrentGuardValues& v_;
162};
163}  // namespace panda::ecmascript::pgo
164#endif  // ECMASCRIPT_PGO_PROFILER_PGO_UTILS_H
165