mirror of https://github.com/axmolengine/axmol.git
Implement full GC relied memory model
This commit is contained in:
parent
022bcc24f1
commit
e1bc6640f4
|
@ -92,18 +92,6 @@ void Ref::retain()
|
|||
{
|
||||
CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
|
||||
++_referenceCount;
|
||||
|
||||
#if CC_ENABLE_SCRIPT_BINDING && CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
if (_scriptOwned && !_rooted)
|
||||
{
|
||||
auto scriptMgr = ScriptEngineManager::getInstance()->getScriptEngine();
|
||||
if (scriptMgr && scriptMgr->getScriptType() == kScriptTypeJavascript)
|
||||
{
|
||||
_referenceCountAtRootTime = _referenceCount-1;
|
||||
scriptMgr->rootObject(this);
|
||||
}
|
||||
}
|
||||
#endif // CC_ENABLE_SCRIPT_BINDING
|
||||
}
|
||||
|
||||
void Ref::release()
|
||||
|
@ -111,17 +99,6 @@ void Ref::release()
|
|||
CCASSERT(_referenceCount > 0, "reference count should be greater than 0");
|
||||
--_referenceCount;
|
||||
|
||||
#if CC_ENABLE_SCRIPT_BINDING && CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
if (_scriptOwned && _rooted && _referenceCount==/*_referenceCountAtRootTime*/ 1)
|
||||
{
|
||||
auto scriptMgr = ScriptEngineManager::getInstance()->getScriptEngine();
|
||||
if (scriptMgr && scriptMgr->getScriptType() == kScriptTypeJavascript)
|
||||
{
|
||||
scriptMgr->unrootObject(this);
|
||||
}
|
||||
}
|
||||
#endif // CC_ENABLE_SCRIPT_BINDING
|
||||
|
||||
if (_referenceCount == 0)
|
||||
{
|
||||
#if defined(COCOS2D_DEBUG) && (COCOS2D_DEBUG > 0)
|
||||
|
|
|
@ -642,6 +642,36 @@ public:
|
|||
*/
|
||||
virtual ccScriptType getScriptType() { return kScriptTypeNone; };
|
||||
|
||||
/**
|
||||
* Reflect the retain relationship to script scope
|
||||
*/
|
||||
virtual void retainScriptObject(Ref* owner, Ref* target) = 0;
|
||||
|
||||
/**
|
||||
* Add the script object to root object
|
||||
*/
|
||||
virtual void rootScriptObject(Ref* target) = 0;
|
||||
|
||||
/**
|
||||
* Reflect the release relationship to script scope
|
||||
*/
|
||||
virtual void releaseScriptObject(Ref* owner, Ref* target) = 0;
|
||||
|
||||
/**
|
||||
* Remove the script object from root object
|
||||
*/
|
||||
virtual void unrootScriptObject(Ref* target) = 0;
|
||||
|
||||
/**
|
||||
* Release all children native refs for the given node in script scope
|
||||
*/
|
||||
virtual void releaseAllChildrenRecursive(Node* node) = 0;
|
||||
|
||||
/**
|
||||
* Release all native refs for the given owner in script scope
|
||||
*/
|
||||
virtual void releaseAllNativeRefs(cocos2d::Ref* owner) = 0;
|
||||
|
||||
/**
|
||||
* Remove script object,The specific meaning should refer to the ScriptType.
|
||||
* For Lua, @see removeScriptObjectByObject of LuaEngine.
|
||||
|
|
|
@ -72,16 +72,20 @@
|
|||
#define TRACE_DEBUGGER_SERVER(...) CCLOG(__VA_ARGS__)
|
||||
#else
|
||||
#define TRACE_DEBUGGER_SERVER(...)
|
||||
#endif // #if DEBUG
|
||||
#endif // #if COCOS2D_DEBUG
|
||||
|
||||
#define BYTE_CODE_FILE_EXT ".jsc"
|
||||
|
||||
// EXPERIMENTAL: Enable this in order to get rid of retain/release
|
||||
// when using the Garbage Collector
|
||||
#define CC_ENABLE_GC_FOR_NATIVE_OBJECTS 0
|
||||
#define CC_ENABLE_GC_FOR_NATIVE_OBJECTS 1
|
||||
|
||||
using namespace cocos2d;
|
||||
|
||||
#if COCOS2D_DEBUG
|
||||
int ScriptingCore::retainCount = 0;
|
||||
#endif //COCOS2D_DEBUG
|
||||
|
||||
static std::string inData;
|
||||
static std::string outData;
|
||||
static std::vector<std::string> g_queue;
|
||||
|
@ -98,7 +102,7 @@ static void serverEntryPoint(unsigned int port);
|
|||
std::unordered_map<std::string, js_type_class_t*> _js_global_type_map;
|
||||
static std::unordered_map<void*, js_proxy_t*> _native_js_global_map;
|
||||
static std::unordered_map<JSObject*, js_proxy_t*> _js_native_global_map;
|
||||
|
||||
std::unordered_map<JSObject*, JSObject*> _js_hook_owner_map;
|
||||
|
||||
static char *_js_log_buf = NULL;
|
||||
|
||||
|
@ -215,22 +219,18 @@ static std::string getMouseFuncName(EventMouse::MouseEventType eventType)
|
|||
return funcName;
|
||||
}
|
||||
|
||||
static void removeJSObject(JSContext* cx, cocos2d::Ref* nativeObj)
|
||||
void removeJSObject(JSContext* cx, cocos2d::Ref* nativeObj)
|
||||
{
|
||||
auto proxy = jsb_get_native_proxy(nativeObj);
|
||||
if (proxy)
|
||||
{
|
||||
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
#if not CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
JS::RemoveObjectRoot(cx, &proxy->obj);
|
||||
#endif
|
||||
// remove the proxy here, since this was a "stack" object, not heap
|
||||
// when js_finalize will be called, it will fail, but
|
||||
// the correct solution is to have a new finalize for event
|
||||
jsb_remove_proxy(proxy);
|
||||
#else
|
||||
// only remove when not using GC,
|
||||
// otherwise finalize won't be able to find the proxy
|
||||
JS::RemoveObjectRoot(cx, &proxy->obj);
|
||||
jsb_remove_proxy(proxy);
|
||||
#endif
|
||||
}
|
||||
else CCLOG("removeJSObject: BUG: cannot find native object = %p", nativeObj);
|
||||
}
|
||||
|
@ -421,8 +421,6 @@ void registerDefaultClasses(JSContext* cx, JS::HandleObject global) {
|
|||
|
||||
JS_DefineFunction(cx, jsc, "garbageCollect", ScriptingCore::forceGC, 0, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
|
||||
JS_DefineFunction(cx, jsc, "dumpRoot", ScriptingCore::dumpRoot, 0, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
|
||||
JS_DefineFunction(cx, jsc, "addGCRootObject", ScriptingCore::addRootJS, 1, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
|
||||
JS_DefineFunction(cx, jsc, "removeGCRootObject", ScriptingCore::removeRootJS, 1, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
|
||||
JS_DefineFunction(cx, jsc, "executeScript", ScriptingCore::executeScript, 1, JSPROP_READONLY | JSPROP_PERMANENT | JSPROP_ENUMERATE );
|
||||
|
||||
// register some global functions
|
||||
|
@ -439,9 +437,8 @@ void registerDefaultClasses(JSContext* cx, JS::HandleObject global) {
|
|||
JS_DefineFunction(cx, global, "__isObjectValid", ScriptingCore::isObjectValid, 1, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
}
|
||||
|
||||
static void sc_finalize(JSFreeOp *freeOp, JSObject *obj)
|
||||
{
|
||||
CCLOG("jsbindings: finalizing JS object %p (global class)", obj);
|
||||
static void sc_finalize(JSFreeOp *freeOp, JSObject *obj) {
|
||||
CCLOGINFO("jsbindings: finalizing JS object %p (global class)", obj);
|
||||
}
|
||||
|
||||
//static JSClass global_class = {
|
||||
|
@ -618,11 +615,11 @@ void ScriptingCore::createGlobalContext() {
|
|||
_global.construct(_cx);
|
||||
_global.ref() = NewGlobalObject(_cx);
|
||||
|
||||
JSAutoCompartment ac(_cx, _global.ref());
|
||||
|
||||
// Removed in Firefox v34
|
||||
js::SetDefaultObjectForContext(_cx, _global.ref());
|
||||
|
||||
JSAutoCompartment ac(_cx, _global.ref());
|
||||
|
||||
runScript("script/jsb_prepare.js");
|
||||
|
||||
for (std::vector<sc_register_sth>::iterator it = registrationList.begin(); it != registrationList.end(); it++) {
|
||||
|
@ -876,9 +873,163 @@ bool ScriptingCore::log(JSContext* cx, uint32_t argc, jsval *vp)
|
|||
}
|
||||
|
||||
|
||||
void ScriptingCore::removeScriptObjectByObject(cocos2d::Ref* nativeObj)
|
||||
void ScriptingCore::retainScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target)
|
||||
{
|
||||
auto proxy = jsb_get_native_proxy(nativeObj);
|
||||
JS::RootedObject global(_cx, _global.ref());
|
||||
JS::RootedObject jsbObj(_cx);
|
||||
get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
|
||||
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
|
||||
if (jsbVal.isNullOrUndefined())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
js_proxy_t *pOwner = jsb_get_native_proxy(owner);
|
||||
js_proxy_t *pTarget = jsb_get_native_proxy(target);
|
||||
if (!pOwner || !pTarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
JS::RootedValue valOwner(_cx, OBJECT_TO_JSVAL(pOwner->obj));
|
||||
JS::RootedValue valTarget(_cx, OBJECT_TO_JSVAL(pTarget->obj));
|
||||
|
||||
JS::RootedValue retval(_cx);
|
||||
jsval valArr[2];
|
||||
valArr[0] = valOwner;
|
||||
valArr[1] = valTarget;
|
||||
|
||||
JS::HandleValueArray args = JS::HandleValueArray::fromMarkedLocation(2, valArr);
|
||||
executeFunctionWithOwner(jsbVal, "registerNativeRef", args, &retval);
|
||||
}
|
||||
|
||||
void ScriptingCore::rootScriptObject(cocos2d::Ref* target)
|
||||
{
|
||||
JS::RootedObject global(_cx, _global.ref());
|
||||
JS::RootedObject jsbObj(_cx);
|
||||
get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
|
||||
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
|
||||
if (jsbVal.isNullOrUndefined())
|
||||
{
|
||||
return;
|
||||
}
|
||||
js_proxy_t *pTarget = jsb_get_native_proxy(target);
|
||||
if (!pTarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
JS::RootedValue valTarget(_cx, OBJECT_TO_JSVAL(pTarget->obj));
|
||||
|
||||
JS::RootedObject root(_cx);
|
||||
get_or_create_js_obj(_cx, jsbObj, "_root", &root);
|
||||
JS::RootedValue valRoot(_cx, OBJECT_TO_JSVAL(root));
|
||||
|
||||
JS::RootedValue retval(_cx);
|
||||
jsval valArr[2];
|
||||
valArr[0] = valRoot;
|
||||
valArr[1] = valTarget;
|
||||
|
||||
JS::HandleValueArray args = JS::HandleValueArray::fromMarkedLocation(2, valArr);
|
||||
executeFunctionWithOwner(jsbVal, "registerNativeRef", args, &retval);
|
||||
}
|
||||
|
||||
void ScriptingCore::releaseScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target)
|
||||
{
|
||||
JS::RootedObject global(_cx, _global.ref());
|
||||
JS::RootedObject jsbObj(_cx);
|
||||
get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
|
||||
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
|
||||
if (jsbVal.isNullOrUndefined())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
js_proxy_t *pOwner = jsb_get_native_proxy(owner);
|
||||
js_proxy_t *pTarget = jsb_get_native_proxy(target);
|
||||
if (!pOwner || !pTarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
JS::RootedValue valOwner(_cx, OBJECT_TO_JSVAL(pOwner->obj));
|
||||
JS::RootedValue valTarget(_cx, OBJECT_TO_JSVAL(pTarget->obj));
|
||||
|
||||
JS::RootedValue retval(_cx);
|
||||
jsval valArr[2];
|
||||
valArr[0] = valOwner;
|
||||
valArr[1] = valTarget;
|
||||
|
||||
JS::HandleValueArray args = JS::HandleValueArray::fromMarkedLocation(2, valArr);
|
||||
executeFunctionWithOwner(jsbVal, "unregisterNativeRef", args, &retval);
|
||||
}
|
||||
|
||||
void ScriptingCore::unrootScriptObject(cocos2d::Ref* target)
|
||||
{
|
||||
JS::RootedObject global(_cx, _global.ref());
|
||||
JS::RootedObject jsbObj(_cx);
|
||||
get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
|
||||
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
|
||||
if (jsbVal.isNullOrUndefined())
|
||||
{
|
||||
return;
|
||||
}
|
||||
js_proxy_t *pTarget = jsb_get_native_proxy(target);
|
||||
if (!pTarget)
|
||||
{
|
||||
return;
|
||||
}
|
||||
JS::RootedValue valTarget(_cx, OBJECT_TO_JSVAL(pTarget->obj));
|
||||
|
||||
JS::RootedObject root(_cx);
|
||||
get_or_create_js_obj(_cx, jsbObj, "_root", &root);
|
||||
JS::RootedValue valRoot(_cx, OBJECT_TO_JSVAL(root));
|
||||
|
||||
JS::RootedValue retval(_cx);
|
||||
jsval valArr[2];
|
||||
valArr[0] = valRoot;
|
||||
valArr[1] = valTarget;
|
||||
|
||||
JS::HandleValueArray args = JS::HandleValueArray::fromMarkedLocation(2, valArr);
|
||||
executeFunctionWithOwner(jsbVal, "unregisterNativeRef", args, &retval);
|
||||
}
|
||||
|
||||
void ScriptingCore::releaseAllChildrenRecursive(cocos2d::Node *node)
|
||||
{
|
||||
const Vector<Node*>& children = node->getChildren();
|
||||
for (auto child : children)
|
||||
{
|
||||
releaseScriptObject(node, child);
|
||||
releaseAllChildrenRecursive(child);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptingCore::releaseAllNativeRefs(cocos2d::Ref* owner)
|
||||
{
|
||||
JS::RootedObject global(_cx, _global.ref());
|
||||
JS::RootedObject jsbObj(_cx);
|
||||
get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
|
||||
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
|
||||
if (jsbVal.isNullOrUndefined())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
js_proxy_t *pOwner = jsb_get_native_proxy(owner);
|
||||
if (!pOwner)
|
||||
{
|
||||
return;
|
||||
}
|
||||
JS::RootedValue valOwner(_cx, OBJECT_TO_JSVAL(pOwner->obj));
|
||||
|
||||
JS::RootedValue retval(_cx);
|
||||
jsval valArr[1];
|
||||
valArr[0] = valOwner;
|
||||
JS::HandleValueArray args = JS::HandleValueArray::fromMarkedLocation(1, valArr);
|
||||
executeFunctionWithOwner(jsbVal, "unregisterAllNativeRefs", args, &retval);
|
||||
}
|
||||
|
||||
|
||||
void ScriptingCore::removeScriptObjectByObject(Ref* pObj)
|
||||
{
|
||||
auto proxy = jsb_get_native_proxy(pObj);
|
||||
if (proxy)
|
||||
{
|
||||
JSContext *cx = getGlobalContext();
|
||||
|
@ -950,33 +1101,6 @@ bool ScriptingCore::dumpRoot(JSContext *cx, uint32_t argc, jsval *vp)
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ScriptingCore::addRootJS(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
if (argc == 1) {
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
JS::Heap<JSObject*> o(args.get(0).toObjectOrNull());
|
||||
if (AddNamedObjectRoot(cx, &o, "from-js") == false) {
|
||||
LOGD("something went wrong when setting an object to the root");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ScriptingCore::removeRootJS(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
if (argc == 1) {
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
JS::Heap<JSObject*> o(args.get(0).toObjectOrNull());
|
||||
if (o != nullptr) {
|
||||
JS::RemoveObjectRoot(cx, &o);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void ScriptingCore::pauseSchedulesAndActions(js_proxy_t* p)
|
||||
{
|
||||
JS::RootedObject obj(_cx, p->obj.get());
|
||||
|
@ -1024,6 +1148,7 @@ void ScriptingCore::cleanupSchedulesAndActions(js_proxy_t* p)
|
|||
|
||||
bool ScriptingCore::isFunctionOverridedInJS(JS::HandleObject obj, const std::string& name, JSNative native)
|
||||
{
|
||||
JSAutoCompartment ac(_cx, obj);
|
||||
JS::RootedValue value(_cx);
|
||||
bool ok = JS_GetProperty(_cx, obj, name.c_str(), &value);
|
||||
if (ok && !value.isNullOrUndefined() && !JS_IsNativeFunction(value.toObjectOrNull(), native))
|
||||
|
@ -1191,11 +1316,8 @@ bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::Eve
|
|||
JSAutoCompartment ac(_cx, _global.ref());
|
||||
|
||||
bool ret = false;
|
||||
|
||||
std::string funcName = getTouchesFuncName(eventCode);
|
||||
|
||||
JS::RootedObject jsretArr(_cx, JS_NewArrayObject(this->_cx, 0));
|
||||
|
||||
JS::RootedObject jsretArr(_cx, JS_NewArrayObject(_cx, 0));
|
||||
int count = 0;
|
||||
|
||||
js_type_class_t *typeClassEvent = nullptr;
|
||||
|
@ -1203,12 +1325,12 @@ bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::Eve
|
|||
|
||||
if (touches.size()>0)
|
||||
typeClassTouch = js_get_type_from_native<cocos2d::Touch>(touches[0]);
|
||||
typeClassEvent = js_get_type_from_native<cocos2d::Event>(event);
|
||||
typeClassEvent = js_get_type_from_native<cocos2d::EventTouch>((cocos2d::EventTouch*)event);
|
||||
|
||||
for (const auto& touch : touches)
|
||||
{
|
||||
JS::RootedValue jsret(_cx, OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, touch, typeClassTouch, "cocos2d::Touch")));
|
||||
if (!JS_SetElement(this->_cx, jsretArr, count, jsret))
|
||||
JS::RootedValue jsret(_cx, OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, touch, typeClassTouch, "cocos2d::Touch")));
|
||||
if (!JS_SetElement(_cx, jsretArr, count, jsret))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
@ -1220,13 +1342,13 @@ bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::Eve
|
|||
{
|
||||
jsval dataVal[2];
|
||||
dataVal[0] = OBJECT_TO_JSVAL(jsretArr);
|
||||
dataVal[1] = OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, event, typeClassEvent, "cocos2d::Event"));
|
||||
dataVal[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClassEvent, "cocos2d::EventTouch"));
|
||||
ret = executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), funcName.c_str(), 2, dataVal, jsvalRet);
|
||||
}
|
||||
|
||||
for (auto& touch : touches)
|
||||
{
|
||||
removeJSObject(this->_cx, touch);
|
||||
removeJSObject(_cx, touch);
|
||||
}
|
||||
|
||||
removeJSObject(_cx, event);
|
||||
|
@ -1251,11 +1373,11 @@ bool ScriptingCore::handleTouchEvent(void* nativeObj, cocos2d::EventTouch::Event
|
|||
if (p)
|
||||
{
|
||||
js_type_class_t *typeClassTouch = js_get_type_from_native<cocos2d::Touch>(touch);
|
||||
js_type_class_t *typeClassEvent = js_get_type_from_native<cocos2d::Event>(event);
|
||||
js_type_class_t *typeClassEvent = js_get_type_from_native<cocos2d::EventTouch>((cocos2d::EventTouch*)event);
|
||||
|
||||
jsval dataVal[2];
|
||||
dataVal[0] = OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, touch, typeClassTouch, "cocos2d::Touch"));
|
||||
dataVal[1] = OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, event, typeClassEvent, "cocos2d::Event"));
|
||||
dataVal[0] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, touch, typeClassTouch, "cocos2d::Touch"));
|
||||
dataVal[1] = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClassEvent, "cocos2d::EventTouch"));
|
||||
|
||||
ret = executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), funcName.c_str(), 2, dataVal, jsvalRet);
|
||||
}
|
||||
|
@ -1274,7 +1396,7 @@ bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::Mouse
|
|||
|
||||
bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::MouseEventType eventType, cocos2d::Event* event, JS::MutableHandleValue jsvalRet)
|
||||
{
|
||||
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
|
||||
JSAutoCompartment ac(_cx, _global.ref());
|
||||
|
||||
std::string funcName = getMouseFuncName(eventType);
|
||||
bool ret = false;
|
||||
|
@ -1282,8 +1404,8 @@ bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::Mouse
|
|||
js_proxy_t * p = jsb_get_native_proxy(nativeObj);
|
||||
if (p)
|
||||
{
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::Event>(event);
|
||||
jsval dataVal = OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, event, typeClass, "cocos2d::Event"));
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::EventMouse>((cocos2d::EventMouse*)event);
|
||||
jsval dataVal = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClass, "cocos2d::EventMouse"));
|
||||
ret = executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), funcName.c_str(), 1, &dataVal, jsvalRet);
|
||||
|
||||
removeJSObject(_cx, event);
|
||||
|
@ -1293,8 +1415,8 @@ bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::Mouse
|
|||
return ret;
|
||||
}
|
||||
|
||||
bool ScriptingCore::executeFunctionWithObjectData(void* nativeObj, const char *name, JSObject *obj) {
|
||||
|
||||
bool ScriptingCore::executeFunctionWithObjectData(void* nativeObj, const char *name, JSObject *obj)
|
||||
{
|
||||
js_proxy_t * p = jsb_get_native_proxy(nativeObj);
|
||||
if (!p) return false;
|
||||
|
||||
|
@ -1363,8 +1485,6 @@ bool ScriptingCore::executeFunctionWithOwner(jsval owner, const char *name, cons
|
|||
|
||||
bool ScriptingCore::handleKeybardEvent(void* nativeObj, cocos2d::EventKeyboard::KeyCode keyCode, bool isPressed, cocos2d::Event* event)
|
||||
{
|
||||
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
|
||||
|
||||
js_proxy_t * p = jsb_get_native_proxy(nativeObj);
|
||||
|
||||
if (nullptr == p)
|
||||
|
@ -1372,10 +1492,10 @@ bool ScriptingCore::handleKeybardEvent(void* nativeObj, cocos2d::EventKeyboard::
|
|||
|
||||
bool ret = false;
|
||||
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::Event>(event);
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::EventKeyboard>((cocos2d::EventKeyboard*)event);
|
||||
jsval args[2] = {
|
||||
int32_to_jsval(_cx, (int32_t)keyCode),
|
||||
OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, event, typeClass, "cocos2d::Event"))
|
||||
OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, event, typeClass, "cocos2d::EventKeyboard"))
|
||||
};
|
||||
|
||||
if (isPressed)
|
||||
|
@ -1394,8 +1514,6 @@ bool ScriptingCore::handleKeybardEvent(void* nativeObj, cocos2d::EventKeyboard::
|
|||
|
||||
bool ScriptingCore::handleFocusEvent(void* nativeObj, cocos2d::ui::Widget* widgetLoseFocus, cocos2d::ui::Widget* widgetGetFocus)
|
||||
{
|
||||
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
|
||||
|
||||
js_proxy_t * p = jsb_get_native_proxy(nativeObj);
|
||||
|
||||
if (nullptr == p)
|
||||
|
@ -1404,8 +1522,8 @@ bool ScriptingCore::handleFocusEvent(void* nativeObj, cocos2d::ui::Widget* widge
|
|||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::ui::Widget>(widgetLoseFocus);
|
||||
|
||||
jsval args[2] = {
|
||||
OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, widgetLoseFocus, typeClass, "cocos2d::ui::Widget")),
|
||||
OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(_cx, widgetGetFocus, typeClass, "cocos2d::ui::Widget"))
|
||||
OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, widgetLoseFocus, typeClass, "cocos2d::ui::Widget")),
|
||||
OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(_cx, widgetGetFocus, typeClass, "cocos2d::ui::Widget"))
|
||||
};
|
||||
|
||||
bool ret = executeFunctionWithOwner(OBJECT_TO_JSVAL(p->obj), "onFocusChanged", 2, args);
|
||||
|
@ -1420,13 +1538,12 @@ int ScriptingCore::executeCustomTouchesEvent(EventTouch::EventCode eventType,
|
|||
std::string funcName = getTouchesFuncName(eventType);
|
||||
|
||||
JS::RootedObject jsretArr(_cx, JS_NewArrayObject(this->_cx, 0));
|
||||
// JS_AddNamedObjectRoot(this->_cx, &jsretArr, "touchArray");
|
||||
int count = 0;
|
||||
for (auto& touch : touches)
|
||||
{
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::Touch>(touch);
|
||||
|
||||
jsval jsret = OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch"));
|
||||
jsval jsret = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch"));
|
||||
JS::RootedValue jsval(_cx, jsret);
|
||||
if (!JS_SetElement(this->_cx, jsretArr, count, jsval)) {
|
||||
break;
|
||||
|
@ -1436,7 +1553,6 @@ int ScriptingCore::executeCustomTouchesEvent(EventTouch::EventCode eventType,
|
|||
|
||||
jsval jsretArrVal = OBJECT_TO_JSVAL(jsretArr);
|
||||
executeFunctionWithOwner(OBJECT_TO_JSVAL(obj), funcName.c_str(), 1, &jsretArrVal);
|
||||
// JS_RemoveObjectRoot(this->_cx, &jsretArr);
|
||||
|
||||
for (auto& touch : touches)
|
||||
{
|
||||
|
@ -1449,17 +1565,14 @@ int ScriptingCore::executeCustomTouchesEvent(EventTouch::EventCode eventType,
|
|||
|
||||
int ScriptingCore::executeCustomTouchEvent(EventTouch::EventCode eventType, Touch *touch, JSObject *obj)
|
||||
{
|
||||
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
|
||||
|
||||
JS::RootedValue retval(_cx);
|
||||
std::string funcName = getTouchFuncName(eventType);
|
||||
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::Touch>(touch);
|
||||
jsval jsTouch = OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch"));
|
||||
jsval jsTouch = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch"));
|
||||
|
||||
executeFunctionWithOwner(OBJECT_TO_JSVAL(obj), funcName.c_str(), 1, &jsTouch, &retval);
|
||||
|
||||
// Remove touch object from global hash table and unroot it.
|
||||
removeJSObject(this->_cx, touch);
|
||||
|
||||
return 1;
|
||||
|
@ -1471,20 +1584,16 @@ int ScriptingCore::executeCustomTouchEvent(EventTouch::EventCode eventType,
|
|||
Touch *touch, JSObject *obj,
|
||||
JS::MutableHandleValue retval)
|
||||
{
|
||||
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
|
||||
|
||||
std::string funcName = getTouchFuncName(eventType);
|
||||
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::Touch>(touch);
|
||||
jsval jsTouch = OBJECT_TO_JSVAL(jsb_ref_get_or_create_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch"));
|
||||
jsval jsTouch = OBJECT_TO_JSVAL(jsb_get_or_create_weak_jsobject(this->_cx, touch, typeClass, "cocos2d::Touch"));
|
||||
|
||||
executeFunctionWithOwner(OBJECT_TO_JSVAL(obj), funcName.c_str(), 1, &jsTouch, retval);
|
||||
|
||||
// Remove touch object from global hash table and unroot it.
|
||||
removeJSObject(this->_cx, touch);
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int ScriptingCore::sendEvent(ScriptEvent* evt)
|
||||
|
@ -1499,8 +1608,6 @@ int ScriptingCore::sendEvent(ScriptEvent* evt)
|
|||
return 0;
|
||||
}
|
||||
|
||||
JSAutoCompartment ac(_cx, _global.ref());
|
||||
|
||||
switch (evt->type)
|
||||
{
|
||||
case kNodeEvent:
|
||||
|
@ -2008,72 +2115,126 @@ void jsb_remove_proxy(js_proxy_t* proxy)
|
|||
//
|
||||
|
||||
// ref_create
|
||||
JSObject* jsb_ref_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
JS::HandleObject jsb_ref_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
{
|
||||
JS::RootedObject proto(cx, typeClass->proto.ref());
|
||||
JS::RootedObject parent(cx, typeClass->parentProto.ref());
|
||||
JS::RootedObject js_obj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
js_proxy_t* newproxy = jsb_new_proxy(ref, js_obj);
|
||||
JS::RootedObject jsObj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
js_proxy_t* newproxy = jsb_new_proxy(ref, jsObj);
|
||||
jsb_ref_init(cx, &newproxy->obj, ref, debug);
|
||||
return js_obj;
|
||||
return jsObj;
|
||||
}
|
||||
|
||||
JSObject* jsb_ref_autoreleased_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
JS::HandleObject jsb_ref_autoreleased_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
{
|
||||
JS::RootedObject proto(cx, typeClass->proto.ref());
|
||||
JS::RootedObject parent(cx, typeClass->parentProto.ref());
|
||||
JS::RootedObject js_obj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
js_proxy_t* newproxy = jsb_new_proxy(ref, js_obj);
|
||||
JS::RootedObject jsObj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
js_proxy_t* newproxy = jsb_new_proxy(ref, jsObj);
|
||||
jsb_ref_autoreleased_init(cx, &newproxy->obj, ref, debug);
|
||||
return js_obj;
|
||||
return jsObj;
|
||||
}
|
||||
|
||||
JS::HandleObject jsb_create_weak_jsobject(JSContext *cx, void *native, js_type_class_t *typeClass, const char* debug)
|
||||
{
|
||||
JS::RootedObject proto(cx, typeClass->proto.ref());
|
||||
JS::RootedObject parent(cx, typeClass->parentProto.ref());
|
||||
JS::RootedObject jsObj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
jsb_new_proxy(native, jsObj);
|
||||
|
||||
#if not CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
JS::AddNamedObjectRoot(cx, &proxy->obj, debug);
|
||||
#else
|
||||
#if COCOS2D_DEBUG
|
||||
CCLOG("++++++WEAK_REF++++++ Cpp(%s): %p - JS: %p", debug, native, jsObj.get());
|
||||
#endif // COCOS2D_DEBUG
|
||||
#endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
return jsObj;
|
||||
}
|
||||
|
||||
// get_or_create
|
||||
JSObject* jsb_ref_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
JS::HandleObject jsb_ref_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
{
|
||||
auto proxy = jsb_get_native_proxy(ref);
|
||||
if (proxy)
|
||||
return proxy->obj;
|
||||
{
|
||||
JS::RootedObject obj(cx, proxy->obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// don't auto-release, don't retain.
|
||||
JS::RootedObject proto(cx, typeClass->proto.ref());
|
||||
JS::RootedObject parent(cx, typeClass->parentProto.ref());
|
||||
JS::RootedObject js_obj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
js_proxy_t* newproxy = jsb_new_proxy(ref, js_obj);
|
||||
JS::RootedObject jsObj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
js_proxy_t* newproxy = jsb_new_proxy(ref, jsObj);
|
||||
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
CC_UNUSED_PARAM(newproxy);
|
||||
|
||||
// retain first copy, and before "owning" to prevent it
|
||||
// from calling "rootObject"
|
||||
ref->retain();
|
||||
ref->_scriptOwned = true;
|
||||
js_add_FinalizeHook(cx, jsObj);
|
||||
#if COCOS2D_DEBUG
|
||||
ScriptingCore::retainCount++;
|
||||
CCLOG("++++++RETAINED++++++ %d Cpp(%s): %p - JS: %p", ScriptingCore::retainCount, debug, ref, jsObj.get());
|
||||
#endif // COCOS2D_DEBUG
|
||||
#else
|
||||
// don't autorelease it
|
||||
JS::AddNamedObjectRoot(cx, &newproxy->obj, debug);
|
||||
#endif
|
||||
#endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
|
||||
return js_obj;
|
||||
return jsObj;
|
||||
}
|
||||
|
||||
// get_or_create: REf is already autoreleased (or created)
|
||||
JSObject* jsb_ref_autoreleased_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
// get_or_create: Ref is already autoreleased (or created)
|
||||
JS::HandleObject jsb_ref_autoreleased_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug)
|
||||
{
|
||||
auto proxy = jsb_get_native_proxy(ref);
|
||||
if (proxy)
|
||||
return proxy->obj;
|
||||
{
|
||||
JS::RootedObject obj(cx, proxy->obj);
|
||||
return obj;
|
||||
}
|
||||
// else
|
||||
return jsb_ref_autoreleased_create_jsobject(cx, ref, typeClass, debug);
|
||||
}
|
||||
|
||||
// get_or_create: when native object isn't a ref object or when the native object life cycle don't need to be managed by js object
|
||||
JS::HandleObject jsb_get_or_create_weak_jsobject(JSContext *cx, void *native, js_type_class_t *typeClass, const char* debug)
|
||||
{
|
||||
auto proxy = jsb_get_native_proxy(native);
|
||||
if (proxy)
|
||||
{
|
||||
JS::RootedObject obj(cx, proxy->obj);
|
||||
return obj;
|
||||
}
|
||||
|
||||
// don't auto-release, don't retain.
|
||||
JS::RootedObject proto(cx, typeClass->proto.ref());
|
||||
JS::RootedObject parent(cx, typeClass->parentProto.ref());
|
||||
JS::RootedObject jsObj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
proxy = jsb_new_proxy(native, jsObj);
|
||||
|
||||
#if not CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
JS::AddNamedObjectRoot(cx, &proxy->obj, debug);
|
||||
#else
|
||||
#if COCOS2D_DEBUG
|
||||
CCLOG("++++++WEAK_REF++++++ Cpp(%s): %p - JS: %p", debug, native, jsObj.get());
|
||||
#endif // COCOS2D_DEBUG
|
||||
#endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
return jsObj;
|
||||
}
|
||||
|
||||
// ref_init
|
||||
void jsb_ref_init(JSContext* cx, JS::Heap<JSObject*> *obj, Ref* ref, const char* debug)
|
||||
{
|
||||
// CCLOG("jsb_ref_init: JSObject address = %p. %s", obj->get(), debug);
|
||||
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
(void)cx;
|
||||
(void)obj;
|
||||
ref->_scriptOwned = true;
|
||||
(void)ref;
|
||||
JS::RootedObject jsObj(cx, *obj);
|
||||
js_add_FinalizeHook(cx, jsObj);
|
||||
// don't retain it, already retained
|
||||
#if COCOS2D_DEBUG
|
||||
ScriptingCore::retainCount++;
|
||||
CCLOG("++++++RETAINED++++++ %d Cpp(%s): %p - JS: %p", ScriptingCore::retainCount, debug, ref, jsObj.get());
|
||||
#endif // COCOS2D_DEBUG
|
||||
#else
|
||||
// autorelease it
|
||||
ref->autorelease();
|
||||
|
@ -2087,46 +2248,46 @@ void jsb_ref_autoreleased_init(JSContext* cx, JS::Heap<JSObject*> *obj, Ref* ref
|
|||
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
(void)cx;
|
||||
(void)obj;
|
||||
// retain first copy, and before "owning" to prevent it
|
||||
// from calling "rootObject"
|
||||
ref->retain();
|
||||
ref->_scriptOwned = true;
|
||||
JS::RootedObject jsObj(cx, *obj);
|
||||
js_add_FinalizeHook(cx, jsObj);
|
||||
#else
|
||||
// don't autorelease it, since it is already autoreleased
|
||||
JS::AddNamedObjectRoot(cx, obj, debug);
|
||||
#endif
|
||||
}
|
||||
|
||||
// finalize
|
||||
void jsb_ref_finalize(JSFreeOp* fop, JSObject* obj)
|
||||
{
|
||||
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
auto proxy = jsb_get_js_proxy(obj);
|
||||
if (proxy)
|
||||
{
|
||||
auto ref = static_cast<cocos2d::Ref*>(proxy->ptr);
|
||||
jsb_remove_proxy(proxy);
|
||||
if (ref)
|
||||
ref->release();
|
||||
}
|
||||
else
|
||||
{
|
||||
CCLOG("jsb_ref_finalize: BUG: proxy not found for %p (%s)", obj, JS_GetClass(obj)->name);
|
||||
}
|
||||
#else
|
||||
// CCLOG("jsb_ref_finalize: JSObject address = %p", obj);
|
||||
#endif
|
||||
}
|
||||
|
||||
// rebind
|
||||
void jsb_ref_rebind(JSContext* cx, JS::HandleObject jsobj, js_proxy_t *proxy, cocos2d::Ref* oldRef, cocos2d::Ref* newRef, const char* debug)
|
||||
{
|
||||
#if not CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
// Release the old reference as it have been retained by jsobj previously,
|
||||
// and the jsobj won't have any chance to release it in the future
|
||||
oldRef->release();
|
||||
#else
|
||||
JS::RemoveObjectRoot(cx, &proxy->obj);
|
||||
#endif
|
||||
jsb_remove_proxy(proxy);
|
||||
|
||||
// Rebind js obj with new action
|
||||
js_proxy_t* newProxy = jsb_new_proxy(newRef, jsobj);
|
||||
jsb_ref_init(cx, &newProxy->obj, newRef, debug);
|
||||
jsb_new_proxy(newRef, jsobj);
|
||||
}
|
||||
|
||||
// Register finalize hook
|
||||
void jsb_register_finalize_hook(JSObject *hook, JSObject *owner)
|
||||
{
|
||||
_js_hook_owner_map.insert(std::make_pair(hook, owner));
|
||||
}
|
||||
|
||||
// Remove hook owner entry in _js_hook_owner_map
|
||||
JSObject *jsb_get_and_remove_hook_owner(JSObject *hook)
|
||||
{
|
||||
auto ownerIt = _js_hook_owner_map.find(hook);
|
||||
// Found
|
||||
if (ownerIt != _js_hook_owner_map.cend())
|
||||
{
|
||||
_js_hook_owner_map.erase(ownerIt);
|
||||
return ownerIt->second;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -88,6 +88,10 @@ private:
|
|||
bool _callFromScript;
|
||||
ScriptingCore();
|
||||
public:
|
||||
#if COCOS2D_DEBUG
|
||||
static int retainCount;
|
||||
#endif // COCOS2D_DEBUG
|
||||
|
||||
~ScriptingCore();
|
||||
|
||||
/**@~english
|
||||
|
@ -102,6 +106,36 @@ public:
|
|||
*/
|
||||
virtual cocos2d::ccScriptType getScriptType() override { return cocos2d::kScriptTypeJavascript; };
|
||||
|
||||
/**
|
||||
* Reflect the retain relationship to script scope
|
||||
*/
|
||||
virtual void retainScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target) override;
|
||||
|
||||
/**
|
||||
* Add the script object to root object
|
||||
*/
|
||||
virtual void rootScriptObject(cocos2d::Ref* target) override;
|
||||
|
||||
/**
|
||||
* Reflect the release relationship to script scope
|
||||
*/
|
||||
virtual void releaseScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target) override;
|
||||
|
||||
/**
|
||||
* Remove the script object from root object
|
||||
*/
|
||||
virtual void unrootScriptObject(cocos2d::Ref* target) override;
|
||||
|
||||
/**
|
||||
* Release all children in script scope
|
||||
*/
|
||||
virtual void releaseAllChildrenRecursive(cocos2d::Node *node) override;
|
||||
|
||||
/**
|
||||
* Release all native refs for the given owner in script scope
|
||||
*/
|
||||
virtual void releaseAllNativeRefs(cocos2d::Ref* owner) override;
|
||||
|
||||
/**
|
||||
* @brief @~english Removes the C++ object's linked JavaScript proxy object from JavaScript context
|
||||
* @param obj @~english Object to be removed
|
||||
|
@ -438,22 +472,6 @@ public:
|
|||
* @param vp @~english The arguments
|
||||
*/
|
||||
static bool dumpRoot(JSContext *cx, uint32_t argc, jsval *vp);
|
||||
/**@~english
|
||||
* Adds a js object to root so that it won't be touched by the garbage collection, it should be invoked from script environment
|
||||
* Bound to `__jsc__.addGCRootObject`
|
||||
* @param cx @~english The js context
|
||||
* @param argc @~english The arguments count
|
||||
* @param vp @~english The arguments
|
||||
*/
|
||||
static bool addRootJS(JSContext *cx, uint32_t argc, jsval *vp);
|
||||
/**@~english
|
||||
* Removes a js object from root, it should be invoked from script environment
|
||||
* Bound to `__jsc__.removeGCRootObject`
|
||||
* @param cx @~english The js context
|
||||
* @param argc @~english The arguments count
|
||||
* @param vp @~english The arguments
|
||||
*/
|
||||
static bool removeRootJS(JSContext *cx, uint32_t argc, jsval *vp);
|
||||
/**@~english
|
||||
* Check whether a js object's C++ proxy is still valid, it should be invoked from script environment
|
||||
* Bound to `window.__isObjectValid`
|
||||
|
@ -573,6 +591,9 @@ js_proxy_t* jsb_get_js_proxy(JSObject* jsObj);
|
|||
void jsb_remove_proxy(js_proxy_t* nativeProxy, js_proxy_t* jsProxy);
|
||||
/** removes both the native and js proxies */
|
||||
void jsb_remove_proxy(js_proxy_t* proxy);
|
||||
/** removes the native js object proxy and unroot the js object (if necessary),
|
||||
it's often used when JS object is created by native object */
|
||||
void removeJSObject(JSContext* cx, cocos2d::Ref* nativeObj);
|
||||
|
||||
/**
|
||||
* Generic initialization function for subclasses of Ref
|
||||
|
@ -588,20 +609,15 @@ void jsb_ref_init(JSContext* cx, JS::Heap<JSObject*> *obj, cocos2d::Ref* ref, co
|
|||
void jsb_ref_autoreleased_init(JSContext* cx, JS::Heap<JSObject*> *obj, cocos2d::Ref* ref, const char* debug);
|
||||
|
||||
/**
|
||||
* Generic finalize used by objects that are subclass of Ref
|
||||
*/
|
||||
void jsb_ref_finalize(JSFreeOp* fop, JSObject* obj);
|
||||
|
||||
/**
|
||||
Disassociates oldRef from jsobj, and associates a new Ref.
|
||||
Useful for the EaseActions and others
|
||||
* Disassociates oldRef from jsobj, and associates a new Ref.
|
||||
* Useful for the EaseActions and others
|
||||
*/
|
||||
void jsb_ref_rebind(JSContext* cx, JS::HandleObject jsobj, js_proxy_t *js2native_proxy, cocos2d::Ref* oldRef, cocos2d::Ref* newRef, const char* debug);
|
||||
|
||||
/**
|
||||
Creates a new JSObject of a certain type (typeClass) and creates a proxy associated with and the Ref
|
||||
* Creates a new JSObject of a certain type (typeClass) and creates a proxy associated with and the Ref
|
||||
*/
|
||||
JSObject* jsb_ref_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
JS::HandleObject jsb_ref_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
|
||||
/**
|
||||
* Creates a new JSObject of a certain type (typeClass) and creates a proxy associated with and the Ref
|
||||
|
@ -609,20 +625,46 @@ JSObject* jsb_ref_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_clas
|
|||
* This function should never be called. It is only added as way to fix
|
||||
* an issue with the static auto-bindings with the "create" function
|
||||
*/
|
||||
JSObject* jsb_ref_autoreleased_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
JS::HandleObject jsb_ref_autoreleased_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
|
||||
/**
|
||||
It will try to get the associated JSObjct for ref.
|
||||
If it can't find it, it will create a new one associating it to Ref.
|
||||
Call this function for objects that were already created and initialized, when returning `getChild()`
|
||||
* It will try to get the associated JSObjct for the native object.
|
||||
* The reference created from JSObject to native object is weak because it won't retain it.
|
||||
* The behavior is exactly the same with 'jsb_ref_create_jsobject' when CC_ENABLE_GC_FOR_NATIVE_OBJECTS desactivated.
|
||||
*/
|
||||
JSObject* jsb_ref_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
JS::HandleObject jsb_create_weak_jsobject(JSContext *cx, void *native, js_type_class_t *typeClass, const char* debug);
|
||||
|
||||
/**
|
||||
It will try to get the associated JSObjct for ref.
|
||||
If it can't find it, it will create a new one associating it to Ref
|
||||
Call this function for objects that might return an already existing copy when you create them. For example, `Animation3D::create()`;
|
||||
* It will try to get the associated JSObjct for ref.
|
||||
* If it can't find it, it will create a new one associating it to Ref.
|
||||
* Call this function for objects that were already created and initialized, when returning `getChild()`
|
||||
*/
|
||||
JSObject* jsb_ref_autoreleased_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
JS::HandleObject jsb_ref_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
|
||||
/**
|
||||
* It will try to get the associated JSObjct for ref.
|
||||
* If it can't find it, it will create a new one associating it to Ref
|
||||
* Call this function for objects that might return an already existing copy when you create them. For example, `Animation3D::create()`;
|
||||
*/
|
||||
JS::HandleObject jsb_ref_autoreleased_get_or_create_jsobject(JSContext *cx, cocos2d::Ref *ref, js_type_class_t *typeClass, const char* debug);
|
||||
|
||||
/**
|
||||
* It will try to get the associated JSObjct for the native object.
|
||||
* If it can't find it, it will create a new one associating it to the native object.
|
||||
* The reference created from JSObject to native object is weak because it won't retain it.
|
||||
* The behavior is exactly the same with 'jsb_ref_get_or_create_jsobject' when CC_ENABLE_GC_FOR_NATIVE_OBJECTS desactivated.
|
||||
*/
|
||||
JS::HandleObject jsb_get_or_create_weak_jsobject(JSContext *cx, void *native, js_type_class_t *typeClass, const char* debug);
|
||||
|
||||
/**
|
||||
* Register finalize hook and its owner as an entry in _js_hook_owner_map,
|
||||
* so that we can find the owner of a FinalizeHook in its finalize function
|
||||
*/
|
||||
void jsb_register_finalize_hook(JSObject *hook, JSObject *owner);
|
||||
|
||||
/**
|
||||
* Remove the entry of finalize hook and its owner in _js_hook_owner_map
|
||||
*/
|
||||
JSObject *jsb_get_and_remove_hook_owner(JSObject *hook);
|
||||
|
||||
#endif /* __SCRIPTING_CORE_H__ */
|
||||
|
|
|
@ -422,72 +422,6 @@ bool js_cocos2dx_CCMenuItemToggle_create(JSContext *cx, uint32_t argc, jsval *vp
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: This function is deprecated. The new API is "new Animation" instead of "Animation.create"
|
||||
// There are not js tests for this function. Impossible to know weather it works Ok.
|
||||
bool js_cocos2dx_CCAnimation_create(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
bool ok = true;
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
if (argc <= 3) {
|
||||
cocos2d::Animation* ret = nullptr;
|
||||
double arg1 = 0.0f;
|
||||
if (argc == 2)
|
||||
{
|
||||
Vector<SpriteFrame*> arg0;
|
||||
if (argc > 0) {
|
||||
ok &= jsval_to_ccvector(cx, args.get(0), &arg0);
|
||||
JSB_PRECONDITION2(ok, cx, false, "Error processing arguments");
|
||||
}
|
||||
JS::RootedValue jsarg1(cx, args.get(1));
|
||||
ok &= JS::ToNumber(cx, jsarg1, &arg1);
|
||||
JSB_PRECONDITION2(ok, cx, false, "Error processing arguments");
|
||||
ret = new (std::nothrow) cocos2d::Animation;
|
||||
ok &= ret->initWithSpriteFrames(arg0, arg1);
|
||||
}
|
||||
else if (argc == 3)
|
||||
{
|
||||
Vector<AnimationFrame*> arg0;
|
||||
if (argc > 0) {
|
||||
ok &= jsval_to_ccvector(cx, args.get(0), &arg0);
|
||||
JSB_PRECONDITION2(ok, cx, false, "Error processing arguments");
|
||||
}
|
||||
unsigned int loops;
|
||||
JS::RootedValue jsarg1(cx, args.get(1));
|
||||
ok &= JS::ToNumber(cx, jsarg1, &arg1);
|
||||
ok &= jsval_to_uint32(cx, args.get(2), &loops);
|
||||
JSB_PRECONDITION2(ok, cx, false, "Error processing arguments");
|
||||
ret = new (std::nothrow) cocos2d::Animation;
|
||||
ok &= ret->initWithAnimationFrames(arg0, arg1, loops);
|
||||
}
|
||||
else if (argc == 1)
|
||||
{
|
||||
Vector<SpriteFrame*> arg0;
|
||||
if (argc > 0) {
|
||||
ok &= jsval_to_ccvector(cx, args.get(0), &arg0);
|
||||
JSB_PRECONDITION2(ok, cx, false, "Error processing arguments");
|
||||
}
|
||||
ret = new (std::nothrow) cocos2d::Animation;
|
||||
ok &= ret->initWithSpriteFrames(arg0);
|
||||
}
|
||||
else if (argc == 0)
|
||||
{
|
||||
ret = new (std::nothrow) cocos2d::Animation;
|
||||
ok = ret->init();
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::Animation>(ret);
|
||||
// link the native object with the javascript object
|
||||
JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, ret, typeClass, "cocos2d::Animation"));
|
||||
args.rval().set(OBJECT_TO_JSVAL(jsobj));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
JS_ReportError(cx, "wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool js_cocos2dx_CCScene_init(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
|
@ -507,30 +441,6 @@ bool js_cocos2dx_CCScene_init(JSContext *cx, uint32_t argc, jsval *vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: This function is deprecated. The new API is "new LayerMultiplex" instead of "LayerMultiplex.create"
|
||||
// There are not js tests for this function. Impossible to know weather it works Ok.
|
||||
bool js_cocos2dx_CCLayerMultiplex_create(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
Vector<Layer*> arg0;
|
||||
bool ok = true;
|
||||
ok &= jsvals_variadic_to_ccvector(cx, args, &arg0);
|
||||
JSB_PRECONDITION2(ok, cx, false, "Error processing arguments");
|
||||
|
||||
cocos2d::LayerMultiplex* ret = new (std::nothrow) cocos2d::LayerMultiplex;
|
||||
ok &= ret->initWithArray(arg0);
|
||||
if (ok)
|
||||
{
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::LayerMultiplex>(ret);
|
||||
// link the native object with the javascript object
|
||||
JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, ret, typeClass, "cocos2d::LayerMultiplex"));
|
||||
args.rval().set(OBJECT_TO_JSVAL(jsobj));
|
||||
return true;
|
||||
}
|
||||
JS_ReportError(cx, "Error creating LayerMultiplex");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool js_cocos2dx_JSTouchDelegate_registerStandardDelegate(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
if (argc == 1 || argc == 2)
|
||||
|
@ -604,6 +514,15 @@ JSObject* getObjectFromNamespace(JSContext* cx, JS::HandleObject ns, const char
|
|||
return NULL;
|
||||
}
|
||||
|
||||
void js_add_FinalizeHook(JSContext *cx, JS::HandleObject target)
|
||||
{
|
||||
JS::RootedObject proto(cx, jsb_FinalizeHook_prototype);
|
||||
JS::RootedObject hook(cx, JS_NewObject(cx, jsb_FinalizeHook_class, proto, JS::NullPtr()));
|
||||
jsb_register_finalize_hook(hook.get(), target.get());
|
||||
JS::RootedValue hookVal(cx, OBJECT_TO_JSVAL(hook));
|
||||
JS_SetProperty(cx, target, "__hook", hookVal);
|
||||
}
|
||||
|
||||
jsval anonEvaluate(JSContext *cx, JS::HandleObject thisObj, const char* string) {
|
||||
JS::RootedValue out(cx);
|
||||
//JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
|
||||
|
@ -2064,12 +1983,14 @@ bool js_forceGC(JSContext *cx, uint32_t argc, jsval *vp) {
|
|||
bool js_cocos2dx_retain(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
#if not CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
|
||||
js_proxy_t *proxy = jsb_get_js_proxy(obj);
|
||||
cocos2d::Ref* cobj = (cocos2d::Ref *)(proxy ? proxy->ptr : NULL);
|
||||
JSB_PRECONDITION2( cobj, cx, false, "js_cocos2dx_retain : Invalid Native Object");
|
||||
|
||||
cobj->retain();
|
||||
#endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
@ -2077,12 +1998,14 @@ bool js_cocos2dx_retain(JSContext *cx, uint32_t argc, jsval *vp)
|
|||
bool js_cocos2dx_release(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
#if not CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
|
||||
js_proxy_t *proxy = jsb_get_js_proxy(obj);
|
||||
cocos2d::Ref* cobj = (cocos2d::Ref *)(proxy ? proxy->ptr : NULL);
|
||||
JSB_PRECONDITION2( cobj, cx, false, "js_cocos2dx_release : Invalid Native Object");
|
||||
|
||||
cobj->release();
|
||||
#endif // CC_ENABLE_GC_FOR_NATIVE_OBJECTS
|
||||
args.rval().setUndefined();
|
||||
return true;
|
||||
}
|
||||
|
@ -2971,7 +2894,8 @@ bool js_CatmullRomActions_initWithDuration(JSContext *cx, uint32_t argc, jsval *
|
|||
JSB_PRECONDITION2( cobj, cx, false, "js_cocos2dx_CatmullRom_initWithDuration : Invalid Native Object");
|
||||
if (argc == 2) {
|
||||
double arg0;
|
||||
ok &= JS::ToNumber( cx, JS::RootedValue(cx, args.get(0)), &arg0);
|
||||
JS::RootedValue jsarg0(cx, args.get(0));
|
||||
ok &= JS::ToNumber(cx, jsarg0, &arg0);
|
||||
|
||||
int num;
|
||||
Point *arr;
|
||||
|
@ -3034,7 +2958,8 @@ bool js_cocos2dx_CardinalSplineTo_initWithDuration(JSContext *cx, uint32_t argc,
|
|||
double arg0;
|
||||
|
||||
double arg2;
|
||||
ok &= JS::ToNumber( cx, JS::RootedValue(cx, args.get(0)), &arg0);
|
||||
JS::RootedValue jsarg0(cx, args.get(0));
|
||||
ok &= JS::ToNumber(cx, jsarg0, &arg0);
|
||||
|
||||
int num;
|
||||
Point *arr;
|
||||
|
@ -3044,7 +2969,8 @@ bool js_cocos2dx_CardinalSplineTo_initWithDuration(JSContext *cx, uint32_t argc,
|
|||
arg1->addControlPoint(arr[i]);
|
||||
}
|
||||
|
||||
ok &= JS::ToNumber( cx, JS::RootedValue(cx, args.get(2)), &arg2);
|
||||
JS::RootedValue jsarg2(cx, args.get(2));
|
||||
ok &= JS::ToNumber(cx, jsarg2, &arg2);
|
||||
JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_CardinalSplineTo_initWithDuration : Error processing arguments");
|
||||
bool ret = cobj->initWithDuration(arg0, arg1, arg2);
|
||||
|
||||
|
@ -3060,11 +2986,13 @@ bool js_cocos2dx_CardinalSplineTo_initWithDuration(JSContext *cx, uint32_t argc,
|
|||
}
|
||||
|
||||
|
||||
bool JSB_CCCatmullRomBy_actionWithDuration(JSContext *cx, uint32_t argc, jsval *vp) {
|
||||
bool JSB_CCCatmullRomBy_actionWithDuration(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
return js_CatmullRomActions_create<cocos2d::CatmullRomBy>(cx, argc, vp);
|
||||
}
|
||||
|
||||
bool JSB_CCCatmullRomTo_actionWithDuration(JSContext *cx, uint32_t argc, jsval *vp) {
|
||||
bool JSB_CCCatmullRomTo_actionWithDuration(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
return js_CatmullRomActions_create<cocos2d::CatmullRomTo>(cx, argc, vp);
|
||||
}
|
||||
|
||||
|
@ -3746,60 +3674,6 @@ bool js_cocos2dx_ccquatMultiply(JSContext *cx, uint32_t argc, jsval *vp)
|
|||
return false;
|
||||
}
|
||||
|
||||
// TODO: This function is deprecated. The new API is "new Sprite" instead of "Sprite.create"
|
||||
// There are not js tests for this function. Impossible to know weather it works Ok.
|
||||
bool js_cocos2dx_Sprite_create(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
bool ok = false;
|
||||
|
||||
cocos2d::Sprite *sprite = nullptr;
|
||||
|
||||
if (argc == 0)
|
||||
{
|
||||
sprite = new (std::nothrow) cocos2d::Sprite;
|
||||
sprite->init();
|
||||
ok = true;
|
||||
}
|
||||
else if (argc == 1)
|
||||
{
|
||||
std::string arg0;
|
||||
ok = jsval_to_std_string(cx, args.get(0), &arg0);
|
||||
if (ok)
|
||||
{
|
||||
sprite = new (std::nothrow) cocos2d::Sprite;
|
||||
sprite->initWithFile(arg0);
|
||||
}
|
||||
}
|
||||
else if(argc == 2)
|
||||
{
|
||||
std::string arg0;
|
||||
ok = jsval_to_std_string(cx, args.get(0), &arg0);
|
||||
cocos2d::Rect arg1;
|
||||
ok |= jsval_to_ccrect(cx, args.get(1), &arg1);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
sprite = new (std::nothrow) cocos2d::Sprite;
|
||||
sprite->initWithFile(arg0, arg1);
|
||||
}
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::Sprite>(sprite);
|
||||
// link the native object with the javascript object
|
||||
JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, sprite, typeClass, "cocos2d::Sprite"));
|
||||
args.rval().set(OBJECT_TO_JSVAL(jsobj));
|
||||
return true;
|
||||
}
|
||||
|
||||
// else
|
||||
|
||||
JS_ReportError(cx, "js_cocos2dx_Sprite_create : wrong number of arguments");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool js_cocos2dx_Sprite_initWithPolygon(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
|
@ -4298,64 +4172,6 @@ bool js_cocos2dx_CCGLProgram_setUniformLocationWithMatrixfvUnion(JSContext *cx,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool js_cocos2dx_CCGLProgram_create(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
bool ok = true;
|
||||
if(argc != 2) {
|
||||
JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *arg0, *arg1;
|
||||
std::string arg0_tmp; ok &= jsval_to_std_string(cx, args.get(0), &arg0_tmp); arg0 = arg0_tmp.c_str();
|
||||
std::string arg1_tmp; ok &= jsval_to_std_string(cx, args.get(1), &arg1_tmp); arg1 = arg1_tmp.c_str();
|
||||
|
||||
GLProgram* ret = new (std::nothrow) cocos2d::GLProgram;
|
||||
ok = ret->initWithFilenames(arg0, arg1);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::GLProgram>(ret);
|
||||
// link the native object with the javascript object
|
||||
JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, ret, typeClass, "cocos2d::GLProgram"));
|
||||
args.rval().set(OBJECT_TO_JSVAL(jsobj));
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_ReportError(cx, "Error creating GLProgram");
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: This function doesn't have test. I was impossible to test it
|
||||
bool js_cocos2dx_CCGLProgram_createWithString(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
bool ok = true;
|
||||
if(argc != 2) {
|
||||
JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 2);
|
||||
return false;
|
||||
}
|
||||
|
||||
const char *arg0, *arg1;
|
||||
std::string arg0_tmp; ok &= jsval_to_std_string(cx, args.get(0), &arg0_tmp); arg0 = arg0_tmp.c_str();
|
||||
std::string arg1_tmp; ok &= jsval_to_std_string(cx, args.get(1), &arg1_tmp); arg1 = arg1_tmp.c_str();
|
||||
|
||||
GLProgram* ret = new (std::nothrow) GLProgram;
|
||||
ok = ret->initWithByteArrays(arg0, arg1);
|
||||
|
||||
if (ok)
|
||||
{
|
||||
js_type_class_t *typeClass = js_get_type_from_native<cocos2d::GLProgram>(ret);
|
||||
// link the native object with the javascript object
|
||||
JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, ret, typeClass, "cocos2d::GLProgram"));
|
||||
args.rval().set(OBJECT_TO_JSVAL(jsobj));
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
bool js_cocos2dx_CCGLProgram_getProgram(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
|
@ -4447,42 +4263,6 @@ bool js_cocos2dx_GLProgramState_setUniformVec4(JSContext *cx, uint32_t argc, jsv
|
|||
return false;
|
||||
}
|
||||
|
||||
#define js_cocos2dx_CCCamera_getXYZ(funcName) \
|
||||
bool ok = true; \
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); \
|
||||
JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); \
|
||||
js_proxy_t *proxy = jsb_get_js_proxy(obj); \
|
||||
cocos2d::Camera* cobj = (cocos2d::Camera *)(proxy ? proxy->ptr : NULL); \
|
||||
JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); \
|
||||
if (argc == 0) { \
|
||||
float x; \
|
||||
float y; \
|
||||
float z; \
|
||||
cobj->funcName(&x, &y, &z); \
|
||||
JS::RootedObject tmp(cx, JS_NewObject(cx, NULL, NULL, NULL)); \
|
||||
\
|
||||
do \
|
||||
{ \
|
||||
if (NULL == tmp) break; \
|
||||
\
|
||||
ok = JS_DefineProperty(cx, tmp, "x", DOUBLE_TO_JSVAL(x), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) && \
|
||||
JS_DefineProperty(cx, tmp, "y", DOUBLE_TO_JSVAL(y), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT) && \
|
||||
JS_DefineProperty(cx, tmp, "z", DOUBLE_TO_JSVAL(z), NULL, NULL, JSPROP_ENUMERATE | JSPROP_PERMANENT); \
|
||||
\
|
||||
if (ok) { \
|
||||
args.rval().set(OBJECT_TO_JSVAL(tmp)); \
|
||||
return true; \
|
||||
} \
|
||||
} while (false); \
|
||||
\
|
||||
args.rval().setUndefined(); \
|
||||
return true; \
|
||||
} \
|
||||
\
|
||||
JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0); \
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
bool js_cocos2dx_SpriteBatchNode_getDescendants(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
|
@ -5169,7 +4949,6 @@ void js_register_cocos2dx_EventKeyboard(JSContext *cx, JS::HandleObject global)
|
|||
jsb_cocos2d_EventKeyboard_class->enumerate = JS_EnumerateStub;
|
||||
jsb_cocos2d_EventKeyboard_class->resolve = JS_ResolveStub;
|
||||
jsb_cocos2d_EventKeyboard_class->convert = JS_ConvertStub;
|
||||
jsb_cocos2d_EventKeyboard_class->finalize = jsb_ref_finalize;
|
||||
jsb_cocos2d_EventKeyboard_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
|
||||
|
||||
static JSPropertySpec properties[] = {
|
||||
|
@ -5813,6 +5592,91 @@ bool js_cocos2dx_ComponentJS_getScriptObject(JSContext *cx, uint32_t argc, jsval
|
|||
return false;
|
||||
}
|
||||
|
||||
JSClass *jsb_FinalizeHook_class;
|
||||
JSObject *jsb_FinalizeHook_prototype;
|
||||
|
||||
static bool jsb_FinalizeHook_constructor(JSContext *cx, uint32_t argc, jsval *vp)
|
||||
{
|
||||
JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
|
||||
// Create new object
|
||||
JS::RootedObject proto(cx, jsb_FinalizeHook_prototype);
|
||||
JS::RootedObject obj(cx, JS_NewObject(cx, jsb_FinalizeHook_class, proto, JS::NullPtr()));
|
||||
// Register arguments[0] as owner
|
||||
if (!args.get(0).isNullOrUndefined())
|
||||
{
|
||||
jsb_register_finalize_hook(obj.get(), args.get(0).toObjectOrNull());
|
||||
}
|
||||
args.rval().set(OBJECT_TO_JSVAL(obj));
|
||||
return true;
|
||||
}
|
||||
void jsb_FinalizeHook_finalize(JSFreeOp *fop, JSObject *obj)
|
||||
{
|
||||
JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
|
||||
JS::RootedObject jsobj(cx, obj);
|
||||
JSObject *ownerPtr = jsb_get_and_remove_hook_owner(obj);
|
||||
if (ownerPtr)
|
||||
{
|
||||
JS::RootedObject owner(cx, ownerPtr);
|
||||
CCLOGINFO("jsbindings: finalizing JS object via Finalizehook %p", owner.get());
|
||||
js_proxy_t* nproxy = nullptr;
|
||||
js_proxy_t* jsproxy = nullptr;
|
||||
jsproxy = jsb_get_js_proxy(owner);
|
||||
if (jsproxy)
|
||||
{
|
||||
cocos2d::Ref *refObj = static_cast<cocos2d::Ref *>(jsproxy->ptr);
|
||||
nproxy = jsb_get_native_proxy(jsproxy->ptr);
|
||||
jsb_remove_proxy(nproxy, jsproxy);
|
||||
|
||||
if (refObj)
|
||||
{
|
||||
int count = refObj->getReferenceCount();
|
||||
if (count == 1)
|
||||
{
|
||||
refObj->autorelease();
|
||||
}
|
||||
else
|
||||
{
|
||||
CC_SAFE_RELEASE(refObj);
|
||||
}
|
||||
#if COCOS2D_DEBUG
|
||||
ScriptingCore::retainCount--;
|
||||
CCLOG("------RELEASED------ %d Native %p ref count: %d JSObj %p", ScriptingCore::retainCount, refObj, count-1, ownerPtr);
|
||||
#endif // COCOS2D_DEBUG
|
||||
}
|
||||
#if COCOS2D_DEBUG
|
||||
else {
|
||||
CCLOG("A non ref object have registered finalize hook: %p", nproxy->ptr);
|
||||
}
|
||||
#endif // COCOS2D_DEBUG
|
||||
}
|
||||
#if COCOS2D_DEBUG
|
||||
else {
|
||||
CCLOG("jsbindings: Failed to remove proxy for js object: %p, it may cause memory leak and future crash", ownerPtr);
|
||||
}
|
||||
#endif // COCOS2D_DEBUG
|
||||
}
|
||||
}
|
||||
|
||||
void jsb_register_FinalizeHook(JSContext *cx, JS::HandleObject global) {
|
||||
jsb_FinalizeHook_class = (JSClass *)calloc(1, sizeof(JSClass));
|
||||
jsb_FinalizeHook_class->name = "FinalizeHook";
|
||||
jsb_FinalizeHook_class->addProperty = JS_PropertyStub;
|
||||
jsb_FinalizeHook_class->delProperty = JS_DeletePropertyStub;
|
||||
jsb_FinalizeHook_class->getProperty = JS_PropertyStub;
|
||||
jsb_FinalizeHook_class->setProperty = JS_StrictPropertyStub;
|
||||
jsb_FinalizeHook_class->enumerate = JS_EnumerateStub;
|
||||
jsb_FinalizeHook_class->resolve = JS_ResolveStub;
|
||||
jsb_FinalizeHook_class->convert = JS_ConvertStub;
|
||||
jsb_FinalizeHook_class->finalize = jsb_FinalizeHook_finalize;
|
||||
jsb_FinalizeHook_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
|
||||
|
||||
jsb_FinalizeHook_prototype = JS_InitClass(cx, global,
|
||||
JS::NullPtr(), // parent proto
|
||||
jsb_FinalizeHook_class,
|
||||
jsb_FinalizeHook_constructor, 0, // constructor
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject global)
|
||||
{
|
||||
JS::RootedObject ccObj(cx);
|
||||
|
@ -5822,6 +5686,9 @@ void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject global)
|
|||
get_or_create_js_obj(cx, global, "cc", &ccObj);
|
||||
get_or_create_js_obj(cx, global, "jsb", &jsbObj);
|
||||
|
||||
// Memory management related
|
||||
jsb_register_FinalizeHook(cx, jsbObj);
|
||||
|
||||
js_register_cocos2dx_PolygonInfo(cx, jsbObj);
|
||||
js_register_cocos2dx_AutoPolygon(cx, jsbObj);
|
||||
|
||||
|
@ -5987,9 +5854,6 @@ void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject global)
|
|||
tmpObj.set(jsb_cocos2d_CatmullRomTo_prototype);
|
||||
JS_DefineFunction(cx, tmpObj, "initWithDuration", JSB_CatmullRomBy_initWithDuration, 2, JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
|
||||
JS_GetProperty(cx, ccObj, "Sprite", &tmpVal);
|
||||
tmpObj = tmpVal.toObjectOrNull();
|
||||
JS_DefineFunction(cx, tmpObj, "create", js_cocos2dx_Sprite_create, 0, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
tmpObj.set(jsb_cocos2d_Sprite_prototype);
|
||||
JS_DefineFunction(cx, tmpObj, "initWithPolygon", js_cocos2dx_Sprite_initWithPolygon, 1, JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
JS_DefineFunction(cx, tmpObj, "setPolygonInfo", js_cocos2dx_Sprite_setPolygonInfo, 1, JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
|
@ -6032,14 +5896,8 @@ void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject global)
|
|||
JS_GetProperty(cx, ccObj, "Spawn", &tmpVal);
|
||||
tmpObj = tmpVal.toObjectOrNull();
|
||||
JS_DefineFunction(cx, tmpObj, "create", js_cocos2dx_CCSpawn_create, 0, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
//JS_GetProperty(cx, ccObj, "Animation", &tmpVal);
|
||||
//tmpObj = tmpVal.toObjectOrNull();
|
||||
//JS_DefineFunction(cx, tmpObj, "create", js_cocos2dx_CCAnimation_create, 0, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
tmpObj.set(jsb_cocos2d_Scene_prototype);
|
||||
JS_DefineFunction(cx, tmpObj, "init", js_cocos2dx_CCScene_init, 0, JSPROP_PERMANENT | JSPROP_ENUMERATE);
|
||||
JS_GetProperty(cx, ccObj, "LayerMultiplex", &tmpVal);
|
||||
tmpObj = tmpVal.toObjectOrNull();
|
||||
JS_DefineFunction(cx, tmpObj, "create", js_cocos2dx_CCLayerMultiplex_create, 0, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
|
||||
JS_GetProperty(cx, ccObj, "CallFunc", &tmpVal);
|
||||
tmpObj = tmpVal.toObjectOrNull();
|
||||
|
@ -6047,11 +5905,6 @@ void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject global)
|
|||
tmpObj.set(jsb_cocos2d_CallFuncN_prototype);
|
||||
JS_DefineFunction(cx, tmpObj, "initWithFunction", js_cocos2dx_CallFunc_initWithFunction, 1, JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
|
||||
JS_GetProperty(cx, ccObj, "GLProgram", &tmpVal);
|
||||
tmpObj = tmpVal.toObjectOrNull();
|
||||
JS_DefineFunction(cx, tmpObj, "create", js_cocos2dx_CCGLProgram_create, 1, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
JS_DefineFunction(cx, tmpObj, "createWithString", js_cocos2dx_CCGLProgram_createWithString, 1, JSPROP_READONLY | JSPROP_PERMANENT);
|
||||
|
||||
tmpObj.set(jsb_cocos2d_Camera_prototype);
|
||||
JS_DefineFunction(cx, tmpObj, "unproject", js_cocos2dx_Camera_unproject, 1, JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
JS_DefineFunction(cx, tmpObj, "isVisibleInFrustum", js_cocos2dx_Camera_isVisibleInFrustum, 1, JSPROP_ENUMERATE | JSPROP_PERMANENT);
|
||||
|
|
|
@ -53,9 +53,11 @@ typedef struct jsCallFuncTarget_proxy {
|
|||
|
||||
extern schedFunc_proxy_t *_schedFunc_target_ht;
|
||||
extern schedTarget_proxy_t *_schedObj_target_ht;
|
||||
|
||||
extern callfuncTarget_proxy_t *_callfuncTarget_native_ht;
|
||||
|
||||
extern JSClass *jsb_FinalizeHook_class;
|
||||
extern JSObject *jsb_FinalizeHook_prototype;
|
||||
|
||||
/**
|
||||
* You don't need to manage the returned pointer. They live for the whole life of
|
||||
* the app.
|
||||
|
@ -81,67 +83,22 @@ inline js_type_class_t *js_get_type_from_native(T* native_obj) {
|
|||
return found ? typeProxyIter->second : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* The returned pointer should be deleted using jsb_remove_proxy. Most of the
|
||||
* time you do that in the C++ destructor.
|
||||
*/
|
||||
template<class T>
|
||||
inline js_proxy_t *js_get_or_create_proxy(JSContext *cx, T *native_obj) {
|
||||
js_proxy_t *proxy = jsb_get_native_proxy(native_obj);
|
||||
if (!proxy) {
|
||||
js_type_class_t *typeProxy = js_get_type_from_native<T>(native_obj);
|
||||
// Return NULL if can't find its type rather than making an assert.
|
||||
// assert(typeProxy);
|
||||
if (!typeProxy) {
|
||||
CCLOGINFO("Could not find the type of native object.");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
|
||||
|
||||
JS::RootedObject proto(cx, typeProxy->proto.ref().get());
|
||||
JS::RootedObject parent(cx, typeProxy->parentProto.ref().get());
|
||||
JS::RootedObject js_obj(cx, JS_NewObject(cx, typeProxy->jsclass, proto, parent));
|
||||
proxy = jsb_new_proxy(native_obj, js_obj);
|
||||
#ifdef DEBUG
|
||||
JS::AddNamedObjectRoot(cx, &proxy->obj, typeid(*native_obj).name());
|
||||
#else
|
||||
JS::AddObjectRoot(cx, &proxy->obj);
|
||||
#endif
|
||||
return proxy;
|
||||
} else {
|
||||
return proxy;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a JSObject based on native_obj.
|
||||
If native_obj is subclass of Ref, it will use the jsb_ref functions.
|
||||
Otherwise it will Root the newly created JSObject
|
||||
* If native_obj is subclass of Ref, it will use the jsb_ref functions.
|
||||
* Otherwise it will Root the newly created JSObject
|
||||
*/
|
||||
template<class T>
|
||||
JSObject* js_get_or_create_jsobject(JSContext *cx, typename std::enable_if<!std::is_base_of<cocos2d::Ref,T>::value,T>::type *native_obj)
|
||||
{
|
||||
// CCLOG("js_get_or_create_jsobject NO REF: %s", typeid(native_obj).name());
|
||||
js_proxy_t *proxy = jsb_get_native_proxy(native_obj);
|
||||
if (!proxy)
|
||||
{
|
||||
js_type_class_t* typeClass = js_get_type_from_native<T>(native_obj);
|
||||
JS::RootedObject proto(cx, typeClass->proto.ref().get());
|
||||
JS::RootedObject parent(cx, typeClass->parentProto.ref().get());
|
||||
JS::RootedObject js_obj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parent));
|
||||
proxy = jsb_new_proxy(native_obj, js_obj);
|
||||
|
||||
JS::AddNamedObjectRoot(cx, &proxy->obj, typeid(*native_obj).name());
|
||||
}
|
||||
return proxy->obj;
|
||||
return jsb_get_or_create_weak_jsobject(cx, native_obj, typeClass, typeid(*native_obj).name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets or creates a JSObject based on native_obj.
|
||||
If native_obj is subclass of Ref, it will use the jsb_ref functions.
|
||||
Otherwise it will Root the newly created JSObject
|
||||
* If native_obj is subclass of Ref, it will use the jsb_ref functions.
|
||||
* Otherwise it will Root the newly created JSObject
|
||||
*/
|
||||
template<class T>
|
||||
JSObject* js_get_or_create_jsobject(JSContext *cx, typename std::enable_if<std::is_base_of<cocos2d::Ref,T>::value,T>::type *native_obj)
|
||||
|
@ -150,6 +107,15 @@ JSObject* js_get_or_create_jsobject(JSContext *cx, typename std::enable_if<std::
|
|||
return jsb_ref_get_or_create_jsobject(cx, native_obj, typeClass, typeid(*native_obj).name());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a FinalizeHook object to the target object.
|
||||
* When the target object get garbage collected, its FinalizeHook's finalize function will be invoked.
|
||||
* In the finalize function, it mainly remove native/js proxys, release/delete the native object.
|
||||
* IMPORTANT: For Ref objects, please remember to retain the native object to correctly manage its reference count.
|
||||
*/
|
||||
void js_add_FinalizeHook(JSContext *cx, JS::HandleObject target);
|
||||
|
||||
|
||||
JS::Value anonEvaluate(JSContext *cx, JS::HandleObject thisObj, const char* string);
|
||||
void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject obj);
|
||||
|
||||
|
|
|
@ -236,17 +236,20 @@ var ClassManager = {
|
|||
//
|
||||
cc.Class = function(){};
|
||||
cc.Class.extend = function (prop) {
|
||||
var _super = this.prototype;
|
||||
var _super = this.prototype,
|
||||
prototype, Class, classId,
|
||||
className = prop._className || "",
|
||||
name, desc;
|
||||
|
||||
// Instantiate a base class (but only create the instance,
|
||||
// don't run the init constructor)
|
||||
initializing = true;
|
||||
var prototype = Object.create(_super);
|
||||
prototype = Object.create(_super);
|
||||
initializing = false;
|
||||
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
|
||||
|
||||
// Copy the properties over onto the new prototype
|
||||
for (var name in prop) {
|
||||
for (name in prop) {
|
||||
// Check if we're overwriting an existing function
|
||||
prototype[name] = typeof prop[name] == "function" &&
|
||||
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
|
||||
|
@ -269,35 +272,75 @@ cc.Class.extend = function (prop) {
|
|||
prop[name];
|
||||
}
|
||||
|
||||
// The dummy class constructor
|
||||
function Class() {
|
||||
Class = function () {
|
||||
if (!initializing) {
|
||||
this.__instanceId = ClassManager.getNewInstanceId();
|
||||
if (!this.ctor) {
|
||||
if (this.__nativeObj)
|
||||
cc.log("No ctor function found! Please check whether `classes_need_extend` section in `ini` file like which in `tools/tojs/cocos2dx.ini`");
|
||||
}
|
||||
else {
|
||||
this.ctor.apply(this, arguments);
|
||||
}
|
||||
}
|
||||
this.ctor && this.ctor.apply(this, arguments);
|
||||
}
|
||||
};
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.prototype.constructor = Class;
|
||||
// And make this class extendable
|
||||
Class.extend = cc.Class.extend;
|
||||
|
||||
var classId = ClassManager.getNewID();
|
||||
classId = ClassManager.getNewID();
|
||||
ClassManager[classId] = _super;
|
||||
var desc = { writable: true, enumerable: false, configurable: true };
|
||||
desc = { writable: true, enumerable: false, configurable: true };
|
||||
Class.id = classId;
|
||||
desc.value = classId;
|
||||
Object.defineProperty(prototype, '__pid', desc);
|
||||
|
||||
// Populate our constructed prototype object
|
||||
Class.prototype = prototype;
|
||||
|
||||
// Enforce the constructor to be what we expect
|
||||
Class.prototype.constructor = Class;
|
||||
|
||||
// And make this class extendable
|
||||
Class.extend = arguments.callee;
|
||||
|
||||
return Class;
|
||||
};
|
||||
|
||||
var __registeCount = 0;
|
||||
|
||||
jsb.registerNativeRef = function (owner, target) {
|
||||
if (typeof owner === "object" && typeof target === "object") {
|
||||
var refs = owner.__nativeRefs;
|
||||
if (!refs) {
|
||||
refs = owner.__nativeRefs = [];
|
||||
}
|
||||
var index = refs.indexOf(target);
|
||||
if (index === -1) {
|
||||
__registeCount++;
|
||||
// cc.log("##########registered " + target + " : " + __registeCount);
|
||||
owner.__nativeRefs.push(target);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jsb.unregisterNativeRef = function (owner, target) {
|
||||
if (typeof owner === "object" && typeof target === "object") {
|
||||
var refs = owner.__nativeRefs;
|
||||
if (!refs) {
|
||||
return;
|
||||
}
|
||||
var index = refs.indexOf(target);
|
||||
if (index !== -1) {
|
||||
__registeCount--;
|
||||
// cc.log("##------##unregistered " + target + " : " + __registeCount);
|
||||
owner.__nativeRefs.splice(index, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
jsb.unregisterAllNativeRefs = function (owner) {
|
||||
if (!owner) return;
|
||||
owner.__nativeRefs.length = 0;
|
||||
};
|
||||
|
||||
jsb.unregisterChildRefsForNode = function (node, recursive) {
|
||||
if (!(node instanceof cc.Node)) return;
|
||||
recursive = !!recursive;
|
||||
var children = node.getChildren(), i, l, child;
|
||||
for (i = 0, l = children.length; i < l; ++i) {
|
||||
child = children[i];
|
||||
jsb.unregisterNativeRef(node, child);
|
||||
if (recursive) {
|
||||
jsb.unregisterChildRefsForNode(child, recursive);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue