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 #ifndef FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_QUICKJS_QJS_UTILS_H
17 #define FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_QUICKJS_QJS_UTILS_H
18
19 #include <cassert>
20 #include <cstring>
21 #include <stack>
22 #include <vector>
23
24 #include "frameworks/bridge/js_frontend/js_ace_page.h"
25 #ifdef __cplusplus
26 extern "C" {
27 #endif
28 #include "third_party/quickjs/cutils.h"
29 #include "third_party/quickjs/quickjs-libc.h"
30 #ifdef __cplusplus
31 }
32 #endif
33
34 namespace OHOS::Ace::Framework {
35
36 enum class JsErrorType {
37 JS_CRASH = 0,
38 JS_CALLBACK_ERROR,
39 FIRE_EVENT_ERROR,
40 EVAL_BUFFER_ERROR,
41 READ_OBJECT_ERROR,
42 DESTROY_APP_ERROR,
43 DESTROY_PAGE_ERROR,
44 LOAD_JS_BUNDLE_ERROR,
45 COMPILE_AND_RUN_BUNDLE_ERROR,
46 LOAD_JS_FRAMEWORK_ERROR,
47 };
48
49 class ScopedString {
50 public:
51 ScopedString(JSContext* ctx, JSValueConst val);
52 ScopedString(JSContext* ctx, JSAtom val);
53 ScopedString(JSValueConst val);
54 ScopedString(JSAtom val);
55 ScopedString(const ScopedString& rhs) = delete;
56 ScopedString& operator=(const ScopedString& rhs) = delete;
57 ScopedString(ScopedString&& rhs) = delete;
58 ScopedString& operator=(ScopedString&& rhs) = delete;
59 ~ScopedString();
60
61 bool operator==(const char* rhs);
62 bool operator==(const std::string& rhs);
63 bool operator==(const ScopedString& rhs);
64
65 const char* get() const;
66 std::string str();
67
68 static std::string Stringify(JSValueConst val);
69 static std::string Stringify(JSContext* ctx, JSValueConst val);
70
71 operator std::string() const;
72
73 private:
74 JSContext* context_ = nullptr;
75 const char* stringValue_ = nullptr;
76 };
77
78 class QJSUtils {
79 public:
80 using FilterFunction = bool (*)(std::string);
81
82 static JSValue NewStringLen(JSContext* ctx, const char* str, size_t len);
83 static JSValue NewString(JSContext* ctx, const char* str);
84 static JSValue ParseJSON(JSContext* ctx, const char* buf, size_t bufLen, const char* filename = nullptr);
85 static JSValue NewObject(JSContext* ctx);
86 static JSValue Call(JSContext* ctx, JSValueConst funcObj, JSValueConst thisObj, int32_t argc, JSValueConst* argv);
87 static JSValue Eval(JSContext* ctx, const char* input, size_t inputLen, const char* filename, int32_t evalFlags);
88 static JSValue GetPropertyStr(JSContext* ctx, JSValueConst thisObj, const char* prop);
89 static void JsStdDumpErrorAce(JSContext* ctx, JsErrorType errorType = JsErrorType::JS_CRASH, int32_t instanceId = 0,
90 const char* pageUrl = nullptr, const RefPtr<JsAcePage>& page = nullptr);
91 static void ExtractEachInfo(const std::string& tempStack, std::vector<std::string>& res);
92 static void GetPosInfo(const std::string& temp, int32_t start, std::string& line);
93 static std::string GetSourceInfo(const std::string& line, const RefPtr<RevSourceMap>& pageMap,
94 const RefPtr<RevSourceMap>& appMap, bool isAppPage);
95 static void JsDumpMemoryStats(JSContext* ctx);
96 static int32_t JsGetArrayLength(JSContext* ctx, JSValueConst arrayObject);
97
98 static std::vector<std::string> GetObjectKeys(JSContext* ctx, JSValueConst obj, int flags = JS_GPN_STRING_MASK);
99 static std::vector<std::string> GetObjectKeys(JSValueConst obj, int flags = JS_GPN_STRING_MASK);
100 static std::vector<std::string> GetFilteredObjectKeys(
101 JSContext* ctx, JSValueConst obj, FilterFunction filterFunc, int flags = JS_GPN_STRING_MASK);
102 static bool CheckAndGetJsProperty(JSContext* ctx, JSValueConst jsObj, JSPropertyEnum** pTab, uint32_t* len);
103 static std::string typeAsString(JSValueConst val);
104 static JSValue GetArgvSafe(int idx, int argc, JSValueConst* argv);
105 static void DefineGlobalFunction(JSContext* ctx, JSCFunction jsFunc, const char* name, const int paramNum);
106 static std::string JsDumpSourceFile(const char* stack, const RefPtr<RevSourceMap>& pageMap,
107 const RefPtr<RevSourceMap>& appMap);
108 };
109
110 /**
111 * @brief A class maintaining a stack of JSContext pointers.
112 *
113 */
114 class QJSContext {
115 public:
116 /**
117 * @brief A class that acquires a JSContext to be retrieved further in a call stack by QJSContext::Current().
118 *
119 * This is used to relieve the QJS embedder of passing JSContext* as an argument.
120 *
121 * @note QJSContext::Scope is thread-safe, but not reentrant.
122 */
123 class Scope {
124 public:
125 Scope(JSContext* ctx);
126 ~Scope();
127
128 static void* operator new(size_t) = delete;
129 static void* operator new[](size_t) = delete;
130 static void operator delete(void*) = delete;
131 static void operator delete[](void*) = delete;
132 Scope(const Scope&) = delete;
133 void operator=(const Scope&) = delete;
134 };
135
136 /**
137 * @brief Get the context on the top of the stack
138 *
139 * @return JSContext*
140 */
141 static JSContext* Current();
142
143 static void* operator new(size_t) = delete;
144 static void* operator new[](size_t) = delete;
145 static void operator delete(void*) = delete;
146 static void operator delete[](void*) = delete;
147 QJSContext(const QJSContext&) = delete;
148 void operator=(const QJSContext&) = delete;
149
150 private:
151 #if defined(USE_CLANG_COVERAGE) || defined(CLANG_COVERAGE)
152 static std::stack<JSContext*> s_qjsContextStack;
153 #else
154 static thread_local std::stack<JSContext*> s_qjsContextStack;
155 #endif
156 };
157
158 class QJSHandleScope {
159 public:
160 QJSHandleScope(JSContext* ctx);
161 ~QJSHandleScope();
162
163 static void* operator new(size_t) = delete;
164 static void* operator new[](size_t) = delete;
165 static void operator delete(void*) = delete;
166 static void operator delete[](void*) = delete;
167
168 private:
169 friend class QJSUtils;
170 friend class QJSValue;
171 #if defined(USE_CLANG_COVERAGE) || defined(CLANG_COVERAGE)
172 static std::stack<QJSHandleScope*> qjsHandleScopeStack_;
173 #else
174 static thread_local std::stack<QJSHandleScope*> qjsHandleScopeStack_;
175 #endif
176
177 static QJSHandleScope* GetCurrent();
178 void Push(JSValue val);
179
180 int32_t scopeId_ = 0;
181 std::vector<JSValueConst> jsValues_;
182 JSContext* context_ = nullptr;
183 };
184
CheckAndGetJsProperty(JSContext * ctx,JSValueConst fromMap,JSPropertyEnum ** pTab,uint32_t * len)185 inline bool CheckAndGetJsProperty(JSContext* ctx, JSValueConst fromMap, JSPropertyEnum** pTab, uint32_t* len)
186 {
187 if (!JS_IsObject(fromMap)) {
188 return false;
189 }
190
191 JS_GetOwnPropertyNames(ctx, pTab, len, fromMap, JS_GPN_STRING_MASK);
192 if (*pTab == nullptr) {
193 return false;
194 }
195 return true;
196 }
197
198 } // namespace OHOS::Ace::Framework
199
200 #endif // FOUNDATION_ACE_FRAMEWORKS_BRIDGE_JS_FRONTEND_ENGINE_QUICKJS_QJS_UTILS_H
201