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