2014-09-10 3 views
0

그래서 처음으로 약간의 배경 :C++/JNI - 벡터 및 배열, C++ 또는 JNI에서 Stored Object (jobject) 변경이 예상치 않게 발생합니까?

저는 자바 용 C++ 라이브러리, 특히 Squirrel 스크립팅 언어를 래핑하는 작업을 해왔습니다. Squirrel Virtual Machine에 네이티브 함수를 전달해야 할 때 문제가 발생합니다. 다람쥐는 SQFUNCTION 함수가 HSQUIRRELVM을 매개 변수로 가지며 SQInteger를 반환하는 함수로 정의되어야합니다. 그러나 자바에서 이것을 감싸는 것을 명심하십시오. 나는 C++이 jobject에서 Java 메소드를 호출하도록 만들 수 있지만, 실제로 다람쥐에게 넘겨주기 위해 람다 함수에서 그 호출을 감쌀 필요가 있었다. 일반적으로 나는 람다 캡쳐로 [=]를 써서 내 변수를 참조 할 수 있지만, 어떤 이유로 변수를 캡쳐하면 람다 함수의 유형이 변경되고 더 이상 SQFUNCTION으로 인식되지 않습니다. 이 문제를 해결하기로 결정한 가장 최근의 방법은 람다가 액세스 할 수 있도록 상수 벡터 또는 배열 중 하나입니다. 나는 다람쥐에게 벡터/배열이 객체가 어디에 저장되어 있는지 알려주고 람다가 다람쥐로부터 그 값을 가져 와서 접근하도록합니다. 문제는 다음과 같습니다. 올바른 슬롯에 객체가 있지만, 거기에 놓은 객체가 아닙니다.

문제는 내가 C++이나 JNI에 익숙하지 않은 경험이 있으며, 내가 찾은 어떤 것도 이것이 어떤 종류의 문제인지를 말해 주었다. 나는 객체와 객체에 대한 포인터를 저장하려고 시도했지만, 두 메소드 모두 동일한 결과를 얻는다. 내가 JSqTestFunc의 인스턴스를 저장하고 있지만 코드가 JSqVM의 인스턴스를 검색하고 있습니다. 이 두 클래스가 다람쥐와 상호 작용하는 것 외에 다른 공통점은 Object를 확장한다는 것입니다. 그렇지 않으면 완전히 관련이 없습니다.

내 질문은 여러 부분에 있어야 같아요

  1. 이것은 C++ 문제 또는 JNI 문제인가?
  2. 어떻게 해결할 수 있습니까?

나는 그것이 JNI 문제가되어야하는 것처럼 느껴진다. 그러나 나에게는 나도 바보가되는 C++을 배제 할 수 없다. 나는 JNI가 jobject 클래스와 그것에 대한 참조를 다루는 방법에 익숙하지 않다. 그래서 아마도 jobject는 다른 클래스의 데이터를 내부적으로 저장하게 될 것이다. C++ 배열/벡터 저장 영역에서 이와 관련된 문제 나 어떤 문제도 발견하지 못했습니다.

는 C++ 기능은 다음과 같습니다

static const int m_maxClosures = 8; 
static int m_closures = 0; 

static JNIEnv *m_envs[m_maxClosures]; 
static jobject m_objs[m_maxClosures]; 

JNIEXPORT void JNICALL Java_com_yourlocalfax_jsquirrel_Squirrel_sq_1newclosure_1native(JNIEnv *env, jclass c, jlong vmhandle, jobject func, jlong nfreevars) { 
    HSQUIRRELVM v = fromPointerHandleToObject<HSQUIRRELVM>(vmhandle); 

    int idx = m_closures; 

    printf("Creating number %d closure of %d", idx, m_maxClosures); 

    m_closures++; 

    m_envs[idx] = env; 
    m_objs[idx] = func; 

    sq_pushinteger(v, idx); 

    JNIEnv *e = m_envs[idx]; 
    jobject o = m_objs[idx]; 

    jobject clsObj = e->CallObjectMethod(o, e->GetMethodID(e->GetObjectClass(o), "getClass", "()Ljava/lang/Class;")); 
    jstring strObj = (jstring)e->CallObjectMethod(clsObj, e->GetMethodID(e->GetObjectClass(clsObj), "getName", "()Ljava/lang/String;")); 

    const char* str = e->GetStringUTFChars(strObj, NULL); 
    printf("\nInitial calling class is: %s\n", str); 
    e->ReleaseStringUTFChars(strObj, str); 

    SQFUNCTION f = [](HSQUIRRELVM v) { 
     print_args(v); 
     squirrel_stack_trace(v); 

     SQInteger i; 

     sq_pushinteger(v, 0); // Push the index in the table TO GET 
     sq_get(v, 1); // Push the index of the actual table 
     sq_getinteger(v, -1, &i); // Get the newly pushed value (integer) 
     //sq_getinteger(v, 2, &i); 
     printf("Location Id is %d of %d", i, m_maxClosures); 

     JNIEnv *e = m_envs[i]; 
     jobject o = m_objs[i]; 

     jobject clsObj = e->CallObjectMethod(o, e->GetMethodID(e->GetObjectClass(o), "getClass", "()Ljava/lang/Class;")); 
     jstring strObj = (jstring)e->CallObjectMethod(clsObj, e->GetMethodID(e->GetObjectClass(clsObj), "getName", "()Ljava/lang/String;")); 

     const char* str = e->GetStringUTFChars(strObj, NULL); 
     printf("\nCalling class is: %s\n", str); 
     e->ReleaseStringUTFChars(strObj, str); 

     jclass cls = e->GetObjectClass(o); 
     jmethodID m = e->GetMethodID(cls, "function", "(Lcom/yourlocalfax/jsquirrel/JSqVM;)I"); 
     //sq_pushinteger(v, e->CallIntMethod(o, m)); 
     return (SQInteger)0; 
    }; 

    sq_newclosure(v, f, nfreevars + 1); 
} 

나는 fromPointerHandleToObject 아직 저를 실패하지 않았 음을 언급해야한다, 나는 다른 모든 함수 호출에서 사용하고있는 모든 시간을 작동합니다. 여전히 코드를보고 싶다면 게시 할 수 있습니다.

그리고 출력은 이것이다 : 당신이 볼 수 있듯이 검색 할 때

Creating number 0 closure of 8 
Initial calling class is: com.yourlocalfax.jsquirrel.test.JSqTestFunc 
Location Id is 0 of 8 
Calling class is: com.yourlocalfax.jsquirrel.JSqVM 

이 때, jobject 배열의 인덱스 0은 처음 JSqTestFunc하지만 JSqVM 저장합니다.

아무리 도움이된다해도 다른 방법을 사용해도이 문제를 해결하기에는 너무 오랜 시간이 걸리므로 많은 도움을 받으실 수 있습니다. 감사!

답변

2

나는이 게시물을 게시 한 후 훨씬 더 심도있게 조사했으며 실제로 로컬 및 글로벌 참조와 관련하여 JNI 측에서 문제가 있음을 알게되었습니다. 내가해야 할 일은 env->NewGlobalRef(object);이고 배열에 개체를 저장합니다. 그것으로 해결되었습니다.

나는 미래에 누구에게 도움이 될지를 대비하여이 질문을 남겨두고 답변 할 예정입니다.