android specific Spidermonkey NoGCScope crash

Hi,

I’ve run into a crash that I don’t really understand, and am hoping for help sorting out. I suspect that this may be some form of threading problem, but I’m not sure. Any help or angles of investigation will be appreciated!

The setup:

I’m trying to complete facebook login. I’ve got it working correctly in Java, but when I try to pass the string back up to JS I get a crash with the below stack:

#00  pc 001ca13a  /data/data/com.redhotlabs.bingo/lib/libgame.so (JS::InNoGCScope()+17)
#01  pc 002ef919  /data/data/com.redhotlabs.bingo/lib/libgame.so
#02  pc 001d27af  /data/data/com.redhotlabs.bingo/lib/libgame.so (JS_NewStringCopyZ+62)
#03  pc 00151449  /data/data/com.redhotlabs.bingo/lib/libgame.so (JSStringCallback::callbackFunc(char const*)+64)
#04  pc 00142fb7  /data/data/com.redhotlabs.bingo/lib/libgame.so (Java_com_redhotlabs_bingo_FacebookManager_currentFacebookUserChanged+46)
#05  pc 0001f3b0  /system/lib/libdvm.so (dvmPlatformInvoke+112)
#06  pc 0004eb6f  /system/lib/libdvm.so (dvmCallJNIMethod(unsigned int const*, JValue*, Method const*, Thread*)+394)
#07  pc 00050c8b  /system/lib/libdvm.so (dvmResolveNativeMethod(unsigned int const*, JValue*, Method const*, Thread*)+174)
#08  pc 000288a4  /system/lib/libdvm.so

the Java code (all of this seems to work fine, and the json encoded string being passed to c*+ is correct:
<pre>
public native void currentFacebookUserChanged;
/* Displays the facebook login dialog./
public void showLoginDialog {
// start Facebook Login
Session.openActiveSession;
}
private class SessionStatusCallback implements Session.StatusCallback {
Override public void call(Session session, SessionState state, Exception exception) { if (session.isOpened()) { // make request to the /me API Request.executeMeRequestAsync(session, new Request.GraphUserCallback() { // callback after Graph API response with user objectOverride
public void onCompleted {
if {
String data = user.getInnerJSONObject.toString;
FacebookManager.getInstance.currentFacebookUserChanged;
}
}
}
}
}
}
</pre>
my c*+ code:

//JSStringCallback extends JSCallbackWrapper, and is retained when passed down to the c++ code
static JSStringCallback* s_userChangedListener;

extern "C"
{
    void Java__FacebookManager_currentFacebookUserChanged(JNIEnv* env, jobject thiz, jstring data) {
        if(s_userChangedListener) {
            const char* nativeData = (env)->GetStringUTFChars( data, 0);
            s_userChangedListener->callbackFunc(nativeData);
        }
    }
}

the JSStringCallback’s callFunc code:

void JSStringCallback::callbackFunc(const char* arg) {

    JSObject* thisObj = JSVAL_IS_VOID(jsThisObj) ? NULL : JSVAL_TO_OBJECT(jsThisObj);
    JSContext *cx = ScriptingCore::getInstance()->getGlobalContext();

    jsval retval;
    if(jsCallback != JSVAL_VOID) {
        CCLog(arg); //This properly prints out the json string of the FB user data
        JSString *str = JS_NewStringCopyZ(cx, arg); //This line throws the error
        jsval senderVal = STRING_TO_JSVAL(str);
        JS_AddValueRoot(cx, &senderVal);
        JS_CallFunctionValue(cx, thisObj, jsCallback, 1, &senderVal, &retval);
        JS_RemoveValueRoot(cx, &senderVal);

//        JS_CallFunctionValue(cx, thisObj, jsCallback, 0, NULL, &retval); //This line will also throw the error if the above lines are commented out

    }
}

I’ve tried putting the c++ call into the UI thread in java using an Async task, but that doesn’t seem to have changed anything.

Thanks for any help you can give,
Mark Henderson

Plz make sure that JSStringCallback::callbackFunc is in GL thread since cocos2d-x is in GL thread.

James Chen wrote:

Plz make sure that JSStringCallback::callbackFunc is in GL thread since cocos2d-x is in GL thread.

I ran into the same case as well, could you please give some tips on how to interact cocos2d-x in another thread?

James Chen wrote:

Plz make sure that JSStringCallback::callbackFunc is in GL thread since cocos2d-x is in GL thread.

This was the problem:)
I changed my JSStringCallback function to work as below, and it seems to have solved my issue:
<pre>
void JSStringCallback::callbackFunc {
this
>m_arg = arg;
CCDirector::sharedDirector()->getScheduler()>scheduleSelector, this, 0, false);
}
void JSStringCallback::scheduledCallback {
const char * arg = this
>m_arg;
JSObject* thisObj = JSVAL_IS_VOID(jsThisObj) ? NULL : JSVAL_TO_OBJECT(jsThisObj);
JSContext cx = ScriptingCore::getInstance->getGlobalContext;
jsval retval;
if {
CCLog;
// JSString
str1 = JS_NewStringCopyZ(cx, “test”);
CCLog(arg);
JSString *str = JS_NewStringCopyZ(cx, arg);
jsval senderVal = STRING_TO_JSVAL(str);
JS_AddValueRoot(cx, &senderVal);
JS_CallFunctionValue(cx, thisObj, jsCallback, 1, &senderVal, &retval);
JS_CallFunctionValue(cx, thisObj, jsCallback, 0, NULL, &retval);
JS_RemoveValueRoot(cx, &senderVal);

}
}