more js fixes

fixes in how ref count is measured
opengl bindings converted to new API
This commit is contained in:
Ricardo Quesada 2015-12-11 15:18:09 -08:00
parent 7e72a7110c
commit 47911e0c24
8 changed files with 78 additions and 104 deletions

View File

@ -50,6 +50,7 @@ Ref::Ref()
, _scriptObject(nullptr) , _scriptObject(nullptr)
, _rooted(false) , _rooted(false)
, _scriptOwned(false) , _scriptOwned(false)
,_referenceCountAtRootTime(0)
#endif #endif
{ {
#if CC_ENABLE_SCRIPT_BINDING #if CC_ENABLE_SCRIPT_BINDING
@ -93,11 +94,15 @@ void Ref::retain()
++_referenceCount; ++_referenceCount;
#if CC_ENABLE_SCRIPT_BINDING && CC_ENABLE_GC_FOR_NATIVE_OBJECTS #if CC_ENABLE_SCRIPT_BINDING && CC_ENABLE_GC_FOR_NATIVE_OBJECTS
if (!_rooted && _scriptOwned) if (_scriptOwned && !_rooted)
{ {
auto scriptMgr = ScriptEngineManager::getInstance()->getScriptEngine(); auto scriptMgr = ScriptEngineManager::getInstance()->getScriptEngine();
if (scriptMgr && scriptMgr->getScriptType() == kScriptTypeJavascript) if (scriptMgr && scriptMgr->getScriptType() == kScriptTypeJavascript)
{ {
_referenceCountAtRootTime = _referenceCount-1;
CCLOG("retain + root: %p (%s) rc=%d rcrt=%d", this, typeid(*this).name(), _referenceCount, _referenceCountAtRootTime);
scriptMgr->rootObject(this); scriptMgr->rootObject(this);
_rooted = true; _rooted = true;
} }
@ -111,7 +116,7 @@ void Ref::release()
--_referenceCount; --_referenceCount;
#if CC_ENABLE_SCRIPT_BINDING && CC_ENABLE_GC_FOR_NATIVE_OBJECTS #if CC_ENABLE_SCRIPT_BINDING && CC_ENABLE_GC_FOR_NATIVE_OBJECTS
if (_scriptOwned && _referenceCount==1 && _rooted) if (_scriptOwned && _rooted && _referenceCount==_referenceCountAtRootTime)
{ {
auto scriptMgr = ScriptEngineManager::getInstance()->getScriptEngine(); auto scriptMgr = ScriptEngineManager::getInstance()->getScriptEngine();
if (scriptMgr && scriptMgr->getScriptType() == kScriptTypeJavascript) if (scriptMgr && scriptMgr->getScriptType() == kScriptTypeJavascript)

View File

@ -161,6 +161,7 @@ public:
When true, it means that the object was already rooted. When true, it means that the object was already rooted.
*/ */
bool _rooted; bool _rooted;
unsigned int _referenceCountAtRootTime;
/** /**
* The life of the object is scrolled by the scripting engine. * The life of the object is scrolled by the scripting engine.

View File

@ -1563,14 +1563,12 @@ void ScriptingCore::rootObject(Ref* ref)
nproxy = jsb_get_native_proxy(ptr); nproxy = jsb_get_native_proxy(ptr);
if (nproxy) { if (nproxy) {
JSContext *cx = getGlobalContext(); JSContext *cx = getGlobalContext();
// FIXME: Creating a RootedObject here is not needed. jsproxy = jsb_get_js_proxy(nproxy->obj);
// it is being created only because jsb_get_js_proxy() requires one JS::AddNamedObjectRoot(cx, &jsproxy->obj, typeid(*ref).name());
// but only the raw pointer is used in jsb_get_js_proxy() }
JS::RootedObject handle(cx, nproxy->obj.get()); else
jsproxy = jsb_get_js_proxy(handle); {
AddObjectRoot(cx, &jsproxy->obj); CCLOG("BUG in rootObject");
CCLOG("Rooting %p - %p: %s", ref, &jsproxy->obj, typeid(*ref).name());
} }
} }
@ -1583,14 +1581,12 @@ void ScriptingCore::unrootObject(Ref* ref)
nproxy = jsb_get_native_proxy(ptr); nproxy = jsb_get_native_proxy(ptr);
if (nproxy) { if (nproxy) {
JSContext *cx = getGlobalContext(); JSContext *cx = getGlobalContext();
// FIXME: Creating a RootedObject here is not needed. jsproxy = jsb_get_js_proxy(nproxy->obj);
// it is being created only because jsb_get_js_proxy() requires one JS::RemoveObjectRoot(cx, &jsproxy->obj);
// but only the raw pointer is used in jsb_get_js_proxy() }
JS::RootedObject handle(cx, nproxy->obj.get()); else
jsproxy = jsb_get_js_proxy(handle); {
RemoveObjectRoot(cx, &jsproxy->obj); CCLOG("BUG in unrootObject");
CCLOG("Unrooting #2 %p - %p: %s", ref, &jsproxy->obj, typeid(*ref).name());
} }
} }
@ -1949,11 +1945,10 @@ js_proxy_t* jsb_get_native_proxy(void* nativeObj)
return p; return p;
} }
js_proxy_t* jsb_get_js_proxy(JS::HandleObject jsObj) js_proxy_t* jsb_get_js_proxy(JSObject* jsObj)
{ {
js_proxy_t* p = nullptr; js_proxy_t* p = nullptr;
JSObject* ptr = jsObj.get(); JS_GET_NATIVE_PROXY(p, jsObj);
JS_GET_NATIVE_PROXY(p, ptr);
return p; return p;
} }
@ -2059,8 +2054,6 @@ void jsb_ref_finalize(JSFreeOp* fop, JSObject* obj)
js_proxy_t* nproxy; js_proxy_t* nproxy;
js_proxy_t* jsproxy; js_proxy_t* jsproxy;
CCLOG("jsb_ref_finalize #1: JSObject address = %p", obj);
JS::RootedObject jsobj(fop->runtime(), obj); JS::RootedObject jsobj(fop->runtime(), obj);
jsproxy = jsb_get_js_proxy(jsobj); jsproxy = jsb_get_js_proxy(jsobj);
if (jsproxy) if (jsproxy)
@ -2070,8 +2063,6 @@ void jsb_ref_finalize(JSFreeOp* fop, JSObject* obj)
if (ref) if (ref)
{ {
CCLOG("jsb_ref_finalize #2: JSObject address = %p (%s)", obj, typeid(*ref).name());
jsb_remove_proxy(nproxy, jsproxy); jsb_remove_proxy(nproxy, jsproxy);
ref->release(); ref->release();
} }

View File

@ -549,7 +549,7 @@ js_type_class_t *jsb_register_class(JSContext *cx, JSClass *jsClass, JS::HandleO
js_proxy_t* jsb_new_proxy(void* nativeObj, JS::HandleObject jsObj); js_proxy_t* jsb_new_proxy(void* nativeObj, JS::HandleObject jsObj);
js_proxy_t* jsb_get_native_proxy(void* nativeObj); js_proxy_t* jsb_get_native_proxy(void* nativeObj);
js_proxy_t* jsb_get_js_proxy(JS::HandleObject jsObj); js_proxy_t* jsb_get_js_proxy(JSObject* jsObj);
void jsb_remove_proxy(js_proxy_t* nativeProxy, js_proxy_t* jsProxy); void jsb_remove_proxy(js_proxy_t* nativeProxy, js_proxy_t* jsProxy);
/** /**

View File

@ -5142,25 +5142,10 @@ bool js_cocos2dx_EventKeyboard_constructor(JSContext *cx, uint32_t argc, jsval *
JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_EventKeyboard_constructor : Error processing arguments"); JSB_PRECONDITION2(ok, cx, false, "js_cocos2dx_EventKeyboard_constructor : Error processing arguments");
cocos2d::EventKeyboard* cobj = new (std::nothrow) cocos2d::EventKeyboard(arg0, arg1); cocos2d::EventKeyboard* cobj = new (std::nothrow) cocos2d::EventKeyboard(arg0, arg1);
cocos2d::Ref *_ccobj = dynamic_cast<cocos2d::Ref *>(cobj); js_type_class_t *typeClass = js_get_type_from_native<cocos2d::EventKeyboard>(cobj);
if (_ccobj) { auto jsobj = jsb_ref_create_jsobject(cx, cobj, typeClass, "cocos2d::EventKeyboard");
_ccobj->autorelease();
} args.rval().set(OBJECT_TO_JSVAL(jsobj));
TypeTest<cocos2d::EventKeyboard> t;
js_type_class_t *typeClass = nullptr;
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
JS::RootedObject proto(cx, typeClass->proto.ref());
JS::RootedObject parentProto(cx, typeClass->parentProto.ref());
JS::RootedObject obj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parentProto));
JS::RootedValue objVal(cx, OBJECT_TO_JSVAL(obj));
args.rval().set(objVal);
// link the native object with the javascript object
js_proxy_t* p = jsb_new_proxy(cobj, obj);
JS::AddNamedObjectRoot(cx, &p->obj, "cocos2d::EventKeyboard");
return true; return true;
} }

View File

@ -32,31 +32,31 @@ void GLNode::draw(Renderer *renderer, const Mat4& transform, uint32_t flags) {
void GLNode::onDraw(Mat4 &transform, uint32_t flags) void GLNode::onDraw(Mat4 &transform, uint32_t flags)
{ {
js_proxy_t* proxy = NULL;
JSContext *cx = ScriptingCore::getInstance()->getGlobalContext(); JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();
proxy = js_get_or_create_proxy<cocos2d::Node>(cx, this);
if( proxy ) { js_type_class_t *typeClass = js_get_type_from_native<cocos2d::GLNode>(this);
// JSObject *jsObj = proxy->obj; auto j = jsb_ref_get_or_create_jsobject(cx, this, typeClass, "cocos2d::GLNode");
JS::RootedObject jsObj(cx, proxy->obj.get());
if (jsObj) {
bool found = false;
JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
JS_HasProperty(cx, jsObj, "draw", &found); if (j)
if (found == true) { {
auto director = Director::getInstance(); JS::RootedObject jsObj(cx, j);
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
JS::RootedValue rval(cx); bool found = false;
JS::RootedValue fval(cx); JSB_AUTOCOMPARTMENT_WITH_GLOBAL_OBJCET
JS_GetProperty(cx, jsObj, "draw", &fval);
JS_CallFunctionValue(cx, jsObj, fval, JS::HandleValueArray::empty(), &rval); JS_HasProperty(cx, jsObj, "draw", &found);
if (found) {
auto director = Director::getInstance();
director->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
director->loadMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW, transform);
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); JS::RootedValue rval(cx);
} JS::RootedValue fval(cx);
JS_GetProperty(cx, jsObj, "draw", &fval);
JS_CallFunctionValue(cx, jsObj, fval, JS::HandleValueArray::empty(), &rval);
director->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
} }
} }
} }
@ -68,32 +68,18 @@ JSObject *js_cocos2dx_GLNode_prototype;
bool js_cocos2dx_GLNode_constructor(JSContext *cx, uint32_t argc, jsval *vp) bool js_cocos2dx_GLNode_constructor(JSContext *cx, uint32_t argc, jsval *vp)
{ {
if (argc == 0) { if (argc == 0) {
cocos2d::GLNode* cobj = new cocos2d::GLNode(); cocos2d::GLNode* cobj = new (std::nothrow) cocos2d::GLNode;
cocos2d::Ref *_ccobj = dynamic_cast<cocos2d::Ref *>(cobj);
if (_ccobj) {
_ccobj->autorelease();
}
TypeTest<cocos2d::GLNode> t; js_type_class_t *typeClass = js_get_type_from_native<cocos2d::GLNode>(cobj);
js_type_class_t *typeClass = nullptr; JS::RootedObject jsobj(cx, jsb_ref_create_jsobject(cx, cobj, typeClass, "cocos2d::GLNode"));
std::string typeName = t.s_name();
auto typeMapIter = _js_global_type_map.find(typeName);
CCASSERT(typeMapIter != _js_global_type_map.end(), "Can't find the class type!");
typeClass = typeMapIter->second;
CCASSERT(typeClass, "The value is null.");
JS::RootedObject proto(cx, typeClass->proto.ref());
JS::RootedObject parentProto(cx, typeClass->parentProto.ref());
JS::RootedObject obj(cx, JS_NewObject(cx, typeClass->jsclass, proto, parentProto));
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
args.rval().set(OBJECT_TO_JSVAL(obj)); args.rval().set(OBJECT_TO_JSVAL(jsobj));
// link the native object with the javascript object
js_proxy_t *p = jsb_new_proxy(cobj, obj);
JS::AddNamedObjectRoot(cx, &p->obj, "cocos2d::GLNode"); bool ok=false;
if (JS_HasProperty(cx, jsobj, "_ctor", &ok) && ok)
ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(jsobj), "_ctor", args);
return true; return true;
} }
@ -101,17 +87,16 @@ bool js_cocos2dx_GLNode_constructor(JSContext *cx, uint32_t argc, jsval *vp)
return false; return false;
} }
void js_cocos2dx_GLNode_finalize(JSFreeOp *fop, JSObject *obj) {
}
static bool js_cocos2dx_GLNode_ctor(JSContext *cx, uint32_t argc, jsval *vp) static bool js_cocos2dx_GLNode_ctor(JSContext *cx, uint32_t argc, jsval *vp)
{ {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
JS::RootedObject obj(cx, args.thisv().toObjectOrNull()); JS::RootedObject obj(cx, args.thisv().toObjectOrNull());
cocos2d::GLNode *nobj = new cocos2d::GLNode(); cocos2d::GLNode *nobj = new (std::nothrow) cocos2d::GLNode;
js_proxy_t* p = jsb_new_proxy(nobj, obj); auto newproxy = jsb_new_proxy(nobj, obj);
nobj->autorelease(); jsb_ref_init(cx, &newproxy->obj, nobj, "cocos2d::GLNode");
JS::AddNamedObjectRoot(cx, &p->obj, "GLNode"); bool isFound = false;
if (JS_HasProperty(cx, obj, "_ctor", &isFound) && isFound)
ScriptingCore::getInstance()->executeFunctionWithOwner(OBJECT_TO_JSVAL(obj), "_ctor", args);
args.rval().setUndefined(); args.rval().setUndefined();
return true; return true;
} }
@ -119,16 +104,16 @@ static bool js_cocos2dx_GLNode_ctor(JSContext *cx, uint32_t argc, jsval *vp)
bool js_cocos2dx_GLNode_create(JSContext *cx, uint32_t argc, jsval *vp) bool js_cocos2dx_GLNode_create(JSContext *cx, uint32_t argc, jsval *vp)
{ {
JS::CallArgs args = JS::CallArgsFromVp(argc, vp); JS::CallArgs args = JS::CallArgsFromVp(argc, vp);
cocos2d::GLNode* ret = new cocos2d::GLNode(); cocos2d::GLNode* ret = new (std::nothrow) cocos2d::GLNode;
jsval jsret; jsval jsret = JSVAL_NULL;
do {
if (ret) { if (ret) {
js_proxy_t *proxy = js_get_or_create_proxy<cocos2d::GLNode>(cx, ret); js_type_class_t *typeClass = js_get_type_from_native<cocos2d::GLNode>(ret);
jsret = OBJECT_TO_JSVAL(proxy->obj);
} else { auto jsobj = jsb_ref_create_jsobject(cx, ret, typeClass, "cocos2d::GLNode");
jsret = JSVAL_NULL; jsret = OBJECT_TO_JSVAL(jsobj);
} }
} while (0);
args.rval().set(jsret); args.rval().set(jsret);
return true; return true;
} }
@ -145,7 +130,7 @@ void js_register_cocos2dx_GLNode(JSContext *cx, JS::HandleObject global) {
js_cocos2dx_GLNode_class->enumerate = JS_EnumerateStub; js_cocos2dx_GLNode_class->enumerate = JS_EnumerateStub;
js_cocos2dx_GLNode_class->resolve = JS_ResolveStub; js_cocos2dx_GLNode_class->resolve = JS_ResolveStub;
js_cocos2dx_GLNode_class->convert = JS_ConvertStub; js_cocos2dx_GLNode_class->convert = JS_ConvertStub;
js_cocos2dx_GLNode_class->finalize = js_cocos2dx_GLNode_finalize; js_cocos2dx_GLNode_class->finalize = jsb_ref_finalize;
js_cocos2dx_GLNode_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2); js_cocos2dx_GLNode_class->flags = JSCLASS_HAS_RESERVED_SLOTS(2);
static JSPropertySpec properties[] = { static JSPropertySpec properties[] = {

View File

@ -119,7 +119,7 @@ bool jsval_to_ray(JSContext *cx, JS::HandleValue vp, cocos2d::Ray* ret);
bool jsval_to_resourcedata(JSContext *cx, JS::HandleValue v, cocos2d::ResourceData* ret); bool jsval_to_resourcedata(JSContext *cx, JS::HandleValue v, cocos2d::ResourceData* ret);
// forward declaration // forward declaration
CC_JS_DLL js_proxy_t* jsb_get_js_proxy(JS::HandleObject jsObj); CC_JS_DLL js_proxy_t* jsb_get_js_proxy(JSObject* jsObj);
template <class T> template <class T>
bool jsvals_variadic_to_ccvector( JSContext *cx, /*jsval *vp, int argc,*/const JS::CallArgs& args, cocos2d::Vector<T>* ret) bool jsvals_variadic_to_ccvector( JSContext *cx, /*jsval *vp, int argc,*/const JS::CallArgs& args, cocos2d::Vector<T>* ret)

View File

@ -70,6 +70,7 @@ var SetPropertyMemoryModelTest = MemoryModelTestBase.extend({
_subtitle:"See console for possible errors", _subtitle:"See console for possible errors",
ctor:function () { ctor:function () {
cc.sys.garbageCollect();
this._super(); this._super();
var sprite = new cc.Sprite(s_grossini_dance_atlas, cc.rect(0, 0, 85, 121)); var sprite = new cc.Sprite(s_grossini_dance_atlas, cc.rect(0, 0, 85, 121));
var tag = 10; var tag = 10;
@ -157,6 +158,12 @@ var LocalVarMemoryModelTest = MemoryModelTestBase.extend({
var sprite2 = new cc.Sprite(s_grossini_dance_atlas, cc.rect(0, 0, 85, 121)); var sprite2 = new cc.Sprite(s_grossini_dance_atlas, cc.rect(0, 0, 85, 121));
var sprite3 = new cc.Sprite(s_grossini_dance_atlas, cc.rect(0, 0, 85, 121)); var sprite3 = new cc.Sprite(s_grossini_dance_atlas, cc.rect(0, 0, 85, 121));
var a = 10; var a = 10;
this.addChild(sprite1);
this.removeChild(sprite1);
// this.addChild(sprite2);
// this.removeChild(sprite2);
this.addChild(sprite3);
this.removeChild(sprite3);
//cc.sys.dumpRoot(); //cc.sys.dumpRoot();
cc.sys.garbageCollect(); cc.sys.garbageCollect();
cc.log(sprite1); cc.log(sprite1);