jsb_pluginx_spidermonkey_specifics.h 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. #ifndef __JS_PLUGINX_SPIDERMONKEY_SPECIFICS_H__
  2. #define __JS_PLUGINX_SPIDERMONKEY_SPECIFICS_H__
  3. #include "cocos2d.h"
  4. #include <typeinfo>
  5. #include <ctype.h>
  6. #include <string.h>
  7. #include <assert.h>
  8. #include "jsapi.h"
  9. #include "uthash.h"
  10. #include <unordered_map>
  11. #ifdef ANDROID
  12. #include <android/log.h>
  13. #endif
  14. #ifndef CCASSERT
  15. #define CCASSERT(a,b) assert(a)
  16. #endif
  17. #define PLUGINX_JSB_DEBUG 0
  18. namespace pluginx {
  19. #if PLUGINX_JSB_DEBUG
  20. #ifdef ANDROID
  21. #define LOG_TAG "jsb_pluginx"
  22. #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
  23. #else
  24. #define LOGD(...) printf(__VA_ARGS__)
  25. #endif
  26. #else
  27. #define LOGD(...) do {} while (0)
  28. #endif
  29. #define JSB_PRECONDITION( condition, ...) do { \
  30. if( ! (condition) ) { \
  31. LOGD("jsb: ERROR: File %s: Line: %d, Function: %s", __FILE__, __LINE__, __FUNCTION__ ); \
  32. LOGD(__VA_ARGS__); \
  33. JSContext* globalContext = ScriptingCore::getInstance()->getGlobalContext(); \
  34. if( ! JS_IsExceptionPending( globalContext ) ) { \
  35. JS_ReportError( globalContext, __VA_ARGS__ ); \
  36. } \
  37. return false; \
  38. } \
  39. } while(0)
  40. #define JSB_PRECONDITION2( condition, context, ret_value, ...) do { \
  41. if( ! (condition) ) { \
  42. LOGD("jsb: ERROR: File %s: Line: %d, Function: %s", __FILE__, __LINE__, __FUNCTION__ ); \
  43. LOGD(__VA_ARGS__); \
  44. if( ! JS_IsExceptionPending( context ) ) { \
  45. JS_ReportError( context, __VA_ARGS__ ); \
  46. } \
  47. return ret_value; \
  48. } \
  49. } while(0)
  50. typedef struct js_proxy {
  51. void *ptr;
  52. JS::Heap<JSObject*> obj;
  53. UT_hash_handle hh;
  54. } js_proxy_t;
  55. extern js_proxy_t *_native_js_global_ht;
  56. extern js_proxy_t *_js_native_global_ht;
  57. typedef struct js_type_class {
  58. JSClass *jsclass;
  59. JS::Heap<JSObject*> proto;
  60. JS::Heap<JSObject*> parentProto;
  61. } js_type_class_t;
  62. extern std::unordered_map<std::string, js_type_class_t*> _js_global_type_map;
  63. unsigned int getHashCodeByString(const char *key);
  64. template< typename DERIVED >
  65. class TypeTest
  66. {
  67. public:
  68. static int s_id()
  69. {
  70. // return id unique for DERIVED
  71. // NOT SURE IT WILL BE REALLY UNIQUE FOR EACH CLASS!!
  72. /* Commented by James Chen
  73. Using 'getHashCodeByString(typeid(*native_obj).name())' instead of 'reinterpret_cast<long>(typeid(*native_obj).name());'.
  74. Since on win32 platform, 'reinterpret_cast<long>(typeid(*native_obj).name());' invoking in cocos2d.dll and outside cocos2d.dll(in TestJavascript.exe) will return different address.
  75. But the return string from typeid(*native_obj).name() is the same string, so we must convert the string to hash id to make sure we can get unique id.
  76. */
  77. // static const long id = reinterpret_cast<long>(typeid( DERIVED ).name());
  78. static const long id = getHashCodeByString(typeid( DERIVED ).name());
  79. return id;
  80. }
  81. static const char* s_name()
  82. {
  83. // return id unique for DERIVED
  84. // ALWAYS VALID BUT STRING, NOT INT - BUT VALID AND CROSS-PLATFORM/CROSS-VERSION COMPATBLE
  85. // AS FAR AS YOU KEEP THE CLASS NAME
  86. return typeid( DERIVED ).name();
  87. }
  88. };
  89. #define JS_NEW_PROXY(p, native_obj, js_obj) \
  90. do { \
  91. p = (js_proxy_t *)malloc(sizeof(js_proxy_t)); \
  92. assert(p); \
  93. js_proxy_t* native_obj##js_obj##tmp = NULL; \
  94. HASH_FIND_PTR(_native_js_global_ht, &native_obj, native_obj##js_obj##tmp); \
  95. assert(!native_obj##js_obj##tmp); \
  96. p->ptr = native_obj; \
  97. p->obj = js_obj; \
  98. HASH_ADD_PTR(_native_js_global_ht, ptr, p); \
  99. p = (js_proxy_t *)malloc(sizeof(js_proxy_t)); \
  100. assert(p); \
  101. native_obj##js_obj##tmp = NULL; \
  102. HASH_FIND_PTR(_js_native_global_ht, &js_obj, native_obj##js_obj##tmp); \
  103. assert(!native_obj##js_obj##tmp); \
  104. p->ptr = native_obj; \
  105. p->obj = js_obj; \
  106. HASH_ADD_PTR(_js_native_global_ht, obj, p); \
  107. } while(0) \
  108. #define JS_GET_PROXY(p, native_obj) \
  109. do { \
  110. HASH_FIND_PTR(_native_js_global_ht, &native_obj, p); \
  111. } while (0)
  112. #define JS_GET_NATIVE_PROXY(p, js_obj) \
  113. do { \
  114. HASH_FIND_PTR(_js_native_global_ht, &js_obj, p); \
  115. } while (0)
  116. #define JS_REMOVE_PROXY(nproxy, jsproxy) \
  117. do { \
  118. if (nproxy) { HASH_DEL(_native_js_global_ht, nproxy); free(nproxy); } \
  119. if (jsproxy) { HASH_DEL(_js_native_global_ht, jsproxy); free(jsproxy); } \
  120. } while (0)
  121. #define JS_TEST_NATIVE_OBJECT(cx, native_obj) \
  122. if (!native_obj) { \
  123. JS_ReportError(cx, "Invalid Native Object"); \
  124. return false; \
  125. }
  126. js_proxy_t* jsb_new_proxy(void* nativeObj, JSObject* jsObj);
  127. js_proxy_t* jsb_get_native_proxy(void* nativeObj);
  128. js_proxy_t* jsb_get_js_proxy(JSObject* jsObj);
  129. void jsb_remove_proxy(js_proxy_t* nativeProxy, js_proxy_t* jsProxy);
  130. void get_or_create_js_obj(JSContext* cx, JS::HandleObject obj, const std::string &name, JS::MutableHandleObject jsObj);
  131. /**
  132. * You don't need to manage the returned pointer. They live for the whole life of
  133. * the app.
  134. */
  135. template <class T>
  136. inline js_type_class_t *js_get_type_from_native(T* native_obj) {
  137. bool found = false;
  138. std::string typeName = typeid(*native_obj).name();
  139. auto typeProxyIter = _js_global_type_map.find(typeName);
  140. if (typeProxyIter == _js_global_type_map.end())
  141. {
  142. typeName = typeid(T).name();
  143. typeProxyIter = _js_global_type_map.find(typeName);
  144. if (typeProxyIter != _js_global_type_map.end())
  145. {
  146. found = true;
  147. }
  148. }
  149. else
  150. {
  151. found = true;
  152. }
  153. return found ? typeProxyIter->second : nullptr;
  154. }
  155. /**
  156. * The returned pointer should be deleted using jsb_remove_proxy. Most of the
  157. * time you do that in the C++ destructor.
  158. */
  159. template<class T>
  160. inline js_proxy_t *js_get_or_create_proxy(JSContext *cx, T *native_obj) {
  161. js_proxy_t *proxy;
  162. HASH_FIND_PTR(_native_js_global_ht, &native_obj, proxy);
  163. if (!proxy) {
  164. js_type_class_t *typeProxy = js_get_type_from_native<T>(native_obj);
  165. // Return NULL if can't find its type rather than making an assert.
  166. // assert(typeProxy);
  167. if (!typeProxy) {
  168. CCLOGINFO("Could not find the type of native object.");
  169. return NULL;
  170. }
  171. //JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
  172. JSObject* js_obj = JS_NewObject(cx, typeProxy->jsclass, JS::RootedObject(cx, typeProxy->proto), JS::RootedObject(cx,typeProxy->parentProto));
  173. proxy = jsb_new_proxy(native_obj, js_obj);
  174. #ifdef DEBUG
  175. JS::AddNamedObjectRoot(cx, &proxy->obj, typeid(*native_obj).name());
  176. #else
  177. JS::AddObjectRoot(cx, &proxy->obj);
  178. #endif
  179. return proxy;
  180. } else {
  181. return proxy;
  182. }
  183. return NULL;
  184. }
  185. } // namespace pluginx {
  186. #endif /* __JS_PLUGINX_SPIDERMONKEY_SPECIFICS_H__ */