ScriptEngine.hpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. /****************************************************************************
  2. Copyright (c) 2016 Chukong Technologies Inc.
  3. Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
  4. http://www.cocos2d-x.org
  5. Permission is hereby granted, free of charge, to any person obtaining a copy
  6. of this software and associated documentation files (the "Software"), to deal
  7. in the Software without restriction, including without limitation the rights
  8. to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9. copies of the Software, and to permit persons to whom the Software is
  10. furnished to do so, subject to the following conditions:
  11. The above copyright notice and this permission notice shall be included in
  12. all copies or substantial portions of the Software.
  13. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. THE SOFTWARE.
  20. ****************************************************************************/
  21. #pragma once
  22. #include "../config.hpp"
  23. #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM
  24. #include "Base.h"
  25. namespace se {
  26. class Object;
  27. class Class;
  28. class Value;
  29. extern Class* __jsb_CCPrivateData_class;
  30. /**
  31. * A stack-allocated class that governs a number of local handles.
  32. * It's only implemented for v8 wrapper now.
  33. * Other script engine wrappers have empty implementation for this class.
  34. * It's used at the beginning of executing any wrapper API.
  35. */
  36. class AutoHandleScope
  37. {
  38. public:
  39. AutoHandleScope();
  40. ~AutoHandleScope();
  41. };
  42. /**
  43. * ScriptEngine is a sington which represents a context of JavaScript VM.
  44. */
  45. class ScriptEngine final
  46. {
  47. public:
  48. /**
  49. * @brief Gets or creates the instance of script engine.
  50. * @return The script engine instance.
  51. */
  52. static ScriptEngine* getInstance();
  53. /**
  54. * @brief Destroys the instance of script engine.
  55. */
  56. static void destroyInstance();
  57. /**
  58. * @brief Gets the global object of JavaScript VM.
  59. * @return The se::Object stores the global JavaScript object.
  60. */
  61. Object* getGlobalObject();
  62. typedef bool (*RegisterCallback)(Object*);
  63. /**
  64. * @brief Adds a callback for registering a native binding module.
  65. * @param[in] cb A callback for registering a native binding module.
  66. * @note This method just add a callback to a vector, callbacks is invoked in `start` method.
  67. */
  68. void addRegisterCallback(RegisterCallback cb);
  69. /**
  70. * @brief Starts the script engine.
  71. * @return true if succeed, otherwise false.
  72. * @note This method will invoke all callbacks of native binding modules by the order of registration.
  73. */
  74. bool start();
  75. /**
  76. * @brief Initializes script engine.
  77. * @return true if succeed, otherwise false.
  78. * @note This method will create JavaScript context and global object.
  79. */
  80. bool init();
  81. /**
  82. * @brief Adds a hook function before initializing script engine.
  83. * @param[in] hook A hook function to be invoked before initializing script engine.
  84. * @note Multiple hook functions could be added, they will be invoked by the order of adding.
  85. */
  86. void addBeforeInitHook(const std::function<void()>& hook);
  87. /**
  88. * @brief Adds a hook function after initializing script engine.
  89. * @param[in] hook A hook function to be invoked before initializing script engine.
  90. * @note Multiple hook functions could be added, they will be invoked by the order of adding.
  91. */
  92. void addAfterInitHook(const std::function<void()>& hook);
  93. /**
  94. * @brief Cleanups script engine.
  95. * @note This method will removes all objects in JavaScript VM even whose are rooted, then shutdown JavaScript VMf.
  96. */
  97. void cleanup();
  98. /**
  99. * @brief Adds a hook function before cleanuping script engine.
  100. * @param[in] hook A hook function to be invoked before cleanuping script engine.
  101. * @note Multiple hook functions could be added, they will be invoked by the order of adding.
  102. */
  103. void addBeforeCleanupHook(const std::function<void()>& hook);
  104. /**
  105. * @brief Adds a hook function after cleanuping script engine.
  106. * @param[in] hook A hook function to be invoked after cleanuping script engine.
  107. * @note Multiple hook functions could be added, they will be invoked by the order of adding.
  108. */
  109. void addAfterCleanupHook(const std::function<void()>& hook);
  110. /**
  111. * @brief Executes a utf-8 string buffer which contains JavaScript code.
  112. * @param[in] scriptStr A utf-8 string buffer, if it isn't null-terminated, parameter `length` should be assigned and > 0.
  113. * @param[in] length The length of parameter `scriptStr`, it will be set to string length internally if passing < 0 and parameter `scriptStr` is null-terminated.
  114. * @param[in] rval The se::Value that results from evaluating script. Passing nullptr if you don't care about the result.
  115. * @param[in] fileName A string containing a URL for the script's source file. This is used by debuggers and when reporting exceptions. Pass NULL if you do not care to include source file information.
  116. * @return true if succeed, otherwise false.
  117. */
  118. bool evalString(const char* scriptStr, ssize_t length = -1, Value* rval = nullptr, const char* fileName = nullptr);
  119. /**
  120. * Delegate class for file operation
  121. */
  122. class FileOperationDelegate
  123. {
  124. public:
  125. FileOperationDelegate()
  126. : onGetDataFromFile(nullptr)
  127. , onGetStringFromFile(nullptr)
  128. , onCheckFileExist(nullptr)
  129. , onGetFullPath(nullptr)
  130. {}
  131. bool isValid() const {
  132. return onGetDataFromFile != nullptr
  133. && onGetStringFromFile != nullptr
  134. && onCheckFileExist != nullptr
  135. && onGetFullPath != nullptr; }
  136. // path, buffer, buffer size
  137. std::function<void(const std::string&, const std::function<void(const uint8_t*, size_t)>& )> onGetDataFromFile;
  138. // path, return file string content.
  139. std::function<std::string(const std::string&)> onGetStringFromFile;
  140. // path
  141. std::function<bool(const std::string&)> onCheckFileExist;
  142. // path, return full path
  143. std::function<std::string(const std::string&)> onGetFullPath;
  144. };
  145. /**
  146. * @brief Sets the delegate for file operation.
  147. * @param delegate[in] The delegate instance for file operation.
  148. */
  149. void setFileOperationDelegate(const FileOperationDelegate& delegate);
  150. /**
  151. * @brief Gets the delegate for file operation.
  152. * @return The delegate for file operation
  153. */
  154. const FileOperationDelegate& getFileOperationDelegate() const;
  155. /**
  156. * @brief Executes a file which contains JavaScript code.
  157. * @param[in] path Script file path.
  158. * @param[in] rval The se::Value that results from evaluating script. Passing nullptr if you don't care about the result.
  159. * @return true if succeed, otherwise false.
  160. */
  161. bool runScript(const std::string& path, Value* rval = nullptr);
  162. /**
  163. * @brief Tests whether script engine is doing garbage collection.
  164. * @return true if it's in garbage collection, otherwise false.
  165. */
  166. bool isGarbageCollecting();
  167. /**
  168. * @brief Performs a JavaScript garbage collection.
  169. */
  170. void garbageCollect() { JS_GC( _cx ); }
  171. /**
  172. * @brief Tests whether script engine is being cleaned up.
  173. * @return true if it's in cleaning up, otherwise false.
  174. */
  175. bool isInCleanup() { return _isInCleanup; }
  176. /**
  177. * @brief Tests whether script engine is valid.
  178. * @return true if it's valid, otherwise false.
  179. */
  180. bool isValid() { return _isValid; }
  181. /**
  182. * @brief Clears all exceptions.
  183. */
  184. void clearException();
  185. using ExceptionCallback = std::function<void(const char*, const char*, const char*)>; // location, message, stack
  186. /**
  187. * @brief Sets the callback function while an exception is fired.
  188. * @param[in] cb The callback function to notify that an exception is fired.
  189. */
  190. void setExceptionCallback(const ExceptionCallback& cb);
  191. /**
  192. * @brief Gets the start time of script engine.
  193. * @return The start time of script engine.
  194. */
  195. const std::chrono::steady_clock::time_point& getStartTime() const { return _startTime; }
  196. /**
  197. * @brief Enables JavaScript debugger
  198. * @param[in] serverAddr The address of debugger server.
  199. * @param[in] port The port of debugger server will use.
  200. * @param[in] isWait Whether wait debugger attach when loading.
  201. */
  202. void enableDebugger(const std::string& serverAddr, uint32_t port, bool isWait = false);
  203. /**
  204. * @brief Tests whether JavaScript debugger is enabled
  205. * @return true if JavaScript debugger is enabled, otherwise false.
  206. */
  207. bool isDebuggerEnabled() const;
  208. /**
  209. * @brief Main loop update trigger, it's need to invoked in main thread every frame.
  210. */
  211. void mainLoopUpdate();
  212. /**
  213. * @brief Gets script virtual machine instance ID. Default value is 1, increase by 1 if `init` is invoked.
  214. */
  215. uint32_t getVMId() const { return _vmId; }
  216. // Private API used in wrapper
  217. JSContext* _getContext() { return _cx; }
  218. void _setGarbageCollecting(bool isGarbageCollecting);
  219. void _debugProcessInput(const std::string& str);
  220. //
  221. private:
  222. ScriptEngine();
  223. ~ScriptEngine();
  224. static void onWeakPointerCompartmentCallback(JSContext* cx, JSCompartment* comp, void* data);
  225. static void onWeakPointerZoneGroupCallback(JSContext* cx, void* data);
  226. bool getScript(const std::string& path, JS::MutableHandleScript script);
  227. bool compileScript(const std::string& path, JS::MutableHandleScript script);
  228. JSContext* _cx;
  229. JSCompartment* _oldCompartment;
  230. Object* _globalObj;
  231. Object* _debugGlobalObj;
  232. FileOperationDelegate _fileOperationDelegate;
  233. std::vector<RegisterCallback> _registerCallbackArray;
  234. std::chrono::steady_clock::time_point _startTime;
  235. std::vector<std::function<void()>> _beforeInitHookArray;
  236. std::vector<std::function<void()>> _afterInitHookArray;
  237. std::vector<std::function<void()>> _beforeCleanupHookArray;
  238. std::vector<std::function<void()>> _afterCleanupHookArray;
  239. ExceptionCallback _exceptionCallback;
  240. // name ~> JSScript map
  241. std::unordered_map<std::string, JS::PersistentRootedScript*> _filenameScriptMap;
  242. std::string _debuggerServerAddr;
  243. uint32_t _debuggerServerPort;
  244. uint32_t _vmId;
  245. bool _isGarbageCollecting;
  246. bool _isValid;
  247. bool _isInCleanup;
  248. bool _isErrorHandleWorking;
  249. };
  250. } // namespace se {
  251. #endif // #if SCRIPT_ENGINE_TYPE == SCRIPT_ENGINE_SM