fix JSB Memory leaks and crashes (#18577)

* [game] Uses global compartment.

* fixed cocostudio bug.

* Fixes Memory leak for JSB.

* Memory leak in ActionsTest.js

* js_callfunc binding check whether jsThis is valid.

* Fixes potential crash in DownloadDelegator .

* CCLOG -> CCLOGINFO for garbage collect callback.

* jsb_c_proxy_s is a struct which contains a JS::Heap<> cpp object. Need to use `new`/`delete` to manage its memory.

* The functionality of JS controls C++ object's lifecycle isn't stable enough, please don't enable it now. Make an error if user enables it.

* Compilation error fixes.

* Removes unused JSAutoCompartment since we use JS_EnterCompartment/JS_LeaveCompartment now.
This commit is contained in:
James Chen 2018-01-10 14:39:45 +08:00 committed by minggo
parent 8f1459b8ef
commit b2ecbca549
17 changed files with 325 additions and 449 deletions

View File

@ -76,7 +76,8 @@ bool JSB_cpConstraint_getBodyA(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpConstraintGetBodyA((cpConstraint*)arg0 ); ret_val = cpConstraintGetBodyA((cpConstraint*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpBody_object), JSB_cpBody_class, "cpBody" )); JS::RootedObject rootedObj(cx, JSB_cpBody_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpBody_class, "cpBody" ));
return true; return true;
} }
@ -94,7 +95,8 @@ bool JSB_cpConstraint_getBodyB(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpConstraintGetBodyB((cpConstraint*)arg0 ); ret_val = cpConstraintGetBodyB((cpConstraint*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpBody_object), JSB_cpBody_class, "cpBody" )); JS::RootedObject rootedObj(cx, JSB_cpBody_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpBody_class, "cpBody" ));
return true; return true;
} }
@ -202,7 +204,8 @@ bool JSB_cpConstraint_getSpace(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpConstraintGetSpace((cpConstraint*)arg0 ); ret_val = cpConstraintGetSpace((cpConstraint*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpSpace_object), JSB_cpSpace_class, "cpSpace" )); JS::RootedObject rootedObj(cx, JSB_cpSpace_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpSpace_class, "cpSpace" ));
return true; return true;
} }
@ -526,7 +529,8 @@ void JSB_cpConstraint_createClass(JSContext *cx, JS::HandleObject globalObj, con
JS_FS_END JS_FS_END
}; };
JSB_cpConstraint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpBase_object), JSB_cpConstraint_class, JSB_cpConstraint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpBase_object);
JSB_cpConstraint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpConstraint_class, JSB_cpConstraint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -732,7 +736,8 @@ void JSB_cpGrooveJoint_createClass(JSContext *cx, JS::HandleObject globalObj, co
JS_FS_END JS_FS_END
}; };
JSB_cpGrooveJoint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpGrooveJoint_class, JSB_cpGrooveJoint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpGrooveJoint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpGrooveJoint_class, JSB_cpGrooveJoint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -850,7 +855,8 @@ void JSB_cpSimpleMotor_createClass(JSContext *cx, JS::HandleObject globalObj, co
JS_FS_END JS_FS_END
}; };
JSB_cpSimpleMotor_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpSimpleMotor_class, JSB_cpSimpleMotor_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpSimpleMotor_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpSimpleMotor_class, JSB_cpSimpleMotor_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -1011,7 +1017,8 @@ void JSB_cpPivotJoint_createClass(JSContext *cx, JS::HandleObject globalObj, con
JS_FS_END JS_FS_END
}; };
JSB_cpPivotJoint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpPivotJoint_class, JSB_cpPivotJoint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpPivotJoint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpPivotJoint_class, JSB_cpPivotJoint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -1216,7 +1223,8 @@ void JSB_cpPinJoint_createClass(JSContext *cx, JS::HandleObject globalObj, const
JS_FS_END JS_FS_END
}; };
JSB_cpPinJoint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpPinJoint_class, JSB_cpPinJoint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpPinJoint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpPinJoint_class, JSB_cpPinJoint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -1466,7 +1474,8 @@ void JSB_cpSlideJoint_createClass(JSContext *cx, JS::HandleObject globalObj, con
JS_FS_END JS_FS_END
}; };
JSB_cpSlideJoint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpSlideJoint_class, JSB_cpSlideJoint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpSlideJoint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpSlideJoint_class, JSB_cpSlideJoint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -1628,7 +1637,8 @@ void JSB_cpGearJoint_createClass(JSContext *cx, JS::HandleObject globalObj, cons
JS_FS_END JS_FS_END
}; };
JSB_cpGearJoint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpGearJoint_class, JSB_cpGearJoint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpGearJoint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpGearJoint_class, JSB_cpGearJoint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -1834,7 +1844,8 @@ void JSB_cpDampedRotarySpring_createClass(JSContext *cx, JS::HandleObject global
JS_FS_END JS_FS_END
}; };
JSB_cpDampedRotarySpring_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpDampedRotarySpring_class, JSB_cpDampedRotarySpring_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpDampedRotarySpring_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpDampedRotarySpring_class, JSB_cpDampedRotarySpring_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -2128,7 +2139,8 @@ void JSB_cpDampedSpring_createClass(JSContext *cx, JS::HandleObject globalObj, c
JS_FS_END JS_FS_END
}; };
JSB_cpDampedSpring_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpDampedSpring_class, JSB_cpDampedSpring_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpDampedSpring_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpDampedSpring_class, JSB_cpDampedSpring_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -2333,7 +2345,8 @@ void JSB_cpRatchetJoint_createClass(JSContext *cx, JS::HandleObject globalObj, c
JS_FS_END JS_FS_END
}; };
JSB_cpRatchetJoint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpRatchetJoint_class, JSB_cpRatchetJoint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpRatchetJoint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpRatchetJoint_class, JSB_cpRatchetJoint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -2495,7 +2508,8 @@ void JSB_cpRotaryLimitJoint_createClass(JSContext *cx, JS::HandleObject globalOb
JS_FS_END JS_FS_END
}; };
JSB_cpRotaryLimitJoint_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpConstraint_object), JSB_cpRotaryLimitJoint_class, JSB_cpRotaryLimitJoint_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpConstraint_object);
JSB_cpRotaryLimitJoint_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpRotaryLimitJoint_class, JSB_cpRotaryLimitJoint_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -3090,7 +3104,8 @@ void JSB_cpArbiter_createClass(JSContext *cx, JS::HandleObject globalObj, const
JS_FS_END JS_FS_END
}; };
JSB_cpArbiter_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpBase_object), JSB_cpArbiter_class, JSB_cpArbiter_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpBase_object);
JSB_cpArbiter_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpArbiter_class, JSB_cpArbiter_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -3380,7 +3395,8 @@ bool JSB_cpSpace_getStaticBody(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpSpaceGetStaticBody((cpSpace*)arg0 ); ret_val = cpSpaceGetStaticBody((cpSpace*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpBody_object), JSB_cpBody_class, "cpBody" )); JS::RootedObject rootedObj(cx, JSB_cpBody_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpBody_class, "cpBody" ));
return true; return true;
} }
@ -3398,7 +3414,8 @@ bool JSB_cpSpace_init(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpSpaceInit((cpSpace*)arg0 ); ret_val = cpSpaceInit((cpSpace*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpSpace_object), JSB_cpSpace_class, "cpSpace" )); JS::RootedObject rootedObj(cx, JSB_cpSpace_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpSpace_class, "cpSpace" ));
return true; return true;
} }
@ -3779,7 +3796,8 @@ void JSB_cpSpace_createClass(JSContext *cx, JS::HandleObject globalObj, const ch
JS_FS_END JS_FS_END
}; };
JSB_cpSpace_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpBase_object), JSB_cpSpace_class, JSB_cpSpace_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpBase_object);
JSB_cpSpace_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpSpace_class, JSB_cpSpace_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -4116,7 +4134,8 @@ bool JSB_cpBody_getSpace(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpBodyGetSpace((cpBody*)arg0 ); ret_val = cpBodyGetSpace((cpBody*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpSpace_object), JSB_cpSpace_class, "cpSpace" )); JS::RootedObject rootedObj(cx, JSB_cpSpace_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpSpace_class, "cpSpace" ));
return true; return true;
} }
@ -4243,7 +4262,8 @@ bool JSB_cpBody_init(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpBodyInit((cpBody*)arg0 , (cpFloat)arg1 , (cpFloat)arg2 ); ret_val = cpBodyInit((cpBody*)arg0 , (cpFloat)arg1 , (cpFloat)arg2 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpBody_object), JSB_cpBody_class, "cpBody" )); JS::RootedObject rootedObj(cx, JSB_cpBody_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpBody_class, "cpBody" ));
return true; return true;
} }
@ -4717,7 +4737,8 @@ void JSB_cpBody_createClass(JSContext *cx, JS::HandleObject globalObj, const cha
JS_FS_END JS_FS_END
}; };
JSB_cpBody_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpBase_object), JSB_cpBody_class, JSB_cpBody_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpBase_object);
JSB_cpBody_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpBody_class, JSB_cpBody_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -4862,7 +4883,8 @@ bool JSB_cpShape_getBody(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpShapeGetBody((cpShape*)arg0 ); ret_val = cpShapeGetBody((cpShape*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpBody_object), JSB_cpBody_class, "cpBody" )); JS::RootedObject rootedObj(cx, JSB_cpBody_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpBody_class, "cpBody" ));
return true; return true;
} }
@ -5042,7 +5064,8 @@ bool JSB_cpShape_getSpace(JSContext *cx, uint32_t argc, jsval *vp) {
ret_val = cpShapeGetSpace((cpShape*)arg0 ); ret_val = cpShapeGetSpace((cpShape*)arg0 );
args.rval().set(c_class_to_jsval( cx, ret_val, JS::RootedObject(cx,JSB_cpSpace_object), JSB_cpSpace_class, "cpSpace" )); JS::RootedObject rootedObj(cx, JSB_cpSpace_object);
args.rval().set(c_class_to_jsval( cx, ret_val, rootedObj, JSB_cpSpace_class, "cpSpace" ));
return true; return true;
} }
@ -5349,7 +5372,8 @@ void JSB_cpShape_createClass(JSContext *cx, JS::HandleObject globalObj, const ch
JS_FS_END JS_FS_END
}; };
JSB_cpShape_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpBase_object), JSB_cpShape_class, JSB_cpShape_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpBase_object);
JSB_cpShape_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpShape_class, JSB_cpShape_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -5462,7 +5486,8 @@ void JSB_cpCircleShape_createClass(JSContext *cx, JS::HandleObject globalObj, co
JS_FS_END JS_FS_END
}; };
JSB_cpCircleShape_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpShape_object), JSB_cpCircleShape_class, JSB_cpCircleShape_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpShape_object);
JSB_cpCircleShape_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpCircleShape_class, JSB_cpCircleShape_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -5639,7 +5664,8 @@ void JSB_cpSegmentShape_createClass(JSContext *cx, JS::HandleObject globalObj, c
JS_FS_END JS_FS_END
}; };
JSB_cpSegmentShape_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpShape_object), JSB_cpSegmentShape_class, JSB_cpSegmentShape_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpShape_object);
JSB_cpSegmentShape_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpSegmentShape_class, JSB_cpSegmentShape_constructor,0,properties,funcs,NULL,st_funcs);
} }
/* /*
@ -5753,7 +5779,8 @@ void JSB_cpPolyShape_createClass(JSContext *cx, JS::HandleObject globalObj, cons
JS_FS_END JS_FS_END
}; };
JSB_cpPolyShape_object = JS_InitClass(cx, globalObj, JS::RootedObject(cx,JSB_cpShape_object), JSB_cpPolyShape_class, JSB_cpPolyShape_constructor,0,properties,funcs,NULL,st_funcs); JS::RootedObject rootedObj(cx, JSB_cpShape_object);
JSB_cpPolyShape_object = JS_InitClass(cx, globalObj, rootedObj, JSB_cpPolyShape_class, JSB_cpPolyShape_constructor,0,properties,funcs,NULL,st_funcs);
} }

View File

@ -74,6 +74,10 @@
#define TRACE_DEBUGGER_SERVER(...) #define TRACE_DEBUGGER_SERVER(...)
#endif // #if COCOS2D_DEBUG #endif // #if COCOS2D_DEBUG
#if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
#error "The functionality of JS controls C++ object's lifecycle isn't stable enough, please don't enable it now."
#endif
#define BYTE_CODE_FILE_EXT ".jsc" #define BYTE_CODE_FILE_EXT ".jsc"
using namespace cocos2d; using namespace cocos2d;
@ -121,6 +125,22 @@ static void ReportException(JSContext *cx)
} }
} }
static void onGarbageCollect(JSRuntime* rt, JSGCStatus status, void* data)
{
/* We finalize any pending toggle refs before doing any garbage collection,
* so that we can collect the JS wrapper objects, and in order to minimize
* the chances of objects having a pending toggle up queued when they are
* garbage collected. */
if (status == JSGC_BEGIN)
{
CCLOGINFO("onGarbageCollect begin, native->js map: %d, js->native map: %d", (int)_native_js_global_map.size(), (int)_js_native_global_map.size());
}
else if (status == JSGC_END)
{
CCLOGINFO("onGarbageCollect end, native->js map: %d, js->native map: %d", (int)_native_js_global_map.size(), (int)_js_native_global_map.size());
}
}
static void executeJSFunctionFromReservedSpot(JSContext *cx, JS::HandleObject obj, static void executeJSFunctionFromReservedSpot(JSContext *cx, JS::HandleObject obj,
const JS::HandleValueArray& dataVal, JS::MutableHandleValue retval) { const JS::HandleValueArray& dataVal, JS::MutableHandleValue retval) {
@ -128,7 +148,6 @@ static void executeJSFunctionFromReservedSpot(JSContext *cx, JS::HandleObject ob
if (func.isNullOrUndefined()) { return; } if (func.isNullOrUndefined()) { return; }
JS::RootedValue thisObj(cx, JS_GetReservedSlot(obj, 1)); JS::RootedValue thisObj(cx, JS_GetReservedSlot(obj, 1));
JSAutoCompartment ac(cx, obj);
if (thisObj.isNullOrUndefined()) { if (thisObj.isNullOrUndefined()) {
JS_CallFunctionValue(cx, obj, func, dataVal, retval); JS_CallFunctionValue(cx, obj, func, dataVal, retval);
@ -471,6 +490,7 @@ ScriptingCore::ScriptingCore()
, _needCleanup(false) , _needCleanup(false)
, _global(nullptr) , _global(nullptr)
, _debugGlobal(nullptr) , _debugGlobal(nullptr)
, _oldCompartment(nullptr)
, _callFromScript(false) , _callFromScript(false)
, _finalizing(nullptr) , _finalizing(nullptr)
{ {
@ -510,7 +530,6 @@ void ScriptingCore::string_report(JS::HandleValue val) {
bool ScriptingCore::evalString(const char *string, JS::MutableHandleValue outVal, const char *filename, JSContext* cx, JS::HandleObject global) bool ScriptingCore::evalString(const char *string, JS::MutableHandleValue outVal, const char *filename, JSContext* cx, JS::HandleObject global)
{ {
JSAutoCompartment ac(cx, global);
JS::PersistentRootedScript script(cx); JS::PersistentRootedScript script(cx);
JS::CompileOptions op(cx); JS::CompileOptions op(cx);
@ -637,14 +656,14 @@ void ScriptingCore::createGlobalContext() {
JS_SetGCZeal(this->_cx, 2, JS_DEFAULT_ZEAL_FREQ); JS_SetGCZeal(this->_cx, 2, JS_DEFAULT_ZEAL_FREQ);
#endif #endif
_global = new (std::nothrow) JS::PersistentRootedObject(_rt, NewGlobalObject(_cx)); JS_SetGCCallback(_rt, onGarbageCollect, nullptr);
_global = new (std::nothrow) JS::PersistentRootedObject(_rt, newGlobalObject(_cx, false));
JS::RootedObject global(_cx, _global->get()); JS::RootedObject global(_cx, _global->get());
// Removed in Firefox v34 // Removed in Firefox v34
js::SetDefaultObjectForContext(_cx, global); js::SetDefaultObjectForContext(_cx, global);
JSAutoCompartment ac(_cx, _global->get());
runScript("script/jsb_prepare.js"); runScript("script/jsb_prepare.js");
for (auto& callback : registrationList) { for (auto& callback : registrationList) {
@ -696,7 +715,6 @@ JS::PersistentRootedScript* ScriptingCore::compileScript(const std::string& path
cocos2d::FileUtils *futil = cocos2d::FileUtils::getInstance(); cocos2d::FileUtils *futil = cocos2d::FileUtils::getInstance();
JSAutoCompartment ac(cx, global);
script = new (std::nothrow) JS::PersistentRootedScript(cx); script = new (std::nothrow) JS::PersistentRootedScript(cx);
if (script == nullptr) { if (script == nullptr) {
return nullptr; return nullptr;
@ -811,7 +829,6 @@ bool ScriptingCore::runScript(const std::string& path, JS::HandleObject global,
bool evaluatedOK = false; bool evaluatedOK = false;
if (script) { if (script) {
JS::RootedValue rval(cx); JS::RootedValue rval(cx);
JSAutoCompartment ac(cx, global);
evaluatedOK = JS_ExecuteScript(cx, global, *script, &rval); evaluatedOK = JS_ExecuteScript(cx, global, *script, &rval);
if (false == evaluatedOK) { if (false == evaluatedOK) {
cocos2d::log("Evaluating %s failed (evaluatedOK == JS_FALSE)", path.c_str()); cocos2d::log("Evaluating %s failed (evaluatedOK == JS_FALSE)", path.c_str());
@ -840,7 +857,6 @@ bool ScriptingCore::requireScript(const char *path, JS::HandleObject global, JSC
bool evaluatedOK = false; bool evaluatedOK = false;
if (script) if (script)
{ {
JSAutoCompartment ac(cx, global);
evaluatedOK = JS_ExecuteScript(cx, global, (*script), jsvalRet); evaluatedOK = JS_ExecuteScript(cx, global, (*script), jsvalRet);
if (false == evaluatedOK) if (false == evaluatedOK)
{ {
@ -902,11 +918,15 @@ void ScriptingCore::cleanup()
CC_SAFE_DELETE(_global); CC_SAFE_DELETE(_global);
CC_SAFE_DELETE(_debugGlobal); CC_SAFE_DELETE(_debugGlobal);
JS_LeaveCompartment(_cx, _oldCompartment);
_oldCompartment = nullptr;
if (_cx) if (_cx)
{ {
JS_DestroyContext(_cx); JS_DestroyContext(_cx);
_cx = NULL; _cx = NULL;
} }
if (_rt) if (_rt)
{ {
JS_DestroyRuntime(_rt); JS_DestroyRuntime(_rt);
@ -950,7 +970,6 @@ bool ScriptingCore::log(JSContext* cx, uint32_t argc, jsval *vp)
void ScriptingCore::retainScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target) void ScriptingCore::retainScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target)
{ {
JS::RootedObject global(_cx, _global->get()); JS::RootedObject global(_cx, _global->get());
JSAutoCompartment ac(_cx, global);
JS::RootedObject jsbObj(_cx); JS::RootedObject jsbObj(_cx);
get_or_create_js_obj(_cx, global, "jsb", &jsbObj); get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj)); JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
@ -984,7 +1003,6 @@ void ScriptingCore::retainScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target
void ScriptingCore::rootScriptObject(cocos2d::Ref* target) void ScriptingCore::rootScriptObject(cocos2d::Ref* target)
{ {
JS::RootedObject global(_cx, _global->get()); JS::RootedObject global(_cx, _global->get());
JSAutoCompartment ac(_cx, global);
JS::RootedObject jsbObj(_cx); JS::RootedObject jsbObj(_cx);
get_or_create_js_obj(_cx, global, "jsb", &jsbObj); get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj)); JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
@ -1019,7 +1037,6 @@ void ScriptingCore::rootScriptObject(cocos2d::Ref* target)
void ScriptingCore::releaseScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target) void ScriptingCore::releaseScriptObject(cocos2d::Ref* owner, cocos2d::Ref* target)
{ {
JS::RootedObject global(_cx, _global->get()); JS::RootedObject global(_cx, _global->get());
JSAutoCompartment ac(_cx, global);
JS::RootedObject jsbObj(_cx); JS::RootedObject jsbObj(_cx);
get_or_create_js_obj(_cx, global, "jsb", &jsbObj); get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj)); JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
@ -1053,7 +1070,6 @@ void ScriptingCore::releaseScriptObject(cocos2d::Ref* owner, cocos2d::Ref* targe
void ScriptingCore::unrootScriptObject(cocos2d::Ref* target) void ScriptingCore::unrootScriptObject(cocos2d::Ref* target)
{ {
JS::RootedObject global(_cx, _global->get()); JS::RootedObject global(_cx, _global->get());
JSAutoCompartment ac(_cx, global);
JS::RootedObject jsbObj(_cx); JS::RootedObject jsbObj(_cx);
get_or_create_js_obj(_cx, global, "jsb", &jsbObj); get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj)); JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
@ -1098,7 +1114,6 @@ void ScriptingCore::releaseAllChildrenRecursive(cocos2d::Node *node)
void ScriptingCore::releaseAllNativeRefs(cocos2d::Ref* owner) void ScriptingCore::releaseAllNativeRefs(cocos2d::Ref* owner)
{ {
JS::RootedObject global(_cx, _global->get()); JS::RootedObject global(_cx, _global->get());
JSAutoCompartment ac(_cx, global);
JS::RootedObject jsbObj(_cx); JS::RootedObject jsbObj(_cx);
get_or_create_js_obj(_cx, global, "jsb", &jsbObj); get_or_create_js_obj(_cx, global, "jsb", &jsbObj);
JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj)); JS::RootedValue jsbVal(_cx, OBJECT_TO_JSVAL(jsbObj));
@ -1239,7 +1254,6 @@ void ScriptingCore::cleanupSchedulesAndActions(js_proxy_t* p)
bool ScriptingCore::isFunctionOverridedInJS(JS::HandleObject obj, const std::string& name, JSNative native) bool ScriptingCore::isFunctionOverridedInJS(JS::HandleObject obj, const std::string& name, JSNative native)
{ {
JS::RootedObject jsobj(_cx, obj); JS::RootedObject jsobj(_cx, obj);
JSAutoCompartment ac(_cx, jsobj);
JS::RootedValue value(_cx); JS::RootedValue value(_cx);
bool ok = JS_GetProperty(_cx, jsobj, name.c_str(), &value); bool ok = JS_GetProperty(_cx, jsobj, name.c_str(), &value);
if (ok && !value.isNullOrUndefined() && !JS_IsNativeFunction(value.toObjectOrNull(), native)) if (ok && !value.isNullOrUndefined() && !JS_IsNativeFunction(value.toObjectOrNull(), native))
@ -1265,8 +1279,6 @@ int ScriptingCore::handleActionEvent(void* data)
js_proxy_t * p = jsb_get_native_proxy(actionObject); js_proxy_t * p = jsb_get_native_proxy(actionObject);
if (!p) return 0; if (!p) return 0;
JSAutoCompartment ac(_cx, _global->get());
int ret = 0; int ret = 0;
JS::RootedValue retval(_cx); JS::RootedValue retval(_cx);
@ -1297,8 +1309,6 @@ int ScriptingCore::handleNodeEvent(void* data)
js_proxy_t * p = jsb_get_native_proxy(node); js_proxy_t * p = jsb_get_native_proxy(node);
if (!p) return 0; if (!p) return 0;
JSAutoCompartment ac(_cx, _global->get());
int ret = 0; int ret = 0;
JS::RootedValue retval(_cx); JS::RootedValue retval(_cx);
jsval dataVal = INT_TO_JSVAL(1); jsval dataVal = INT_TO_JSVAL(1);
@ -1362,8 +1372,6 @@ int ScriptingCore::handleComponentEvent(void* data)
js_proxy_t * p = jsb_get_native_proxy(node); js_proxy_t * p = jsb_get_native_proxy(node);
if (!p) return 0; if (!p) return 0;
JSAutoCompartment ac(_cx, _global->get());
int ret = 0; int ret = 0;
JS::RootedValue retval(_cx); JS::RootedValue retval(_cx);
jsval dataVal = INT_TO_JSVAL(1); jsval dataVal = INT_TO_JSVAL(1);
@ -1404,8 +1412,6 @@ bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::Eve
bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::EventCode eventCode, const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event, JS::MutableHandleValue jsvalRet) bool ScriptingCore::handleTouchesEvent(void* nativeObj, cocos2d::EventTouch::EventCode eventCode, const std::vector<cocos2d::Touch*>& touches, cocos2d::Event* event, JS::MutableHandleValue jsvalRet)
{ {
JSAutoCompartment ac(_cx, _global->get());
bool ret = false; bool ret = false;
std::string funcName = getTouchesFuncName(eventCode); std::string funcName = getTouchesFuncName(eventCode);
JS::RootedObject jsretArr(_cx, JS_NewArrayObject(_cx, 0)); JS::RootedObject jsretArr(_cx, JS_NewArrayObject(_cx, 0));
@ -1450,8 +1456,6 @@ bool ScriptingCore::handleTouchEvent(void* nativeObj, cocos2d::EventTouch::Event
bool ScriptingCore::handleTouchEvent(void* nativeObj, cocos2d::EventTouch::EventCode eventCode, cocos2d::Touch* touch, cocos2d::Event* event, JS::MutableHandleValue jsvalRet) bool ScriptingCore::handleTouchEvent(void* nativeObj, cocos2d::EventTouch::EventCode eventCode, cocos2d::Touch* touch, cocos2d::Event* event, JS::MutableHandleValue jsvalRet)
{ {
JSAutoCompartment ac(_cx, _global->get());
std::string funcName = getTouchFuncName(eventCode); std::string funcName = getTouchFuncName(eventCode);
bool ret = false; bool ret = false;
@ -1481,8 +1485,6 @@ bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::Mouse
bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::MouseEventType eventType, cocos2d::Event* event, JS::MutableHandleValue jsvalRet) bool ScriptingCore::handleMouseEvent(void* nativeObj, cocos2d::EventMouse::MouseEventType eventType, cocos2d::Event* event, JS::MutableHandleValue jsvalRet)
{ {
JSAutoCompartment ac(_cx, _global->get());
std::string funcName = getMouseFuncName(eventType); std::string funcName = getMouseFuncName(eventType);
bool ret = false; bool ret = false;
@ -1551,8 +1553,6 @@ bool ScriptingCore::executeFunctionWithOwner(jsval owner, const char *name, cons
do do
{ {
JSAutoCompartment ac(cx, obj);
if (JS_HasProperty(cx, obj, name, &hasFunc) && hasFunc) { if (JS_HasProperty(cx, obj, name, &hasFunc) && hasFunc) {
if (!JS_GetProperty(cx, obj, name, &funcVal)) { if (!JS_GetProperty(cx, obj, name, &funcVal)) {
break; break;
@ -1575,8 +1575,6 @@ std::chrono::steady_clock::time_point ScriptingCore::getEngineStartTime() const
bool ScriptingCore::handleKeyboardEvent(void* nativeObj, cocos2d::EventKeyboard::KeyCode keyCode, bool isPressed, cocos2d::Event* event) bool ScriptingCore::handleKeyboardEvent(void* nativeObj, cocos2d::EventKeyboard::KeyCode keyCode, bool isPressed, cocos2d::Event* event)
{ {
JSAutoCompartment ac(_cx, _global->get());
js_proxy_t * p = jsb_get_native_proxy(nativeObj); js_proxy_t * p = jsb_get_native_proxy(nativeObj);
if (nullptr == p) if (nullptr == p)
return false; return false;
@ -1605,8 +1603,6 @@ bool ScriptingCore::handleKeyboardEvent(void* nativeObj, cocos2d::EventKeyboard:
bool ScriptingCore::handleFocusEvent(void* nativeObj, cocos2d::ui::Widget* widgetLoseFocus, cocos2d::ui::Widget* widgetGetFocus) bool ScriptingCore::handleFocusEvent(void* nativeObj, cocos2d::ui::Widget* widgetLoseFocus, cocos2d::ui::Widget* widgetGetFocus)
{ {
JSAutoCompartment ac(_cx, _global->get());
js_proxy_t * p = jsb_get_native_proxy(nativeObj); js_proxy_t * p = jsb_get_native_proxy(nativeObj);
if (nullptr == p) if (nullptr == p)
return false; return false;
@ -1627,8 +1623,6 @@ bool ScriptingCore::handleFocusEvent(void* nativeObj, cocos2d::ui::Widget* widge
int ScriptingCore::executeCustomTouchesEvent(EventTouch::EventCode eventType, int ScriptingCore::executeCustomTouchesEvent(EventTouch::EventCode eventType,
const std::vector<Touch*>& touches, JSObject *obj) const std::vector<Touch*>& touches, JSObject *obj)
{ {
JSAutoCompartment ac(_cx, _global->get());
std::string funcName = getTouchesFuncName(eventType); std::string funcName = getTouchesFuncName(eventType);
JS::RootedObject jsretArr(_cx, JS_NewArrayObject(this->_cx, 0)); JS::RootedObject jsretArr(_cx, JS_NewArrayObject(this->_cx, 0));
@ -1654,8 +1648,6 @@ int ScriptingCore::executeCustomTouchesEvent(EventTouch::EventCode eventType,
int ScriptingCore::executeCustomTouchEvent(EventTouch::EventCode eventType, Touch *touch, JSObject *obj) int ScriptingCore::executeCustomTouchEvent(EventTouch::EventCode eventType, Touch *touch, JSObject *obj)
{ {
JSAutoCompartment ac(_cx, _global->get());
JS::RootedValue retval(_cx); JS::RootedValue retval(_cx);
std::string funcName = getTouchFuncName(eventType); std::string funcName = getTouchFuncName(eventType);
@ -1686,8 +1678,6 @@ int ScriptingCore::executeCustomTouchEvent(EventTouch::EventCode eventType,
int ScriptingCore::executeGlobalFunction(const char* functionName) int ScriptingCore::executeGlobalFunction(const char* functionName)
{ {
JSAutoCompartment ac(_cx, _global->get());
std::string evalStr = functionName; std::string evalStr = functionName;
JS::RootedValue globalVal(_cx, OBJECT_TO_JSVAL(_global->get())); JS::RootedValue globalVal(_cx, OBJECT_TO_JSVAL(_global->get()));
return executeFunctionWithOwner(globalVal, functionName, 0, NULL); return executeFunctionWithOwner(globalVal, functionName, 0, NULL);
@ -1757,6 +1747,11 @@ bool ScriptingCore::isObjectValid(JSContext *cx, uint32_t argc, jsval *vp)
{ {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
if (argc == 1) { if (argc == 1) {
if (!args[0].isObject())
{
args.rval().setBoolean(false);
return true;
}
JS::RootedObject tmpObj(cx, args.get(0).toObjectOrNull()); JS::RootedObject tmpObj(cx, args.get(0).toObjectOrNull());
js_proxy_t *proxy = jsb_get_js_proxy(tmpObj); js_proxy_t *proxy = jsb_get_js_proxy(tmpObj);
if (proxy && proxy->ptr) { if (proxy && proxy->ptr) {
@ -1851,8 +1846,6 @@ void SimpleRunLoop::update(float dt)
void ScriptingCore::debugProcessInput(const std::string& str) void ScriptingCore::debugProcessInput(const std::string& str)
{ {
JSAutoCompartment ac(_cx, _debugGlobal->get());
JSString* jsstr = JS_NewStringCopyZ(_cx, str.c_str()); JSString* jsstr = JS_NewStringCopyZ(_cx, str.c_str());
jsval argv = STRING_TO_JSVAL(jsstr); jsval argv = STRING_TO_JSVAL(jsstr);
JS::RootedValue outval(_cx); JS::RootedValue outval(_cx);
@ -2076,11 +2069,9 @@ void ScriptingCore::enableDebugger(unsigned int port)
{ {
if (!_debugGlobal) if (!_debugGlobal)
{ {
JSAutoCompartment ac0(_cx, _global->get());
JS_SetDebugMode(_cx, true); JS_SetDebugMode(_cx, true);
_debugGlobal = new (std::nothrow) JS::PersistentRootedObject(_cx, NewGlobalObject(_cx, true)); _debugGlobal = new (std::nothrow) JS::PersistentRootedObject(_cx, newGlobalObject(_cx, true));
// Adds the debugger object to root, otherwise it may be collected by GC. // Adds the debugger object to root, otherwise it may be collected by GC.
//AddObjectRoot(_cx, &_debugGlobal.ref()); no need, it's persistent rooted now //AddObjectRoot(_cx, &_debugGlobal.ref()); no need, it's persistent rooted now
//JS_WrapObject(_cx, &_debugGlobal.ref()); Not really needed, JS_WrapObject makes a cross-compartment wrapper for the given JS object //JS_WrapObject(_cx, &_debugGlobal.ref()); Not really needed, JS_WrapObject makes a cross-compartment wrapper for the given JS object
@ -2117,7 +2108,7 @@ void ScriptingCore::enableDebugger(unsigned int port)
} }
} }
JSObject* NewGlobalObject(JSContext* cx, bool debug) JSObject* ScriptingCore::newGlobalObject(JSContext* cx, bool debug)
{ {
JS::CompartmentOptions options; JS::CompartmentOptions options;
options.setVersion(JSVERSION_LATEST); options.setVersion(JSVERSION_LATEST);
@ -2126,7 +2117,19 @@ JSObject* NewGlobalObject(JSContext* cx, bool debug)
if (!glob) { if (!glob) {
return nullptr; return nullptr;
} }
JSAutoCompartment ac(cx, glob);
JSCompartment* oldDebugCompartment = nullptr;
if (!debug)
{
_oldCompartment = JS_EnterCompartment(cx, glob);
}
else
{
oldDebugCompartment = JS_EnterCompartment(cx, glob);
}
bool ok = true; bool ok = true;
ok = JS_InitStandardClasses(cx, glob); ok = JS_InitStandardClasses(cx, glob);
if (ok) if (ok)
@ -2138,6 +2141,11 @@ JSObject* NewGlobalObject(JSContext* cx, bool debug)
JS_FireOnNewGlobalObject(cx, glob); JS_FireOnNewGlobalObject(cx, glob);
if (debug)
{
JS_LeaveCompartment(cx, oldDebugCompartment);
}
return glob; return glob;
} }
@ -2173,7 +2181,7 @@ js_proxy_t* jsb_new_proxy(void* nativeObj, JS::HandleObject jsHandle)
if (nativeObj && jsObj) if (nativeObj && jsObj)
{ {
// native to JS index // native to JS index
proxy = (js_proxy_t *)malloc(sizeof(js_proxy_t)); proxy = new (std::nothrow) js_proxy_t();
CC_ASSERT(proxy && "not enough memory"); CC_ASSERT(proxy && "not enough memory");
#if 0 #if 0
@ -2252,7 +2260,7 @@ void jsb_remove_proxy(js_proxy_t* proxy)
if (it_js != _js_native_global_map.end()) if (it_js != _js_native_global_map.end())
{ {
// Free it once, since we only have one proxy alloced entry // Free it once, since we only have one proxy alloced entry
free(it_js->second); delete it_js->second;
_js_native_global_map.erase(it_js); _js_native_global_map.erase(it_js);
} }
else CCLOG("jsb_remove_proxy: failed. JS key not found"); else CCLOG("jsb_remove_proxy: failed. JS key not found");
@ -2367,9 +2375,7 @@ JSObject* jsb_get_or_create_weak_jsobject(JSContext *cx, void *native, js_type_c
JS::RootedValue flagVal(cx, OBJECT_TO_JSVAL(flag)); JS::RootedValue flagVal(cx, OBJECT_TO_JSVAL(flag));
JS_SetProperty(cx, jsObj, "__cppCreated", flagVal); JS_SetProperty(cx, jsObj, "__cppCreated", flagVal);
#if ! CC_ENABLE_GC_FOR_NATIVE_OBJECTS #if CC_ENABLE_GC_FOR_NATIVE_OBJECTS
JS::AddNamedObjectRoot(cx, &proxy->obj, debug);
#else
js_add_FinalizeHook(cx, jsObj, false); js_add_FinalizeHook(cx, jsObj, false);
#if COCOS2D_DEBUG > 1 #if COCOS2D_DEBUG > 1
if (debug != nullptr) if (debug != nullptr)

View File

@ -84,6 +84,7 @@ private:
JSContext *_cx; JSContext *_cx;
JS::PersistentRootedObject *_global; JS::PersistentRootedObject *_global;
JS::PersistentRootedObject *_debugGlobal; JS::PersistentRootedObject *_debugGlobal;
JSCompartment *_oldCompartment;
SimpleRunLoop* _runLoop; SimpleRunLoop* _runLoop;
bool _jsInited; bool _jsInited;
bool _needCleanup; bool _needCleanup;
@ -556,6 +557,8 @@ private:
void string_report(JS::HandleValue val); void string_report(JS::HandleValue val);
void initRegister(); void initRegister();
JSObject* newGlobalObject(JSContext* cx, bool debug);
public: public:
int handleNodeEvent(void* data); int handleNodeEvent(void* data);
int handleActionEvent(void* data); int handleActionEvent(void* data);
@ -576,7 +579,6 @@ public:
void restartVM(); void restartVM();
}; };
JSObject* NewGlobalObject(JSContext* cx, bool debug = false);
bool jsb_set_reserved_slot(JSObject *obj, uint32_t idx, jsval value); bool jsb_set_reserved_slot(JSObject *obj, uint32_t idx, jsval value);
bool jsb_get_reserved_slot(JSObject *obj, uint32_t idx, jsval& ret); bool jsb_get_reserved_slot(JSObject *obj, uint32_t idx, jsval& ret);

View File

@ -601,7 +601,7 @@ void js_add_object_reference(JS::HandleValue owner, JS::HandleValue target)
ScriptingCore *engine = ScriptingCore::getInstance(); ScriptingCore *engine = ScriptingCore::getInstance();
JSContext *cx = engine->getGlobalContext(); JSContext *cx = engine->getGlobalContext();
JS::RootedObject global(cx, engine->getGlobalObject()); JS::RootedObject global(cx, engine->getGlobalObject());
JSAutoCompartment(cx, global);
JS::RootedObject jsbObj(cx); JS::RootedObject jsbObj(cx);
get_or_create_js_obj(cx, global, "jsb", &jsbObj); get_or_create_js_obj(cx, global, "jsb", &jsbObj);
JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj)); JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj));
@ -627,7 +627,7 @@ void js_remove_object_reference(JS::HandleValue owner, JS::HandleValue target)
ScriptingCore *engine = ScriptingCore::getInstance(); ScriptingCore *engine = ScriptingCore::getInstance();
JSContext *cx = engine->getGlobalContext(); JSContext *cx = engine->getGlobalContext();
JS::RootedObject global(cx, engine->getGlobalObject()); JS::RootedObject global(cx, engine->getGlobalObject());
JSAutoCompartment(cx, global);
JS::RootedObject ownerObj(cx, owner.toObjectOrNull()); JS::RootedObject ownerObj(cx, owner.toObjectOrNull());
JS::RootedObject targetObj(cx, target.toObjectOrNull()); JS::RootedObject targetObj(cx, target.toObjectOrNull());
@ -657,7 +657,7 @@ void js_add_object_root(JS::HandleValue target)
ScriptingCore *engine = ScriptingCore::getInstance(); ScriptingCore *engine = ScriptingCore::getInstance();
JSContext *cx = engine->getGlobalContext(); JSContext *cx = engine->getGlobalContext();
JS::RootedObject global(cx, engine->getGlobalObject()); JS::RootedObject global(cx, engine->getGlobalObject());
JSAutoCompartment(cx, global);
JS::RootedObject jsbObj(cx); JS::RootedObject jsbObj(cx);
get_or_create_js_obj(cx, global, "jsb", &jsbObj); get_or_create_js_obj(cx, global, "jsb", &jsbObj);
JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj)); JS::RootedValue jsbVal(cx, OBJECT_TO_JSVAL(jsbObj));
@ -687,7 +687,6 @@ void js_remove_object_root(JS::HandleValue target)
ScriptingCore *engine = ScriptingCore::getInstance(); ScriptingCore *engine = ScriptingCore::getInstance();
JSContext *cx = engine->getGlobalContext(); JSContext *cx = engine->getGlobalContext();
JS::RootedObject global(cx, engine->getGlobalObject()); JS::RootedObject global(cx, engine->getGlobalObject());
JSAutoCompartment(cx, global);
JS::RootedObject jsbObj(cx); JS::RootedObject jsbObj(cx);
get_or_create_js_obj(cx, global, "jsb", &jsbObj); get_or_create_js_obj(cx, global, "jsb", &jsbObj);
@ -711,138 +710,68 @@ void js_remove_object_root(JS::HandleValue target)
} }
JSCallbackWrapper::JSCallbackWrapper() JSCallbackWrapper::JSCallbackWrapper()
: _cppOwner(nullptr) : _jsCallback(nullptr)
, _jsThisObj(nullptr)
, _extraData(nullptr)
{ {
JSContext* cx = ScriptingCore::getInstance()->getGlobalContext();
JS::RootedObject root(cx);
get_or_create_js_obj("jsb._root", &root);
JS::RootedValue valRoot(cx, OBJECT_TO_JSVAL(root));
_owner = valRoot;
}
JSCallbackWrapper::JSCallbackWrapper(JS::HandleValue owner)
: _cppOwner(nullptr)
{
_owner = owner;
JS::RootedObject ownerObj(ScriptingCore::getInstance()->getGlobalContext(), owner.toObjectOrNull());
js_proxy *t = jsb_get_js_proxy(ownerObj);
if (t) {
_cppOwner = t->ptr;
}
} }
JSCallbackWrapper::~JSCallbackWrapper() JSCallbackWrapper::~JSCallbackWrapper()
{ {
ScriptingCore* sc = ScriptingCore::getInstance(); CC_SAFE_DELETE(_jsCallback);
JSContext* cx = sc->getGlobalContext(); CC_SAFE_DELETE(_jsThisObj);
JSAutoCompartment(cx, sc->getGlobalObject()); CC_SAFE_DELETE(_extraData);
JS::RootedValue ownerVal(cx, _owner);
if (sc->getFinalizing() || ownerVal.isNullOrUndefined())
{
return;
}
js_proxy *t;
if (_cppOwner != nullptr)
{
JS::RootedObject ownerObj(cx, ownerVal.toObjectOrNull());
t = jsb_get_js_proxy(ownerObj);
// Owner already released, no need to do the following release anymore, gc will take care of everything
if (t == nullptr || _cppOwner != t->ptr)
{
return;
}
}
JS::RootedValue target(cx, _jsCallback);
if (!target.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, target);
}
target.set(_jsThisObj);
if (!target.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, target);
}
target.set(_extraData);
if (!target.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, target);
}
} }
void JSCallbackWrapper::setJSCallbackFunc(JS::HandleValue func) { void JSCallbackWrapper::setJSCallbackFunc(JS::HandleValue func)
if (!func.isNullOrUndefined()) {
{ JSContext* cx = ScriptingCore::getInstance()->getGlobalContext();
JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); CC_SAFE_DELETE(_jsCallback);
JS::RootedValue ownerVal(cx, _owner); _jsCallback = new (std::nothrow) JS::PersistentRootedValue(cx, func);
if (!ownerVal.isNullOrUndefined())
{
JSAutoCompartment(cx, &ownerVal.toObject());
JS::RootedValue target(cx, _jsCallback);
if (!target.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, target);
}
js_add_object_reference(ownerVal, func);
}
_jsCallback = func;
}
} }
void JSCallbackWrapper::setJSCallbackThis(JS::HandleValue thisObj) { void JSCallbackWrapper::setJSCallbackThis(JS::HandleValue thisObj)
if (!thisObj.isNullOrUndefined()) {
{ JSContext* cx = ScriptingCore::getInstance()->getGlobalContext();
JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); CC_SAFE_DELETE(_jsThisObj);
JS::RootedValue ownerVal(cx, _owner); _jsThisObj = new (std::nothrow) JS::PersistentRootedValue(cx, thisObj);
if (!ownerVal.isNullOrUndefined())
{
JSAutoCompartment(cx, &ownerVal.toObject());
JS::RootedValue target(cx, _jsThisObj);
if (!target.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, target);
}
js_add_object_reference(ownerVal, thisObj);
}
_jsThisObj = thisObj;
}
} }
void JSCallbackWrapper::setJSExtraData(JS::HandleValue data) { void JSCallbackWrapper::setJSExtraData(JS::HandleValue data)
if (!data.isNullOrUndefined()) {
{ JSContext* cx = ScriptingCore::getInstance()->getGlobalContext();
JSContext* cx = ScriptingCore::getInstance()->getGlobalContext(); CC_SAFE_DELETE(_extraData);
JS::RootedValue ownerVal(cx, _owner); _extraData = new (std::nothrow) JS::PersistentRootedValue(cx, data);
if (!ownerVal.isNullOrUndefined())
{
JSAutoCompartment(cx, &ownerVal.toObject());
JS::RootedValue target(cx, _extraData);
if (!target.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, target);
}
js_add_object_reference(ownerVal, data);
}
_extraData = data;
}
} }
const jsval JSCallbackWrapper::getJSCallbackFunc() const const jsval JSCallbackWrapper::getJSCallbackFunc() const
{ {
return _jsCallback; if (_jsCallback != nullptr)
{
return _jsCallback->get();
}
return JS::NullValue();
} }
const jsval JSCallbackWrapper::getJSCallbackThis() const const jsval JSCallbackWrapper::getJSCallbackThis() const
{ {
return _jsThisObj; if (_jsThisObj != nullptr)
{
return _jsThisObj->get();
}
return JS::NullValue();
} }
const jsval JSCallbackWrapper::getJSExtraData() const const jsval JSCallbackWrapper::getJSExtraData() const
{ {
return _extraData; if (_extraData != nullptr)
{
return _extraData->get();
}
return JS::NullValue();
} }
// cc.CallFunc.create( func, this, [data]) // cc.CallFunc.create( func, this, [data])
@ -858,7 +787,7 @@ static bool js_callFunc(JSContext *cx, uint32_t argc, jsval *vp)
JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, ret, typeClass, "cocos2d::CallFuncN")); JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, ret, typeClass, "cocos2d::CallFuncN"));
JS::RootedValue retVal(cx, OBJECT_TO_JSVAL(jsobj)); JS::RootedValue retVal(cx, OBJECT_TO_JSVAL(jsobj));
std::shared_ptr<JSCallbackWrapper> tmpCobj(new JSCallbackWrapper(retVal)); std::shared_ptr<JSCallbackWrapper> tmpCobj(new JSCallbackWrapper());
JS::RootedValue callback(cx, args.get(0)); JS::RootedValue callback(cx, args.get(0));
tmpCobj->setJSCallbackFunc(callback); tmpCobj->setJSCallbackFunc(callback);
@ -876,7 +805,13 @@ static bool js_callFunc(JSContext *cx, uint32_t argc, jsval *vp)
bool ok = ret->initWithFunction([=](Node* sender){ bool ok = ret->initWithFunction([=](Node* sender){
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
JS::RootedValue jsvalThis(cx, tmpCobj->getJSCallbackThis()); JS::RootedValue jsvalThis(cx, tmpCobj->getJSCallbackThis());
JS::RootedObject thisObj(cx, jsvalThis.toObjectOrNull());
JS::RootedObject thisObj(cx);
if (jsvalThis.isObject())
{
thisObj.set(jsvalThis.toObjectOrNull());
}
JS::RootedValue jsvalCallback(cx, tmpCobj->getJSCallbackFunc()); JS::RootedValue jsvalCallback(cx, tmpCobj->getJSCallbackFunc());
JS::RootedValue jsvalExtraData(cx, tmpCobj->getJSExtraData()); JS::RootedValue jsvalExtraData(cx, tmpCobj->getJSExtraData());
@ -930,7 +865,7 @@ bool js_cocos2dx_CallFunc_initWithFunction(JSContext *cx, uint32_t argc, jsval *
CallFuncN *action = (cocos2d::CallFuncN *)(proxy ? proxy->ptr : nullptr); CallFuncN *action = (cocos2d::CallFuncN *)(proxy ? proxy->ptr : nullptr);
JSB_PRECONDITION2(action, cx, false, "Invalid Native Object"); JSB_PRECONDITION2(action, cx, false, "Invalid Native Object");
std::shared_ptr<JSCallbackWrapper> tmpCobj(new JSCallbackWrapper(args.thisv())); std::shared_ptr<JSCallbackWrapper> tmpCobj(new JSCallbackWrapper());
JS::RootedValue callback(cx, args.get(0)); JS::RootedValue callback(cx, args.get(0));
tmpCobj->setJSCallbackFunc(callback); tmpCobj->setJSCallbackFunc(callback);
@ -980,24 +915,20 @@ bool js_cocos2dx_CallFunc_initWithFunction(JSContext *cx, uint32_t argc, jsval *
} }
JSScheduleWrapper::JSScheduleWrapper() JSScheduleWrapper::JSScheduleWrapper()
: JSCallbackWrapper() : _pTarget(nullptr)
, _pTarget(nullptr)
, _priority(0) , _priority(0)
, _isUpdateSchedule(false) , _isUpdateSchedule(false)
, _pPureJSTarget(nullptr)
{ {
_pPureJSTarget = nullptr;
} }
JSScheduleWrapper::JSScheduleWrapper(JS::HandleValue owner) JSScheduleWrapper::~JSScheduleWrapper()
: JSCallbackWrapper(owner)
, _pTarget(nullptr)
, _priority(0)
, _isUpdateSchedule(false)
{ {
_pPureJSTarget = nullptr; CC_SAFE_DELETE(_pPureJSTarget);
} }
void JSScheduleWrapper::setTargetForSchedule(JS::HandleValue sched, JSScheduleWrapper *target) { void JSScheduleWrapper::setTargetForSchedule(JS::HandleValue sched, JSScheduleWrapper *target)
{
do { do {
JSObject* jsfunc = sched.toObjectOrNull(); JSObject* jsfunc = sched.toObjectOrNull();
auto targetArray = getTargetForSchedule(sched); auto targetArray = getTargetForSchedule(sched);
@ -1016,14 +947,14 @@ void JSScheduleWrapper::setTargetForSchedule(JS::HandleValue sched, JSScheduleWr
} while(0); } while(0);
} }
JSBinding::Array* JSScheduleWrapper::getTargetForSchedule(JS::HandleValue sched) { JSBinding::Array* JSScheduleWrapper::getTargetForSchedule(JS::HandleValue sched)
{
schedFunc_proxy_t *t = nullptr; schedFunc_proxy_t *t = nullptr;
JSObject *o = sched.toObjectOrNull(); JSObject *o = sched.toObjectOrNull();
HASH_FIND_PTR(_schedFunc_target_ht, &o, t); HASH_FIND_PTR(_schedFunc_target_ht, &o, t);
return t != nullptr ? t->targets : nullptr; return t != nullptr ? t->targets : nullptr;
} }
void JSScheduleWrapper::setTargetForJSObject(JS::HandleObject jsTargetObj, JSScheduleWrapper *target) void JSScheduleWrapper::setTargetForJSObject(JS::HandleObject jsTargetObj, JSScheduleWrapper *target)
{ {
auto targetArray = getTargetForJSObject(jsTargetObj); auto targetArray = getTargetForJSObject(jsTargetObj);
@ -1323,12 +1254,14 @@ void JSScheduleWrapper::setTarget(Ref* pTarget)
void JSScheduleWrapper::setPureJSTarget(JS::HandleObject pPureJSTarget) void JSScheduleWrapper::setPureJSTarget(JS::HandleObject pPureJSTarget)
{ {
_pPureJSTarget = pPureJSTarget; JSContext* cx = ScriptingCore::getInstance()->getGlobalContext();
CC_SAFE_DELETE(_pPureJSTarget);
_pPureJSTarget = new JS::PersistentRootedObject(cx, pPureJSTarget);
} }
JSObject* JSScheduleWrapper::getPureJSTarget() JSObject* JSScheduleWrapper::getPureJSTarget()
{ {
return _pPureJSTarget; return _pPureJSTarget->get();
} }
void JSScheduleWrapper::setPriority(int priority) void JSScheduleWrapper::setPriority(int priority)
@ -1467,7 +1400,7 @@ bool js_CCNode_scheduleOnce(JSContext *cx, uint32_t argc, jsval *vp)
if (!bFound) if (!bFound)
{ {
tmpCobj = new (std::nothrow) JSScheduleWrapper(thisValue); tmpCobj = new (std::nothrow) JSScheduleWrapper();
tmpCobj->autorelease(); tmpCobj->autorelease();
tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackThis(thisValue);
tmpCobj->setJSCallbackFunc(args.get(0)); tmpCobj->setJSCallbackFunc(args.get(0));
@ -1565,7 +1498,7 @@ bool js_CCNode_schedule(JSContext *cx, uint32_t argc, jsval *vp)
if (!bFound) if (!bFound)
{ {
tmpCobj = new (std::nothrow) JSScheduleWrapper(thisValue); tmpCobj = new (std::nothrow) JSScheduleWrapper();
tmpCobj->autorelease(); tmpCobj->autorelease();
tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackThis(thisValue);
tmpCobj->setJSCallbackFunc(args.get(0)); tmpCobj->setJSCallbackFunc(args.get(0));
@ -1641,7 +1574,7 @@ bool js_cocos2dx_CCNode_scheduleUpdateWithPriority(JSContext *cx, uint32_t argc,
if (!bFound) if (!bFound)
{ {
tmpCobj = new (std::nothrow) JSScheduleWrapper(JS::NullHandleValue); tmpCobj = new (std::nothrow) JSScheduleWrapper();
tmpCobj->autorelease(); tmpCobj->autorelease();
tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackThis(thisValue);
tmpCobj->setJSCallbackFunc(jsUpdateFunc); tmpCobj->setJSCallbackFunc(jsUpdateFunc);
@ -1744,7 +1677,7 @@ bool js_cocos2dx_CCNode_scheduleUpdate(JSContext *cx, uint32_t argc, jsval *vp)
if (!bFound) if (!bFound)
{ {
tmpCobj = new (std::nothrow) JSScheduleWrapper(JS::NullHandleValue); tmpCobj = new (std::nothrow) JSScheduleWrapper();
tmpCobj->autorelease(); tmpCobj->autorelease();
tmpCobj->setJSCallbackThis(thisValue); tmpCobj->setJSCallbackThis(thisValue);
tmpCobj->setJSCallbackFunc(jsUpdateFunc); tmpCobj->setJSCallbackFunc(jsUpdateFunc);
@ -1861,7 +1794,7 @@ bool js_CCScheduler_scheduleUpdateForTarget(JSContext *cx, uint32_t argc, jsval
if (!bFound) if (!bFound)
{ {
tmpCObj = new (std::nothrow) JSScheduleWrapper(args.thisv()); tmpCObj = new (std::nothrow) JSScheduleWrapper();
tmpCObj->autorelease(); tmpCObj->autorelease();
tmpCObj->setJSCallbackThis(args.get(0)); tmpCObj->setJSCallbackThis(args.get(0));
tmpCObj->setJSCallbackFunc(jsUpdateFunc); tmpCObj->setJSCallbackFunc(jsUpdateFunc);
@ -1989,7 +1922,7 @@ bool js_CCScheduler_scheduleCallbackForTarget(JSContext *cx, uint32_t argc, jsva
if (!bFound) if (!bFound)
{ {
tmpCObj = new (std::nothrow) JSScheduleWrapper(args.thisv()); tmpCObj = new (std::nothrow) JSScheduleWrapper();
tmpCObj->autorelease(); tmpCObj->autorelease();
tmpCObj->setJSCallbackThis(args.get(0)); tmpCObj->setJSCallbackThis(args.get(0));
tmpCObj->setJSCallbackFunc(args.get(1)); tmpCObj->setJSCallbackFunc(args.get(1));
@ -2660,6 +2593,9 @@ bool js_cocos2dx_ActionInterval_repeat(JSContext *cx, uint32_t argc, jsval *vp)
cocos2d::Repeat* action = new (std::nothrow) cocos2d::Repeat; cocos2d::Repeat* action = new (std::nothrow) cocos2d::Repeat;
action->initWithAction(cobj, timesInt); action->initWithAction(cobj, timesInt);
#if !CC_ENABLE_GC_FOR_NATIVE_OBJECTS
action->autorelease();
#endif
jsb_ref_rebind(cx, obj, proxy, cobj, action, "cocos2d::Repeat"); jsb_ref_rebind(cx, obj, proxy, cobj, action, "cocos2d::Repeat");
args.rval().set(OBJECT_TO_JSVAL(obj)); args.rval().set(OBJECT_TO_JSVAL(obj));
@ -2681,7 +2617,9 @@ bool js_cocos2dx_ActionInterval_repeatForever(JSContext *cx, uint32_t argc, jsva
if (argc == 0) { if (argc == 0) {
cocos2d::RepeatForever* action = new (std::nothrow) cocos2d::RepeatForever; cocos2d::RepeatForever* action = new (std::nothrow) cocos2d::RepeatForever;
action->initWithAction(cobj); action->initWithAction(cobj);
#if !CC_ENABLE_GC_FOR_NATIVE_OBJECTS
action->autorelease();
#endif
jsb_ref_rebind(cx, jsobj, proxy, cobj, action, "cocos2d::RepeatForever"); jsb_ref_rebind(cx, jsobj, proxy, cobj, action, "cocos2d::RepeatForever");
args.rval().set(OBJECT_TO_JSVAL(jsobj)); args.rval().set(OBJECT_TO_JSVAL(jsobj));
return true; return true;
@ -2712,6 +2650,9 @@ bool js_cocos2dx_ActionInterval_speed(JSContext *cx, uint32_t argc, jsval *vp)
cocos2d::Speed* action = new (std::nothrow) cocos2d::Speed; cocos2d::Speed* action = new (std::nothrow) cocos2d::Speed;
action->initWithAction(cobj, speed); action->initWithAction(cobj, speed);
#if !CC_ENABLE_GC_FOR_NATIVE_OBJECTS
action->autorelease();
#endif
jsb_ref_rebind(cx, obj, proxy, cobj, action, "cocos2d::Speed"); jsb_ref_rebind(cx, obj, proxy, cobj, action, "cocos2d::Speed");
args.rval().set(OBJECT_TO_JSVAL(obj)); args.rval().set(OBJECT_TO_JSVAL(obj));
@ -2762,6 +2703,12 @@ enum ACTION_TAG {
bool js_cocos2dx_ActionInterval_easing(JSContext *cx, uint32_t argc, jsval *vp) bool js_cocos2dx_ActionInterval_easing(JSContext *cx, uint32_t argc, jsval *vp)
{ {
if (argc == 0)
{
JS_ReportError(cx, "wrong number of arguments: %d, was expecting %d", argc, 0);
return false;
}
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::RootedObject jsobj(cx, args.thisv().toObjectOrNull()); JS::RootedObject jsobj(cx, args.thisv().toObjectOrNull());
js_proxy_t *proxy = jsb_get_js_proxy(jsobj); js_proxy_t *proxy = jsb_get_js_proxy(jsobj);
@ -2772,19 +2719,19 @@ bool js_cocos2dx_ActionInterval_easing(JSContext *cx, uint32_t argc, jsval *vp)
JS::RootedObject tmp(cx); JS::RootedObject tmp(cx);
JS::RootedValue jsTag(cx); JS::RootedValue jsTag(cx);
JS::RootedValue jsParam(cx); JS::RootedValue jsParam(cx);
double tag; double tag = 0.0;
double parameter; double parameter = 0.0;
for (uint32_t i = 0; i < argc; i++) do
{ {
JS::RootedValue vpi(cx, args.get(i)); JS::RootedValue vpi(cx, args[0]);
bool ok = vpi.isObject() && bool ok = vpi.isObject() &&
JS_ValueToObject(cx, vpi, &tmp) && JS_ValueToObject(cx, vpi, &tmp) &&
JS_GetProperty(cx, tmp, "tag", &jsTag) && JS_GetProperty(cx, tmp, "tag", &jsTag) &&
JS::ToNumber(cx, jsTag, &tag); JS::ToNumber(cx, jsTag, &tag);
JS_GetProperty(cx, tmp, "param", &jsParam) && JS::ToNumber(cx, jsParam, &parameter); JS_GetProperty(cx, tmp, "param", &jsParam) && JS::ToNumber(cx, jsParam, &parameter);
bool hasParam = (parameter == parameter); bool hasParam = (parameter == parameter);
if (!ok) continue; if (!ok) break;
ok = true; ok = true;
if (tag == EASE_IN) if (tag == EASE_IN)
@ -3003,7 +2950,7 @@ bool js_cocos2dx_ActionInterval_easing(JSContext *cx, uint32_t argc, jsval *vp)
ok &= JS::ToNumber(cx, jsParam3, &parameter3); ok &= JS::ToNumber(cx, jsParam3, &parameter3);
ok &= JS_GetProperty(cx, tmp, "param4", &jsParam4); ok &= JS_GetProperty(cx, tmp, "param4", &jsParam4);
ok &= JS::ToNumber(cx, jsParam4, &parameter4); ok &= JS::ToNumber(cx, jsParam4, &parameter4);
if (!ok) continue; if (!ok) break;
auto tmpaction = new (std::nothrow) cocos2d::EaseBezierAction; auto tmpaction = new (std::nothrow) cocos2d::EaseBezierAction;
tmpaction->initWithAction(oldAction); tmpaction->initWithAction(oldAction);
@ -3011,14 +2958,19 @@ bool js_cocos2dx_ActionInterval_easing(JSContext *cx, uint32_t argc, jsval *vp)
newAction = tmpaction; newAction = tmpaction;
} }
else else
continue; {
break;
}
if (!ok || !newAction) { if (!ok || !newAction) {
JS_ReportError(cx, "js_cocos2dx_ActionInterval_easing : Invalid action: At least one action was expecting parameter"); JS_ReportError(cx, "js_cocos2dx_ActionInterval_easing : Invalid action: At least one action was expecting parameter");
return false; return false;
} }
} } while (false);
#if !CC_ENABLE_GC_FOR_NATIVE_OBJECTS
newAction->autorelease();
#endif
// Unbind existing proxy binding with cobj, and rebind with the new action // Unbind existing proxy binding with cobj, and rebind with the new action
jsb_ref_rebind(cx, jsobj, proxy, oldAction, newAction, "cocos2d::EaseAction"); jsb_ref_rebind(cx, jsobj, proxy, oldAction, newAction, "cocos2d::EaseAction");

View File

@ -158,8 +158,8 @@ void register_cocos2dx_js_core(JSContext* cx, JS::HandleObject obj);
class JSCallbackWrapper: public cocos2d::Ref { class JSCallbackWrapper: public cocos2d::Ref {
public: public:
JSCallbackWrapper(); JSCallbackWrapper();
JSCallbackWrapper(JS::HandleValue owner);
virtual ~JSCallbackWrapper(); virtual ~JSCallbackWrapper();
void setJSCallbackFunc(JS::HandleValue callback); void setJSCallbackFunc(JS::HandleValue callback);
void setJSCallbackThis(JS::HandleValue thisObj); void setJSCallbackThis(JS::HandleValue thisObj);
void setJSExtraData(JS::HandleValue data); void setJSExtraData(JS::HandleValue data);
@ -168,19 +168,17 @@ public:
const jsval getJSCallbackThis() const; const jsval getJSCallbackThis() const;
const jsval getJSExtraData() const; const jsval getJSExtraData() const;
protected: protected:
JS::Heap<JS::Value> _owner; JS::PersistentRootedValue* _jsCallback;
JS::Heap<JS::Value> _jsCallback; JS::PersistentRootedValue* _jsThisObj;
JS::Heap<JS::Value> _jsThisObj; JS::PersistentRootedValue* _extraData;
JS::Heap<JS::Value> _extraData;
void* _cppOwner;
}; };
class JSScheduleWrapper: public JSCallbackWrapper { class JSScheduleWrapper: public JSCallbackWrapper
{
public: public:
JSScheduleWrapper(); JSScheduleWrapper();
JSScheduleWrapper(JS::HandleValue owner); virtual ~JSScheduleWrapper();
static void setTargetForSchedule(JS::HandleValue sched, JSScheduleWrapper *target); static void setTargetForSchedule(JS::HandleValue sched, JSScheduleWrapper *target);
static JSBinding::Array* getTargetForSchedule(JS::HandleValue sched); static JSBinding::Array* getTargetForSchedule(JS::HandleValue sched);
@ -216,7 +214,7 @@ public:
protected: protected:
Ref* _pTarget; Ref* _pTarget;
JS::Heap<JSObject*> _pPureJSTarget; JS::PersistentRootedObject* _pPureJSTarget;
int _priority; int _priority;
bool _isUpdateSchedule; bool _isUpdateSchedule;
}; };

View File

@ -29,7 +29,7 @@
class JSCCBAnimationWrapper: public JSCallbackWrapper class JSCCBAnimationWrapper: public JSCallbackWrapper
{ {
public: public:
JSCCBAnimationWrapper(JS::HandleValue owner) : JSCallbackWrapper(owner) {} JSCCBAnimationWrapper() {}
void animationCompleteCallback() void animationCompleteCallback()
{ {

View File

@ -99,7 +99,7 @@ bool js_cocos2dx_CCBAnimationManager_animationCompleteCallback(JSContext *cx, ui
js_proxy_t *p = jsb_get_js_proxy(obj); js_proxy_t *p = jsb_get_js_proxy(obj);
cocosbuilder::CCBAnimationManager *node = (cocosbuilder::CCBAnimationManager *)(p ? p->ptr : NULL); cocosbuilder::CCBAnimationManager *node = (cocosbuilder::CCBAnimationManager *)(p ? p->ptr : NULL);
JSCCBAnimationWrapper *tmpCobj = new (std::nothrow) JSCCBAnimationWrapper(args.thisv()); JSCCBAnimationWrapper *tmpCobj = new (std::nothrow) JSCCBAnimationWrapper();
tmpCobj->autorelease(); tmpCobj->autorelease();
tmpCobj->setJSCallbackThis(args.get(0)); tmpCobj->setJSCallbackThis(args.get(0));

View File

@ -28,7 +28,7 @@
class JSArmatureWrapper: public JSCallbackWrapper { class JSArmatureWrapper: public JSCallbackWrapper {
public: public:
JSArmatureWrapper(JS::HandleValue owner) : JSCallbackWrapper(owner) {}; JSArmatureWrapper(){};
void movementCallbackFunc(cocostudio::Armature *armature, cocostudio::MovementEventType movementType, const std::string& movementID); 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 frameCallbackFunc(cocostudio::Bone *bone, const std::string& evt, int originFrameIndex, int currentFrameIndex);
@ -117,7 +117,7 @@ static bool js_cocos2dx_ArmatureAnimation_setMovementEventCallFunc(JSContext *cx
return true; return true;
} }
else if (argc == 1 || argc == 2) { else if (argc == 1 || argc == 2) {
JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper(args.thisv()); JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper();
tmpObj->autorelease(); tmpObj->autorelease();
auto userDict = static_cast<JSBinding::DictionaryRef*>(cobj->getUserObject()); auto userDict = static_cast<JSBinding::DictionaryRef*>(cobj->getUserObject());
@ -164,7 +164,7 @@ static bool js_cocos2dx_ArmatureAnimation_setFrameEventCallFunc(JSContext *cx, u
return true; return true;
} }
else if (argc == 1 || argc == 2) { else if (argc == 1 || argc == 2) {
JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper(args.thisv()); JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper();
tmpObj->autorelease(); tmpObj->autorelease();
auto dict = static_cast<JSBinding::DictionaryRef*>(cobj->getUserObject()); auto dict = static_cast<JSBinding::DictionaryRef*>(cobj->getUserObject());
@ -206,7 +206,7 @@ static bool jsb_Animation_addArmatureFileInfoAsyncCallFunc(JSContext *cx, uint32
JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object"); JSB_PRECONDITION2( cobj, cx, false, "Invalid Native Object");
if (argc == 3) { if (argc == 3) {
JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper(args.thisv()); JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper();
tmpObj->autorelease(); tmpObj->autorelease();
tmpObj->setJSCallbackFunc(args.get(1)); tmpObj->setJSCallbackFunc(args.get(1));
@ -221,7 +221,7 @@ static bool jsb_Animation_addArmatureFileInfoAsyncCallFunc(JSContext *cx, uint32
} }
if(argc == 5){ if(argc == 5){
JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper(args.thisv()); JSArmatureWrapper *tmpObj = new (std::nothrow) JSArmatureWrapper();
tmpObj->autorelease(); tmpObj->autorelease();
tmpObj->setJSCallbackFunc(args.get(3)); tmpObj->setJSCallbackFunc(args.get(3));

View File

@ -31,8 +31,10 @@
#include "base/CCDirector.h" #include "base/CCDirector.h"
#include "base/CCScheduler.h" #include "base/CCScheduler.h"
#include "network/CCDownloader.h"
#include "renderer/CCTextureCache.h" #include "renderer/CCTextureCache.h"
#include "renderer/CCTextureCube.h" #include "renderer/CCTextureCube.h"
#include "renderer/CCTexture2D.h"
USING_NS_CC; USING_NS_CC;
USING_NS_CC_EXT; USING_NS_CC_EXT;
@ -301,7 +303,6 @@ private:
jsval dataVal = OBJECT_TO_JSVAL(p->obj); jsval dataVal = OBJECT_TO_JSVAL(p->obj);
JS::RootedObject obj(cx, _JSTableViewDataSource); JS::RootedObject obj(cx, _JSTableViewDataSource);
JSAutoCompartment ac(cx, obj);
if (JS_HasProperty(cx, obj, jsFunctionName.c_str(), &hasAction) && hasAction) if (JS_HasProperty(cx, obj, jsFunctionName.c_str(), &hasAction) && hasAction)
{ {
@ -334,7 +335,6 @@ private:
dataVal[1] = ssize_to_jsval(cx,idx); dataVal[1] = ssize_to_jsval(cx,idx);
JS::RootedObject obj(cx, _JSTableViewDataSource); JS::RootedObject obj(cx, _JSTableViewDataSource);
JSAutoCompartment ac(cx, obj);
if (JS_HasProperty(cx, obj, jsFunctionName.c_str(), &hasAction) && hasAction) if (JS_HasProperty(cx, obj, jsFunctionName.c_str(), &hasAction) && hasAction)
{ {
@ -813,10 +813,6 @@ bool js_cocos2dx_extension_EventListenerAssetsManagerEx_create(JSContext *cx, ui
if (ret) { if (ret) {
JS::RootedObject jsobj(cx, js_get_or_create_jsobject<cocos2d::extension::EventListenerAssetsManagerEx>(cx, ret)); JS::RootedObject jsobj(cx, js_get_or_create_jsobject<cocos2d::extension::EventListenerAssetsManagerEx>(cx, ret));
jsret = OBJECT_TO_JSVAL(jsobj); jsret = OBJECT_TO_JSVAL(jsobj);
if (wrapper)
{
wrapper->setOwner(cx, jsret);
}
} else { } else {
jsret = JS::NullValue(); jsret = JS::NullValue();
} }
@ -827,50 +823,54 @@ bool js_cocos2dx_extension_EventListenerAssetsManagerEx_create(JSContext *cx, ui
return false; return false;
} }
__JSDownloaderDelegator::__JSDownloaderDelegator(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleObject callback) class JSDownloaderDelegator : cocos2d::Ref
{
public:
void download();
static JSDownloaderDelegator *create(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleValue callback);
protected:
JSDownloaderDelegator(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleValue callback);
~JSDownloaderDelegator();
void startDownload();
private:
void onSuccess(cocos2d::Texture2D *tex);
void onError();
std::shared_ptr<cocos2d::network::Downloader> _downloader;
std::string _url;
JSContext *_cx;
JS::PersistentRootedValue* _jsCallback;
JS::PersistentRootedObject* _obj;
};
JSDownloaderDelegator::JSDownloaderDelegator(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleValue callback)
: _cx(cx) : _cx(cx)
, _url(url) , _url(url)
{ {
_obj = obj; _obj = new (std::nothrow) JS::PersistentRootedObject(cx, obj);
_jsCallback = callback; _jsCallback = new (std::nothrow) JS::PersistentRootedValue(cx, callback);
JS::RootedValue target(cx, OBJECT_TO_JSVAL(obj));
if (!target.isNullOrUndefined())
{
js_add_object_root(target);
}
target.set(OBJECT_TO_JSVAL(callback));
if (!target.isNullOrUndefined())
{
js_add_object_root(target);
}
} }
__JSDownloaderDelegator::~__JSDownloaderDelegator() JSDownloaderDelegator::~JSDownloaderDelegator()
{ {
JS::RootedValue target(_cx, OBJECT_TO_JSVAL(_obj)); CC_SAFE_DELETE(_obj);
if (!target.isNullOrUndefined()) CC_SAFE_DELETE(_jsCallback);
{
js_remove_object_root(target);
}
target.set(OBJECT_TO_JSVAL(_jsCallback));
if (!target.isNullOrUndefined())
{
js_remove_object_root(target);
}
_downloader->onTaskError = (nullptr); _downloader->onTaskError = nullptr;
_downloader->onDataTaskSuccess = (nullptr); _downloader->onDataTaskSuccess = nullptr;
} }
__JSDownloaderDelegator *__JSDownloaderDelegator::create(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleObject callback) JSDownloaderDelegator *JSDownloaderDelegator::create(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleValue callback)
{ {
__JSDownloaderDelegator *delegate = new (std::nothrow) __JSDownloaderDelegator(cx, obj, url, callback); JSDownloaderDelegator *delegate = new (std::nothrow) JSDownloaderDelegator(cx, obj, url, callback);
delegate->autorelease(); delegate->autorelease();
return delegate; return delegate;
} }
void __JSDownloaderDelegator::startDownload() void JSDownloaderDelegator::startDownload()
{ {
if (auto texture = Director::getInstance()->getTextureCache()->getTextureForKey(_url)) if (auto texture = Director::getInstance()->getTextureCache()->getTextureForKey(_url))
{ {
@ -918,65 +918,50 @@ void __JSDownloaderDelegator::startDownload()
} }
} }
void __JSDownloaderDelegator::download() void JSDownloaderDelegator::download()
{ {
retain(); retain();
startDownload(); startDownload();
} }
void __JSDownloaderDelegator::downloadAsync() void JSDownloaderDelegator::onError()
{ {
retain(); JS::RootedValue callback(_cx, *_jsCallback);
auto t = std::thread(&__JSDownloaderDelegator::startDownload, this); if (!callback.isNull()) {
t.detach();
}
void __JSDownloaderDelegator::onError()
{
Director::getInstance()->getScheduler()->performFunctionInCocosThread([this]
{
JS::RootedValue callback(_cx, OBJECT_TO_JSVAL(_jsCallback));
if (!callback.isNull()) {
JS::RootedObject global(_cx, ScriptingCore::getInstance()->getGlobalObject());
JSAutoCompartment ac(_cx, global);
jsval succeed = BOOLEAN_TO_JSVAL(false);
JS::RootedValue retval(_cx);
JS_CallFunctionValue(_cx, global, callback, JS::HandleValueArray::fromMarkedLocation(1, &succeed), &retval);
}
release();
});
}
void __JSDownloaderDelegator::onSuccess(Texture2D *tex)
{
CCASSERT(tex, "__JSDownloaderDelegator::onSuccess must make sure tex not null!");
//Director::getInstance()->getScheduler()->performFunctionInCocosThread([this, tex]
{
JS::RootedObject global(_cx, ScriptingCore::getInstance()->getGlobalObject()); JS::RootedObject global(_cx, ScriptingCore::getInstance()->getGlobalObject());
JSAutoCompartment ac(_cx, global);
jsval valArr[2]; jsval succeed = BOOLEAN_TO_JSVAL(false);
if (tex) JS::RootedValue retval(_cx);
{ JS_CallFunctionValue(_cx, global, callback, JS::HandleValueArray::fromMarkedLocation(1, &succeed), &retval);
valArr[0] = BOOLEAN_TO_JSVAL(true); }
JS::RootedObject jsobj(_cx, js_get_or_create_jsobject<Texture2D>(_cx, tex)); release();
valArr[1] = OBJECT_TO_JSVAL(jsobj); }
}
else
{
valArr[0] = BOOLEAN_TO_JSVAL(false);
valArr[1] = JSVAL_NULL;
}
JS::RootedValue callback(_cx, OBJECT_TO_JSVAL(_jsCallback)); void JSDownloaderDelegator::onSuccess(Texture2D *tex)
if (!callback.isNull()) {
{ CCASSERT(tex, "JSDownloaderDelegator::onSuccess must make sure tex not null!");
JS::RootedValue retval(_cx); JS::RootedObject global(_cx, ScriptingCore::getInstance()->getGlobalObject());
JS_CallFunctionValue(_cx, global, callback, JS::HandleValueArray::fromMarkedLocation(2, valArr), &retval);
} jsval valArr[2];
release(); if (tex)
}//); {
valArr[0] = BOOLEAN_TO_JSVAL(true);
JS::RootedObject jsobj(_cx, js_get_or_create_jsobject<Texture2D>(_cx, tex));
valArr[1] = OBJECT_TO_JSVAL(jsobj);
}
else
{
valArr[0] = BOOLEAN_TO_JSVAL(false);
valArr[1] = JSVAL_NULL;
}
JS::RootedValue callback(_cx, *_jsCallback);
if (!callback.isNull())
{
JS::RootedValue retval(_cx);
JS_CallFunctionValue(_cx, global, callback, JS::HandleValueArray::fromMarkedLocation(2, valArr), &retval);
}
release();
} }
// jsb.loadRemoteImg(url, function(succeed, result) {}) // jsb.loadRemoteImg(url, function(succeed, result) {})
@ -989,10 +974,8 @@ bool js_load_remote_image(JSContext *cx, uint32_t argc, jsval *vp)
std::string url; std::string url;
bool ok = jsval_to_std_string(cx, args.get(0), &url); bool ok = jsval_to_std_string(cx, args.get(0), &url);
JSB_PRECONDITION2(ok, cx, false, "js_load_remote_image : Error processing arguments"); JSB_PRECONDITION2(ok, cx, false, "js_load_remote_image : Error processing arguments");
JS::RootedObject callback(cx, args.get(1).toObjectOrNull()); JSDownloaderDelegator *delegate = JSDownloaderDelegator::create(cx, obj, url, args[1]);
delegate->download();
__JSDownloaderDelegator *delegate = __JSDownloaderDelegator::create(cx, obj, url, callback);
delegate->downloadAsync();
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;

View File

@ -26,32 +26,6 @@
#include "jsapi.h" #include "jsapi.h"
#include "jsfriendapi.h" #include "jsfriendapi.h"
#include "network/CCDownloader.h"
#include "renderer/CCTexture2D.h"
class __JSDownloaderDelegator : cocos2d::Ref
{
public:
void downloadAsync();
void download();
static __JSDownloaderDelegator *create(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleObject callback);
protected:
__JSDownloaderDelegator(JSContext *cx, JS::HandleObject obj, const std::string &url, JS::HandleObject callback);
~__JSDownloaderDelegator();
void startDownload();
private:
void onSuccess(cocos2d::Texture2D *tex);
void onError();
std::shared_ptr<cocos2d::network::Downloader> _downloader;
std::string _url;
JSContext *_cx;
JS::Heap<JSObject*> _jsCallback;
JS::Heap<JSObject*> _obj;
};
void register_all_cocos2dx_extension_manual(JSContext* cx, JS::HandleObject global); void register_all_cocos2dx_extension_manual(JSContext* cx, JS::HandleObject global);

View File

@ -116,9 +116,7 @@ JSAutoCompartment ac(cx, obj)
#define JSB_ENSURE_AUTOCOMPARTMENT(cx, obj) #define JSB_ENSURE_AUTOCOMPARTMENT(cx, obj)
#endif #endif
#define JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET \ #define JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
JSAutoCompartment __jsb_ac(ScriptingCore::getInstance()->getGlobalContext(), ScriptingCore::getInstance()->getGlobalObject());
/** @def JSB_INCLUDE_SYSTEM /** @def JSB_INCLUDE_SYSTEM
Whether or not it should include bindings for system components like LocalStorage Whether or not it should include bindings for system components like LocalStorage

View File

@ -141,12 +141,12 @@ void jsb_del_c_proxy_for_jsobject( JSObject *jsobj )
CCASSERT(proxy, "Invalid proxy for JSObject"); CCASSERT(proxy, "Invalid proxy for JSObject");
JS_SetPrivate(jsobj, NULL); JS_SetPrivate(jsobj, NULL);
free(proxy); delete(proxy);
} }
void jsb_set_c_proxy_for_jsobject( JSObject *jsobj, void *handle, unsigned long flags) void jsb_set_c_proxy_for_jsobject( JSObject *jsobj, void *handle, unsigned long flags)
{ {
struct jsb_c_proxy_s *proxy = (struct jsb_c_proxy_s*) malloc(sizeof(*proxy)); struct jsb_c_proxy_s *proxy = new (std::nothrow) (struct jsb_c_proxy_s);
CCASSERT(proxy, "No memory for proxy"); CCASSERT(proxy, "No memory for proxy");
proxy->handle = handle; proxy->handle = handle;

View File

@ -107,80 +107,23 @@ const char* JSStringWrapper::get()
// JSFunctionWrapper // JSFunctionWrapper
JSFunctionWrapper::JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval) JSFunctionWrapper::JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval)
: _cppOwner(nullptr) : _cx(cx)
, _cx(cx)
{ {
_jsthis = jsthis; _jsthis = new (std::nothrow) JS::PersistentRootedObject(cx, jsthis);
_fval = fval; _fval = new (std::nothrow) JS::PersistentRootedValue(cx, fval);
} }
JSFunctionWrapper::JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval, JS::HandleValue owner) JSFunctionWrapper::JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval, JS::HandleValue owner)
: _cppOwner(nullptr) : _cx(cx)
, _cx(cx)
{ {
_jsthis = jsthis; _jsthis = new (std::nothrow) JS::PersistentRootedObject(cx, jsthis);
_fval = fval; _fval = new (std::nothrow) JS::PersistentRootedValue(cx, fval);
setOwner(cx, JS::RootedValue(cx, owner));
} }
JSFunctionWrapper::~JSFunctionWrapper() JSFunctionWrapper::~JSFunctionWrapper()
{ {
ScriptingCore* sc = ScriptingCore::getInstance(); CC_SAFE_DELETE(_jsthis);
JSContext* cx = sc->getGlobalContext(); CC_SAFE_DELETE(_fval);
JSAutoCompartment(cx, sc->getGlobalObject());
JS::RootedValue ownerVal(_cx, _owner);
if (sc->getFinalizing() || ownerVal.isNullOrUndefined())
{
return;
}
if (_cppOwner != nullptr)
{
JS::RootedObject ownerObj(cx, ownerVal.toObjectOrNull());
js_proxy *t = jsb_get_js_proxy(ownerObj);
// JS object already released, no need to do the following release anymore, gc will take care of everything
if (t == nullptr || _cppOwner != t->ptr)
{
return;
}
}
JS::RootedValue thisVal(_cx, OBJECT_TO_JSVAL(_jsthis));
if (!thisVal.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, thisVal);
}
JS::RootedValue funcVal(_cx, _fval);
if (!funcVal.isNullOrUndefined())
{
js_remove_object_reference(ownerVal, funcVal);
}
}
void JSFunctionWrapper::setOwner(JSContext* cx, JS::HandleValue owner)
{
JSAutoCompartment(cx, ScriptingCore::getInstance()->getGlobalObject());
JS::RootedValue ownerVal(cx, owner);
if (!owner.isNullOrUndefined())
{
_owner = owner;
JS::RootedObject ownerObj(cx, owner.toObjectOrNull());
js_proxy *t = jsb_get_js_proxy(ownerObj);
if (t) {
_cppOwner = t->ptr;
}
JS::RootedValue thisVal(cx, OBJECT_TO_JSVAL(_jsthis));
if (!thisVal.isNullOrUndefined())
{
js_add_object_reference(ownerVal, thisVal);
}
JS::RootedValue funcVal(cx, _fval);
if (!funcVal.isNullOrUndefined())
{
js_add_object_reference(ownerVal, funcVal);
}
}
} }
bool JSFunctionWrapper::invoke(unsigned int argc, jsval *argv, JS::MutableHandleValue rval) bool JSFunctionWrapper::invoke(unsigned int argc, jsval *argv, JS::MutableHandleValue rval)
@ -190,11 +133,7 @@ bool JSFunctionWrapper::invoke(unsigned int argc, jsval *argv, JS::MutableHandle
bool JSFunctionWrapper::invoke(JS::HandleValueArray args, JS::MutableHandleValue rval) bool JSFunctionWrapper::invoke(JS::HandleValueArray args, JS::MutableHandleValue rval)
{ {
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET return JS_CallFunctionValue(_cx, *_jsthis, *_fval, args, rval);
JS::RootedObject thisObj(_cx, _jsthis);
JS::RootedValue fval(_cx, _fval);
return JS_CallFunctionValue(_cx, thisObj, fval, args, rval);
} }
static Color3B getColorFromJSObject(JSContext *cx, JS::HandleObject colorObject) static Color3B getColorFromJSObject(JSContext *cx, JS::HandleObject colorObject)

View File

@ -82,16 +82,13 @@ public:
JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval, JS::HandleValue owner); JSFunctionWrapper(JSContext* cx, JS::HandleObject jsthis, JS::HandleValue fval, JS::HandleValue owner);
~JSFunctionWrapper(); ~JSFunctionWrapper();
void setOwner(JSContext* cx, JS::HandleValue owner);
bool invoke(unsigned int argc, jsval *argv, JS::MutableHandleValue rval); bool invoke(unsigned int argc, jsval *argv, JS::MutableHandleValue rval);
bool invoke(JS::HandleValueArray args, JS::MutableHandleValue rval); bool invoke(JS::HandleValueArray args, JS::MutableHandleValue rval);
private: private:
JSContext *_cx; JSContext *_cx;
JS::Heap<JSObject*> _jsthis; JS::PersistentRootedObject* _jsthis;
JS::Heap<JS::Value> _fval; JS::PersistentRootedValue* _fval;
JS::Heap<JS::Value> _owner; private:
void* _cppOwner;
CC_DISALLOW_COPY_AND_ASSIGN(JSFunctionWrapper); CC_DISALLOW_COPY_AND_ASSIGN(JSFunctionWrapper);
}; };

View File

@ -202,10 +202,6 @@ bool js_EventListenerAcceleration_create(JSContext *cx, uint32_t argc, jsval *vp
auto ret = EventListenerAcceleration::create(arg0); auto ret = EventListenerAcceleration::create(arg0);
JS::RootedValue jsret(cx, OBJECT_TO_JSVAL(js_get_or_create_jsobject<EventListenerAcceleration>(cx, ret))); JS::RootedValue jsret(cx, OBJECT_TO_JSVAL(js_get_or_create_jsobject<EventListenerAcceleration>(cx, ret)));
if (wrapper)
{
wrapper->setOwner(cx, jsret);
}
args.rval().set(jsret); args.rval().set(jsret);
return true; return true;
} }
@ -275,10 +271,6 @@ bool js_EventListenerCustom_create(JSContext *cx, uint32_t argc, jsval *vp)
auto ret = EventListenerCustom::create(arg0, arg1); auto ret = EventListenerCustom::create(arg0, arg1);
JS::RootedValue jsret(cx, OBJECT_TO_JSVAL(js_get_or_create_jsobject<EventListenerCustom>(cx, ret))); JS::RootedValue jsret(cx, OBJECT_TO_JSVAL(js_get_or_create_jsobject<EventListenerCustom>(cx, ret)));
if (wrapper)
{
wrapper->setOwner(cx, jsret);
}
args.rval().set(jsret); args.rval().set(jsret);
return true; return true;
} }

View File

@ -1035,7 +1035,6 @@ void MinXmlHttpRequest::_notify(JS::HandleObject callback, JS::HandleValueArray
if (callback) if (callback)
{ {
JS::RootedObject obj(_cx, p->obj); JS::RootedObject obj(_cx, p->obj);
JSAutoCompartment ac(_cx, obj);
//JS_IsExceptionPending(cx) && JS_ReportPendingException(cx); //JS_IsExceptionPending(cx) && JS_ReportPendingException(cx);
JS::RootedValue callbackVal(_cx, OBJECT_TO_JSVAL(callback)); JS::RootedValue callbackVal(_cx, OBJECT_TO_JSVAL(callback));
JS::RootedValue out(_cx); JS::RootedValue out(_cx);

View File

@ -2329,6 +2329,11 @@ var Issue1305 = ActionsDemo.extend({
}, },
onExit:function () { onExit:function () {
this._super(); this._super();
if (this._spriteTmp)
{
this._spriteTmp.release();
this._spriteTmp = null;
}
}, },
onLog:function (pSender) { onLog:function (pSender) {
cc.log("This message SHALL ONLY appear when the sprite is added to the scene, NOT BEFORE"); cc.log("This message SHALL ONLY appear when the sprite is added to the scene, NOT BEFORE");
@ -2336,8 +2341,12 @@ var Issue1305 = ActionsDemo.extend({
onAddSprite:function (dt) { onAddSprite:function (dt) {
this._spriteTmp.x = 250; this._spriteTmp.x = 250;
this._spriteTmp.y = 250; this._spriteTmp.y = 250;
this.addChild(this._spriteTmp); if (this._spriteTmp)
this._spriteTmp.release(); {
this.addChild(this._spriteTmp);
this._spriteTmp.release();
this._spriteTmp = null;
}
}, },
title:function () { title:function () {
return "Issue 1305"; return "Issue 1305";