From 530321fe70674b74eb496a1e953502f36eaee143 Mon Sep 17 00:00:00 2001 From: pandamicro Date: Thu, 22 Oct 2015 17:00:57 +0800 Subject: [PATCH] #14124 Improved JSCallbackWrapper with generational GC and fix the issue --- .../js-bindings/manual/cocos2d_specifics.cpp | 290 +++++++----------- .../js-bindings/manual/cocos2d_specifics.hpp | 22 +- .../cocosbuilder/cocosbuilder_specifics.hpp | 11 +- .../cocostudio/jsb_cocos2dx_studio_manual.cpp | 75 +---- .../spine/jsb_cocos2dx_spine_manual.cpp | 9 +- .../manual/ui/jsb_cocos2dx_ui_manual.cpp | 48 +-- 6 files changed, 149 insertions(+), 306 deletions(-) diff --git a/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp b/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp index ee2695816c..374b71ec99 100644 --- a/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp +++ b/cocos/scripting/js-bindings/manual/cocos2d_specifics.cpp @@ -878,49 +878,48 @@ jsval anonEvaluate(JSContext *cx, JS::HandleObject thisObj, const char* string) } JSCallbackWrapper::JSCallbackWrapper() -: _jsCallback(JSVAL_VOID), _jsThisObj(JSVAL_VOID), _extraData(JSVAL_VOID) { - + JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); + _jsCallback.construct(cx, JS::NullHandleValue); + _jsThisObj.construct(cx, JS::NullHandleValue); + _extraData.construct(cx, JS::NullHandleValue); } JSCallbackWrapper::~JSCallbackWrapper() { - JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RemoveValueRoot(cx, &_jsCallback); - JS::RemoveValueRoot(cx, &_jsThisObj); + _jsCallback.destroyIfConstructed(); + _jsThisObj.destroyIfConstructed(); + _extraData.destroyIfConstructed(); } -void JSCallbackWrapper::setJSCallbackFunc(jsval func) { - _jsCallback = func; - JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); - // Root the callback function. - JS::AddNamedValueRoot(cx, &_jsCallback, "JSCallbackWrapper_callback_func"); +void JSCallbackWrapper::setJSCallbackFunc(JS::HandleValue func) { + if (!func.isNullOrUndefined()) + _jsCallback.ref() = func; } -void JSCallbackWrapper::setJSCallbackThis(jsval thisObj) { - _jsThisObj = thisObj; - JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); - // Root the this object. - JS::AddNamedValueRoot(cx, &_jsThisObj, "JSCallbackWrapper_callback_this"); +void JSCallbackWrapper::setJSCallbackThis(JS::HandleValue thisObj) { + if (!thisObj.isNullOrUndefined()) + _jsThisObj.ref() = thisObj; } -void JSCallbackWrapper::setJSExtraData(jsval data) { - _extraData = data; +void JSCallbackWrapper::setJSExtraData(JS::HandleValue data) { + if (!data.isNullOrUndefined()) + _extraData.ref() = data; } -const jsval& JSCallbackWrapper::getJSCallbackFunc() const +const jsval JSCallbackWrapper::getJSCallbackFunc() const { - return _jsCallback.get(); + return _jsCallback.ref().get(); } -const jsval& JSCallbackWrapper::getJSCallbackThis() const +const jsval JSCallbackWrapper::getJSCallbackThis() const { - return _jsThisObj.get(); + return _jsThisObj.ref().get(); } -const jsval& JSCallbackWrapper::getJSExtraData() const +const jsval JSCallbackWrapper::getJSExtraData() const { - return _extraData.get(); + return _extraData.ref().get(); } // cc.CallFunc.create( func, this, [data]) @@ -932,82 +931,52 @@ static bool js_callFunc(JSContext *cx, uint32_t argc, jsval *vp) std::shared_ptr tmpCobj(new JSCallbackWrapper()); - tmpCobj->setJSCallbackFunc(args.get(0)); + JS::RootedValue callback(cx, args.get(0)); + tmpCobj->setJSCallbackFunc(callback); if(argc >= 2) { - tmpCobj->setJSCallbackThis(args.get(1)); - } if(argc == 3) { - tmpCobj->setJSExtraData(args.get(2)); + JS::RootedValue thisObj(cx, args.get(1)); + tmpCobj->setJSCallbackThis(thisObj); + } + if(argc >= 3) { + JS::RootedValue data(cx, args.get(2)); + tmpCobj->setJSExtraData(data); } CallFuncN *ret = CallFuncN::create([=](Node* sender){ -// const jsval& jsvalThis = tmpCobj->getJSCallbackThis(); -// const jsval& jsvalCallback = tmpCobj->getJSCallbackFunc(); -// const jsval& jsvalExtraData = tmpCobj->getJSExtraData(); + JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET + JS::RootedValue jsvalThis(cx, tmpCobj->getJSCallbackThis()); + JS::RootedObject thisObj(cx, jsvalThis.toObjectOrNull()); JS::RootedValue jsvalCallback(cx, tmpCobj->getJSCallbackFunc()); JS::RootedValue jsvalExtraData(cx, tmpCobj->getJSExtraData()); - - bool hasExtraData = !jsvalExtraData.isUndefined(); - JS::RootedObject thisObj(cx, jsvalThis.toObjectOrNull()); - - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - - if(sender) + + JS::RootedValue senderVal(cx); + if (sender) { js_proxy_t *proxy = js_get_or_create_proxy(cx, sender); - - JS::RootedValue retval(cx); - if(jsvalCallback != JSVAL_VOID) - { - if (hasExtraData) - { - jsval valArr[2]; - valArr[0] = OBJECT_TO_JSVAL(proxy->obj); - valArr[1] = jsvalExtraData; - - //TODO: really need root? -// JS_AddValueRoot(cx, valArr); - JS::HandleValueArray callArgs = JS::HandleValueArray::fromMarkedLocation(2, valArr); - JS_CallFunctionValue(cx, thisObj, jsvalCallback, callArgs, &retval); -// JS_RemoveValueRoot(cx, valArr); - } - else - { - jsval senderVal = OBJECT_TO_JSVAL(proxy->obj); - JS::HandleValueArray callArgs = JS::HandleValueArray::fromMarkedLocation(1, &senderVal); -// JS_AddValueRoot(cx, &senderVal); - - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - - JS_CallFunctionValue(cx, thisObj, jsvalCallback, callArgs, &retval); -// JS_RemoveValueRoot(cx, &senderVal); - } - } + senderVal.set(OBJECT_TO_JSVAL(proxy->obj)); } else { - JS::RootedValue callRet(cx); - JS_CallFunctionValue(cx, thisObj, jsvalCallback, JS::HandleValueArray::empty(), &callRet); + senderVal.set(JS::NullValue()); } - // I think the JSCallFuncWrapper isn't needed. - // Since an action will be run by a cc.Node, it will be released at the Node::cleanup. - // By James Chen - // JSCallFuncWrapper::setTargetForNativeNode(node, (JSCallFuncWrapper *)this); + if (!jsvalCallback.isNullOrUndefined()) + { + JS::RootedValue retval(cx); + + jsval valArr[2]; + valArr[0] = senderVal; + valArr[1] = jsvalExtraData; + + JS::HandleValueArray callArgs = JS::HandleValueArray::fromMarkedLocation(2, valArr); + JS_CallFunctionValue(cx, thisObj, jsvalCallback, callArgs, &retval); + } }); js_proxy_t *proxy = js_get_or_create_proxy(cx, ret); args.rval().set(OBJECT_TO_JSVAL(proxy->obj)); - JS_SetReservedSlot(proxy->obj, 0, args.get(0)); - if(argc > 1) { - JS_SetReservedSlot(proxy->obj, 1, args.get(1)); - } -// if(argc == 3) { -// JS_SetReservedSlot(proxy->obj, 2, args.get(2)); -// } - - // test->execute(); return true; } JS_ReportError(cx, "Invalid number of arguments"); @@ -1025,90 +994,69 @@ bool js_cocos2dx_CallFunc_initWithFunction(JSContext *cx, uint32_t argc, jsval * JSB_PRECONDITION2(action, cx, false, "Invalid Native Object"); JS::CallArgs args = JS::CallArgsFromVp(argc, vp); - + std::shared_ptr tmpCobj(new JSCallbackWrapper()); - - tmpCobj->setJSCallbackFunc(args.get(0)); + + JS::RootedValue callback(cx, args.get(0)); + tmpCobj->setJSCallbackFunc(callback); if(argc >= 2) { - tmpCobj->setJSCallbackThis(args.get(1)); - } if(argc == 3) { - tmpCobj->setJSExtraData(args.get(2)); + JS::RootedValue thisObj(cx, args.get(1)); + tmpCobj->setJSCallbackThis(thisObj); + } + if(argc >= 3) { + JS::RootedValue data(cx, args.get(2)); + tmpCobj->setJSExtraData(data); } action->initWithFunction([=](Node* sender){ -// const jsval& jsvalThis = tmpCobj->getJSCallbackThis(); -// const jsval& jsvalCallback = tmpCobj->getJSCallbackFunc(); -// const jsval& jsvalExtraData = tmpCobj->getJSExtraData(); + JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET + JS::RootedValue jsvalThis(cx, tmpCobj->getJSCallbackThis()); + JS::RootedObject thisObj(cx, jsvalThis.toObjectOrNull()); JS::RootedValue jsvalCallback(cx, tmpCobj->getJSCallbackFunc()); JS::RootedValue jsvalExtraData(cx, tmpCobj->getJSExtraData()); - bool hasExtraData = !jsvalExtraData.isUndefined(); - JS::RootedObject thisObj(cx, jsvalThis.toObjectOrNull()); - - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - - if(sender) + JS::RootedValue senderVal(cx); + if (sender) { js_proxy_t *senderProxy = js_get_or_create_proxy(cx, sender); - - JS::RootedValue retval(cx); - if(jsvalCallback != JSVAL_VOID) - { - if (hasExtraData) - { - jsval valArr[2]; - valArr[0] = OBJECT_TO_JSVAL(senderProxy->obj); - valArr[1] = jsvalExtraData; - -// JS_AddValueRoot(cx, valArr); -// JS_CallFunctionValue(cx, thisObj, jsvalCallback, 2, valArr, &retval); -// JS_RemoveValueRoot(cx, valArr); - - JS::HandleValueArray callArgs = JS::HandleValueArray::fromMarkedLocation(2, valArr); - JS_CallFunctionValue(cx, thisObj, jsvalCallback, callArgs, &retval); - } - else - { - jsval senderVal = OBJECT_TO_JSVAL(senderProxy->obj); -// JS_AddValueRoot(cx, &senderVal); -// JS_CallFunctionValue(cx, thisObj, jsvalCallback, 1, &senderVal, &retval); -// JS_RemoveValueRoot(cx, &senderVal); - - JS::HandleValueArray callArgs = JS::HandleValueArray::fromMarkedLocation(1, &senderVal); - JS_CallFunctionValue(cx, thisObj, jsvalCallback, callArgs, &retval); - } - } + senderVal.set(OBJECT_TO_JSVAL(senderProxy->obj)); } else { - JS::RootedValue ret(cx); - JS_CallFunctionValue(cx, thisObj, jsvalCallback, JS::HandleValueArray::empty(), &ret); + senderVal.set(JS::NullValue()); } - - // I think the JSCallFuncWrapper isn't needed. - // Since an action will be run by a cc.Node, it will be released at the Node::cleanup. - // By James Chen - // JSCallFuncWrapper::setTargetForNativeNode(node, (JSCallFuncWrapper *)this); + if (!jsvalCallback.isNullOrUndefined()) + { + JS::RootedValue retval(cx); + + jsval valArr[2]; + valArr[0] = senderVal; + valArr[1] = jsvalExtraData; + + JS::HandleValueArray callArgs = JS::HandleValueArray::fromMarkedLocation(2, valArr); + JS_CallFunctionValue(cx, thisObj, jsvalCallback, callArgs, &retval); + } }); - - JS_SetReservedSlot(proxy->obj, 0, args.get(0)); - if(argc > 1) { - JS_SetReservedSlot(proxy->obj, 1, args.get(1)); - } return true; } JS_ReportError(cx, "Invalid number of arguments"); return false; } +JSScheduleWrapper::JSScheduleWrapper() +: _pTarget(NULL) +, _priority(0) +, _isUpdateSchedule(false) +{ + JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); + _pPureJSTarget.construct(cx); +} + JSScheduleWrapper::~JSScheduleWrapper() { - if (_pPureJSTarget.get()) { - JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RemoveObjectRoot(cx, &_pPureJSTarget); - } + _pPureJSTarget.destroyIfConstructed(); } void JSScheduleWrapper::setTargetForSchedule(JS::HandleValue sched, JSScheduleWrapper *target) { @@ -1398,44 +1346,26 @@ void JSScheduleWrapper::scheduleFunc(float dt) jsval data = DOUBLE_TO_JSVAL(dt); JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - - //XXX: really need root? -// bool ok = JS_AddValueRoot(cx, &data); -// if (!ok) { -// CCLOG("scheduleFunc: Root value fails."); -// return; -// } JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - if(!_jsCallback.isNullOrUndefined()) { + JS::RootedValue callback(cx, getJSCallbackFunc()); + if(!callback.isNullOrUndefined()) { JS::HandleValueArray args = JS::HandleValueArray::fromMarkedLocation(1, &data); JS::RootedValue retval(cx); - JS_CallFunctionValue(cx, JS::RootedObject(cx, _jsThisObj.toObjectOrNull()), JS::RootedValue(cx, _jsCallback.get()), args, &retval); + JS::RootedObject callbackTarget(cx, getJSCallbackThis().toObjectOrNull()); + JS_CallFunctionValue(cx, callbackTarget, callback, args, &retval); } - -// JS_RemoveValueRoot(cx, &data); } void JSScheduleWrapper::update(float dt) { jsval data = DOUBLE_TO_JSVAL(dt); - //XXX: really need root? -// JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - -// bool ok = JS_AddValueRoot(cx, &data); -// if (!ok) { -// CCLOG("scheduleFunc: Root value fails."); -// return; -// } - - ScriptingCore::getInstance()->executeFunctionWithOwner(_jsThisObj, "update", 1, &data); - -// JS_RemoveValueRoot(cx, &data); + ScriptingCore::getInstance()->executeFunctionWithOwner(getJSCallbackThis(), "update", 1, &data); } -Ref* JSScheduleWrapper::getTarget() +Ref* JSScheduleWrapper::getTarget() { return _pTarget; } @@ -1447,15 +1377,12 @@ void JSScheduleWrapper::setTarget(Ref* pTarget) void JSScheduleWrapper::setPureJSTarget(JS::HandleObject pPureJSTarget) { - CCASSERT(_pPureJSTarget == NULL, "The pure js target has been set"); - JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); - _pPureJSTarget = pPureJSTarget; - JS::AddNamedObjectRoot(cx, &_pPureJSTarget, "Pure JS target"); + _pPureJSTarget.ref() = pPureJSTarget; } JSObject* JSScheduleWrapper::getPureJSTarget() { - return _pPureJSTarget.get(); + return _pPureJSTarget.ref().get(); } void JSScheduleWrapper::setPriority(int priority) @@ -1550,8 +1477,8 @@ bool js_CCNode_scheduleOnce(JSContext *cx, uint32_t argc, jsval *vp) bool ok = true; JS::CallArgs args = JS::CallArgsFromVp(argc, vp); -// JSObject *obj = JS_THIS_OBJECT(cx, vp); - JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); + JS::RootedValue thisValue(cx, args.thisv()); + JS::RootedObject obj(cx, thisValue.toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); cocos2d::Node *node = (cocos2d::Node *)(proxy ? proxy->ptr : NULL); @@ -1586,7 +1513,7 @@ bool js_CCNode_scheduleOnce(JSContext *cx, uint32_t argc, jsval *vp) { tmpCobj = new JSScheduleWrapper(); tmpCobj->autorelease(); - tmpCobj->setJSCallbackThis(OBJECT_TO_JSVAL(obj)); + tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackFunc(args.get(0)); tmpCobj->setTarget(node); @@ -1630,8 +1557,8 @@ bool js_CCNode_schedule(JSContext *cx, uint32_t argc, jsval *vp) bool ok = true; JS::CallArgs args = JS::CallArgsFromVp(argc, vp); -// JSObject *obj = JS_THIS_OBJECT(cx, vp); - JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); + JS::RootedValue thisValue(cx, args.thisv()); + JS::RootedObject obj(cx, thisValue.toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); cocos2d::Node *node = (cocos2d::Node *)(proxy ? proxy->ptr : NULL); Scheduler *sched = node->getScheduler(); @@ -1679,7 +1606,7 @@ bool js_CCNode_schedule(JSContext *cx, uint32_t argc, jsval *vp) { tmpCobj = new JSScheduleWrapper(); tmpCobj->autorelease(); - tmpCobj->setJSCallbackThis(OBJECT_TO_JSVAL(obj)); + tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackFunc(args.get(0)); tmpCobj->setTarget(node); JSScheduleWrapper::setTargetForSchedule(args.get(0), tmpCobj); @@ -1710,8 +1637,8 @@ bool js_cocos2dx_CCNode_scheduleUpdateWithPriority(JSContext *cx, uint32_t argc, { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; -// JSObject *obj = JS_THIS_OBJECT(cx, vp); - JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); + JS::RootedValue thisValue(cx, args.thisv()); + JS::RootedObject obj(cx, thisValue.toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); cocos2d::Node* cobj = (cocos2d::Node *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); @@ -1753,7 +1680,7 @@ bool js_cocos2dx_CCNode_scheduleUpdateWithPriority(JSContext *cx, uint32_t argc, { tmpCobj = new JSScheduleWrapper(); tmpCobj->autorelease(); - tmpCobj->setJSCallbackThis(OBJECT_TO_JSVAL(obj)); + tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackFunc(jsUpdateFunc); tmpCobj->setTarget(cobj); tmpCobj->setUpdateSchedule(true); @@ -1775,7 +1702,6 @@ bool js_cocos2dx_CCNode_scheduleUpdateWithPriority(JSContext *cx, uint32_t argc, bool js_cocos2dx_CCNode_unscheduleUpdate(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); -// JSObject *obj = JS_THIS_OBJECT(cx, vp); JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); cocos2d::Node* cobj = (cocos2d::Node *)(proxy ? proxy->ptr : NULL); @@ -1785,8 +1711,6 @@ bool js_cocos2dx_CCNode_unscheduleUpdate(JSContext *cx, uint32_t argc, jsval *vp { cobj->unscheduleUpdate(); do { -// JSObject *tmpObj = obj; - __Array *arr = JSScheduleWrapper::getTargetForJSObject(obj); // If there aren't any targets, just return true. // Otherwise, the for loop will break immediately. @@ -1817,8 +1741,8 @@ bool js_cocos2dx_CCNode_scheduleUpdate(JSContext *cx, uint32_t argc, jsval *vp) { JS::CallArgs args = JS::CallArgsFromVp(argc, vp); bool ok = true; -// JSObject *obj = JS_THIS_OBJECT(cx, vp); - JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); + JS::RootedValue thisValue(cx, args.thisv()); + JS::RootedObject obj(cx, thisValue.toObjectOrNull()); js_proxy_t *proxy = jsb_get_js_proxy(obj); cocos2d::Node* cobj = (cocos2d::Node *)(proxy ? proxy->ptr : NULL); JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); @@ -1857,7 +1781,7 @@ bool js_cocos2dx_CCNode_scheduleUpdate(JSContext *cx, uint32_t argc, jsval *vp) { tmpCobj = new JSScheduleWrapper(); tmpCobj->autorelease(); - tmpCobj->setJSCallbackThis(OBJECT_TO_JSVAL(obj)); + tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackFunc(jsUpdateFunc); tmpCobj->setTarget(cobj); tmpCobj->setUpdateSchedule(true); diff --git a/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp b/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp index 5bad0a7d62..6d9a6a31c7 100644 --- a/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp +++ b/cocos/scripting/js-bindings/manual/cocos2d_specifics.hpp @@ -124,24 +124,24 @@ class JSCallbackWrapper: public cocos2d::Ref { public: JSCallbackWrapper(); virtual ~JSCallbackWrapper(); - void setJSCallbackFunc(jsval obj); - void setJSCallbackThis(jsval thisObj); - void setJSExtraData(jsval data); + void setJSCallbackFunc(JS::HandleValue callback); + void setJSCallbackThis(JS::HandleValue thisObj); + void setJSExtraData(JS::HandleValue data); - const jsval& getJSCallbackFunc() const; - const jsval& getJSCallbackThis() const; - const jsval& getJSExtraData() const; + const jsval getJSCallbackFunc() const; + const jsval getJSCallbackThis() const; + const jsval getJSExtraData() const; protected: - JS::Heap _jsCallback; - JS::Heap _jsThisObj; - JS::Heap _extraData; + mozilla::Maybe _jsCallback; + mozilla::Maybe _jsThisObj; + mozilla::Maybe _extraData; }; class JSScheduleWrapper: public JSCallbackWrapper { public: - JSScheduleWrapper() : _pTarget(NULL), _pPureJSTarget(NULL), _priority(0), _isUpdateSchedule(false) {} + JSScheduleWrapper(); virtual ~JSScheduleWrapper(); static void setTargetForSchedule(JS::HandleValue sched, JSScheduleWrapper *target); @@ -178,7 +178,7 @@ public: protected: Ref* _pTarget; - JS::Heap _pPureJSTarget; + mozilla::Maybe _pPureJSTarget; int _priority; bool _isUpdateSchedule; }; diff --git a/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp b/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp index 6e41e37186..d3fb9a0da0 100644 --- a/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp +++ b/cocos/scripting/js-bindings/manual/cocosbuilder/cocosbuilder_specifics.hpp @@ -32,18 +32,19 @@ public: JSCCBAnimationWrapper() {} virtual ~JSCCBAnimationWrapper() {} - void animationCompleteCallback() + void animationCompleteCallback() { - - if(!_jsCallback.isNullOrUndefined() && !_jsThisObj.isNullOrUndefined()) + JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); + JS::RootedValue callback(cx, getJSCallbackFunc()); + JS::RootedValue thisObj(cx, getJSCallbackThis()); + if(!callback.isNullOrUndefined() && !thisObj.isNullOrUndefined()) { - JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); JS::RootedValue retval(cx); JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS_CallFunctionValue(cx, JS::RootedObject(cx, _jsThisObj.toObjectOrNull()), JS::RootedValue(cx, _jsCallback), JS::HandleValueArray::empty(), &retval); + JS_CallFunctionValue(cx, JS::RootedObject(cx, thisObj.toObjectOrNull()), JS::RootedValue(cx, callback), JS::HandleValueArray::empty(), &retval); } } diff --git a/cocos/scripting/js-bindings/manual/cocostudio/jsb_cocos2dx_studio_manual.cpp b/cocos/scripting/js-bindings/manual/cocostudio/jsb_cocos2dx_studio_manual.cpp index 4975cbced3..766dbd988f 100644 --- a/cocos/scripting/js-bindings/manual/cocostudio/jsb_cocos2dx_studio_manual.cpp +++ b/cocos/scripting/js-bindings/manual/cocostudio/jsb_cocos2dx_studio_manual.cpp @@ -28,55 +28,19 @@ class JSArmatureWrapper: public JSCallbackWrapper { public: - JSArmatureWrapper(); - virtual ~JSArmatureWrapper(); - - virtual void setJSCallbackThis(jsval thisObj); - void movementCallbackFunc(cocostudio::Armature *armature, cocostudio::MovementEventType movementType, const std::string& movementID); void frameCallbackFunc(cocostudio::Bone *bone, const std::string& evt, int originFrameIndex, int currentFrameIndex); void addArmatureFileInfoAsyncCallbackFunc(float percent); - -private: - bool m_bNeedUnroot; }; -JSArmatureWrapper::JSArmatureWrapper() - : m_bNeedUnroot(false) -{ - -} - -JSArmatureWrapper::~JSArmatureWrapper() -{ - if (m_bNeedUnroot) - { - JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RemoveValueRoot(cx, &_jsThisObj); - } -} - -void JSArmatureWrapper::setJSCallbackThis(jsval obj) -{ - JSCallbackWrapper::setJSCallbackThis(obj); - - JSObject *thisObj = obj.toObjectOrNull(); - js_proxy *p = jsb_get_js_proxy(thisObj); - if (!p) - { - JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - m_bNeedUnroot = true; - m_bNeedUnroot &= JS::AddValueRoot(cx, &_jsThisObj); - } -} - void JSArmatureWrapper::movementCallbackFunc(cocostudio::Armature *armature, cocostudio::MovementEventType movementType, const std::string& movementID) { JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RootedObject thisObj(cx, _jsThisObj.toObjectOrNull()); + JS::RootedObject thisObj(cx, getJSCallbackThis().toObjectOrNull()); js_proxy_t *proxy = js_get_or_create_proxy(cx, armature); + JS::RootedValue callback(cx, getJSCallbackFunc()); JS::RootedValue retval(cx); - if (_jsCallback != JSVAL_VOID) + if (!callback.isNullOrUndefined()) { int movementEventType = (int)movementType; jsval movementVal = INT_TO_JSVAL(movementEventType); @@ -87,31 +51,26 @@ void JSArmatureWrapper::movementCallbackFunc(cocostudio::Armature *armature, coc valArr[0] = OBJECT_TO_JSVAL(proxy->obj); valArr[1] = movementVal; valArr[2] = idVal; - - //JS_AddValueRoot(cx, valArr); JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS_CallFunctionValue(cx, thisObj, JS::RootedValue(cx, _jsCallback), JS::HandleValueArray::fromMarkedLocation(3, valArr), &retval); - //JS_RemoveValueRoot(cx, valArr); + JS_CallFunctionValue(cx, thisObj, callback, JS::HandleValueArray::fromMarkedLocation(3, valArr), &retval); } } void JSArmatureWrapper::addArmatureFileInfoAsyncCallbackFunc(float percent) { JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RootedObject thisObj(cx, _jsThisObj.toObjectOrNull()); + JS::RootedObject thisObj(cx, getJSCallbackThis().toObjectOrNull()); + JS::RootedValue callback(cx, getJSCallbackFunc()); JS::RootedValue retval(cx); - if (_jsCallback != JSVAL_VOID) + if (!callback.isNullOrUndefined()) { jsval percentVal = DOUBLE_TO_JSVAL(percent); - - //JS_AddValueRoot(cx, &percentVal); JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS_CallFunctionValue(cx, thisObj, JS::RootedValue(cx, _jsCallback), JS::HandleValueArray::fromMarkedLocation(1, &percentVal), &retval); - //JS_RemoveValueRoot(cx, &percentVal); + JS_CallFunctionValue(cx, thisObj, callback, JS::HandleValueArray::fromMarkedLocation(1, &percentVal), &retval); } } @@ -121,10 +80,11 @@ void JSArmatureWrapper::frameCallbackFunc(cocostudio::Bone *bone, const std::str JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RootedObject thisObj(cx, _jsThisObj.toObjectOrNull()); + JS::RootedObject thisObj(cx, getJSCallbackThis().toObjectOrNull()); + JS::RootedValue callback(cx, getJSCallbackFunc()); js_proxy_t *proxy = js_get_or_create_proxy(cx, bone); JS::RootedValue retval(cx); - if (_jsCallback != JSVAL_VOID) + if (!callback.isNullOrUndefined()) { jsval nameVal = std_string_to_jsval(cx, evt); jsval originIndexVal = INT_TO_JSVAL(originFrameIndex); @@ -135,11 +95,8 @@ void JSArmatureWrapper::frameCallbackFunc(cocostudio::Bone *bone, const std::str valArr[1] = nameVal; valArr[2] = originIndexVal; valArr[3] = currentIndexVal; - - //JS_AddValueRoot(cx, valArr); - JS_CallFunctionValue(cx, thisObj, JS::RootedValue(cx, _jsCallback), JS::HandleValueArray::fromMarkedLocation(4, valArr), &retval); - //JS_RemoveValueRoot(cx, valArr); + JS_CallFunctionValue(cx, thisObj, callback, JS::HandleValueArray::fromMarkedLocation(4, valArr), &retval); } } @@ -173,7 +130,8 @@ static bool js_cocos2dx_ArmatureAnimation_setMovementEventCallFunc(JSContext *cx tmpObj->setJSCallbackFunc(args.get(0)); if (argc == 1) { - tmpObj->setJSCallbackThis(JSVAL_NULL); + JS::RootedValue nullVal(cx, JS::NullValue()); + tmpObj->setJSCallbackThis(nullVal); } else { @@ -219,7 +177,8 @@ static bool js_cocos2dx_ArmatureAnimation_setFrameEventCallFunc(JSContext *cx, u tmpObj->setJSCallbackFunc(args.get(0)); if (argc == 1) { - tmpObj->setJSCallbackThis(JSVAL_NULL); + JS::RootedValue nullVal(cx, JS::NullValue()); + tmpObj->setJSCallbackThis(nullVal); } else { @@ -417,7 +376,7 @@ static bool js_cocos2dx_studio_Frame_getEasingParams(JSContext *cx, uint32_t arg bool ok = true; for(size_t i = 0; i < ret.size(); ++i) { - ok &= JS_SetElement(cx, jsobj, i, ret[i]); + ok &= JS_SetElement(cx, jsobj, (int)i, ret[i]); } JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_studio_Frame_getEasingParams : Error processing arguments"); diff --git a/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp b/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp index 2053c45136..ec43c482e8 100644 --- a/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp +++ b/cocos/scripting/js-bindings/manual/spine/jsb_cocos2dx_spine_manual.cpp @@ -564,10 +564,11 @@ public: void animationCallbackFunc(spine::SkeletonAnimation* node, int trackIndex, spEventType type, spEvent* event, int loopCount) const { JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RootedObject thisObj(cx, _jsThisObj.toObjectOrNull()); + JS::RootedObject thisObj(cx, getJSCallbackThis().toObjectOrNull()); + JS::RootedValue callback(cx, getJSCallbackFunc()); js_proxy_t *proxy = js_get_or_create_proxy(cx, node); JS::RootedValue retval(cx); - if (_jsCallback != JSVAL_VOID) + if (!callback.isNullOrUndefined()) { jsval nodeVal = OBJECT_TO_JSVAL(proxy->obj); jsval trackIndexVal = INT_TO_JSVAL(trackIndex); @@ -585,10 +586,8 @@ public: valArr[3] = eventVal; valArr[4] = loopCountVal; - //JS_AddValueRoot(cx, valArr); JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - JS_CallFunctionValue(cx, thisObj, JS::RootedValue(cx, _jsCallback), JS::HandleValueArray::fromMarkedLocation(5, valArr), &retval); - //JS_RemoveValueRoot(cx, valArr); + JS_CallFunctionValue(cx, thisObj, callback, JS::HandleValueArray::fromMarkedLocation(5, valArr), &retval); } } }; diff --git a/cocos/scripting/js-bindings/manual/ui/jsb_cocos2dx_ui_manual.cpp b/cocos/scripting/js-bindings/manual/ui/jsb_cocos2dx_ui_manual.cpp index 07b338d760..82495331fb 100755 --- a/cocos/scripting/js-bindings/manual/ui/jsb_cocos2dx_ui_manual.cpp +++ b/cocos/scripting/js-bindings/manual/ui/jsb_cocos2dx_ui_manual.cpp @@ -31,53 +31,17 @@ using namespace cocos2d::ui; class JSStudioEventListenerWrapper: public JSCallbackWrapper { public: - JSStudioEventListenerWrapper(); - virtual ~JSStudioEventListenerWrapper(); - - virtual void setJSCallbackThis(jsval thisObj); - virtual void eventCallbackFunc(Ref*,int); - -private: - bool m_bNeedUnroot; }; -JSStudioEventListenerWrapper::JSStudioEventListenerWrapper() - : m_bNeedUnroot(false) -{ - -} - -JSStudioEventListenerWrapper::~JSStudioEventListenerWrapper() -{ - if (m_bNeedUnroot) - { - JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RemoveValueRoot(cx, &_jsThisObj); - } -} - -void JSStudioEventListenerWrapper::setJSCallbackThis(jsval jsThisObj) -{ - JSCallbackWrapper::setJSCallbackThis(jsThisObj); - - JSObject *thisObj = jsThisObj.toObjectOrNull(); - js_proxy *p = jsb_get_js_proxy(thisObj); - if (!p) - { - JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - m_bNeedUnroot = true; - m_bNeedUnroot &= JS::AddValueRoot(cx, &_jsThisObj); - } -} - void JSStudioEventListenerWrapper::eventCallbackFunc(Ref* sender,int eventType) { JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); - JS::RootedObject thisObj(cx, _jsThisObj.isNullOrUndefined() ? NULL : _jsThisObj.toObjectOrNull()); + JS::RootedObject thisObj(cx, getJSCallbackThis().toObjectOrNull()); + JS::RootedValue callback(cx, getJSCallbackFunc()); js_proxy_t *proxy = js_get_or_create_proxy(cx, sender); JS::RootedValue retval(cx); - if (!_jsCallback.isNullOrUndefined()) + if (!callback.isNullOrUndefined()) { jsval touchVal = INT_TO_JSVAL(eventType); @@ -85,12 +49,8 @@ void JSStudioEventListenerWrapper::eventCallbackFunc(Ref* sender,int eventType) valArr[0] = OBJECT_TO_JSVAL(proxy->obj); valArr[1] = touchVal; - //JS::AddValueRoot(cx, valArr); - JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET - - JS_CallFunctionValue(cx, thisObj, JS::RootedValue(cx, _jsCallback), JS::HandleValueArray::fromMarkedLocation(2, valArr), &retval); - //JS::RemoveValueRoot(cx, valArr); + JS_CallFunctionValue(cx, thisObj, callback, JS::HandleValueArray::fromMarkedLocation(2, valArr), &retval); } }