pjs/js/jsd/java/jsd_jntv.c

2695 строки
79 KiB
C

/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* The contents of this file are subject to the Netscape Public License
* Version 1.0 (the "NPL"); you may not use this file except in
* compliance with the NPL. You may obtain a copy of the NPL at
* http://www.mozilla.org/NPL/
*
* Software distributed under the NPL is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
* for the specific language governing rights and limitations under the
* NPL.
*
* The Initial Developer of this code under the NPL is Netscape
* Communications Corporation. Portions created by Netscape are
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
* Reserved.
*/
/*
* JNI natives to reflect JSD into Java
*/
#include "jsdj.h"
/* this can be included for type checking, but otherwise is not needed */
/* #include "_jni/jsdjnih.h" */
/***************************************************************************/
#define ASSERT_RETURN_VOID(x) \
JS_BEGIN_MACRO \
if(!(x)) \
{ \
JS_ASSERT(0); \
return; \
} \
JS_END_MACRO
#define ASSERT_RETURN_VALUE(x,v)\
JS_BEGIN_MACRO \
if(!(x)) \
{ \
JS_ASSERT(0); \
return v; \
} \
JS_END_MACRO
#define CHECK_RETURN_VOID(x) \
JS_BEGIN_MACRO \
if(!(x)) \
{ \
return; \
} \
JS_END_MACRO
#define CHECK_RETURN_VALUE(x,v) \
JS_BEGIN_MACRO \
if(!(x)) \
{ \
return v; \
} \
JS_END_MACRO
#define ASSERT_GOTO(x,w) \
JS_BEGIN_MACRO \
if(!(x)) \
{ \
JS_ASSERT(0); \
goto w; \
} \
JS_END_MACRO
#define CHECK_GOTO(x,w) \
JS_BEGIN_MACRO \
if(!(x)) \
{ \
goto w; \
} \
JS_END_MACRO
#ifdef DEBUG
#define ASSERT_CLEAR_EXCEPTION(e) \
JS_BEGIN_MACRO \
if((*e)->ExceptionOccurred(e)) \
{ \
(*e)->ExceptionDescribe(e); \
JS_ASSERT(0); \
} \
(*e)->ExceptionClear(e); \
JS_END_MACRO
#else /* ! DEBUG */
#define ASSERT_CLEAR_EXCEPTION(e) (*e)->ExceptionClear(e)
#endif /* DEBUG */
#define CHECK_CLEAR_EXCEPTION(e) (*e)->ExceptionClear(e)
/***************************************************************************/
#ifdef DEBUG
void JSDJ_ASSERT_VALID_CONTEXT(JSDJContext* jsdjc)
{
JS_ASSERT(jsdjc);
}
#endif /* DEBUG */
static JSHashNumber
_hash_root(const void *key)
{
return ((JSHashNumber) key) >> 2; /* help lame MSVC1.5 on Win16 */
}
static JSBool g_singleContextMode = JS_FALSE;
static JSHashTable* g_contextTable = NULL;
static void* g_lock = NULL;
static int g_contextCount = 0;
static JSDJContext* g_newestContext = NULL;
#define LOCK() \
JS_BEGIN_MACRO \
if(!g_singleContextMode) { \
if(!g_lock) \
g_lock = JSD_CreateLock(); \
JS_ASSERT(g_lock); \
JSD_Lock(g_lock); \
} \
JS_END_MACRO
#define UNLOCK() \
JS_BEGIN_MACRO \
if(!g_singleContextMode) { \
JS_ASSERT(g_lock); \
JSD_Unlock(g_lock); \
} \
JS_END_MACRO
/***************************************************************************/
JSDJContext*
jsdj_SimpleInitForSingleContextMode(JSDContext* jsdc,
JSDJ_GetJNIEnvProc getEnvProc, void* user)
{
JSDJContext* jsdjc;
if(!jsdj_SetSingleContextMode())
return NULL;
if(!(jsdjc = jsdj_CreateContext()))
return NULL;
if(getEnvProc)
{
JSDJ_UserCallbacks callbacks;
callbacks.size = sizeof(JSDJ_UserCallbacks);
callbacks.getJNIEnv = getEnvProc;
jsdj_SetUserCallbacks(jsdjc, &callbacks, user);
}
if(jsdc)
jsdj_SetJSDContext(jsdjc, jsdc);
if(!jsdj_RegisterNatives(jsdjc))
{
jsdj_DestroyContext(jsdjc);
jsdjc = NULL;
}
return jsdjc;
}
JSBool
jsdj_SetSingleContextMode()
{
/* this can not be called after any contexts have been created */
ASSERT_RETURN_VALUE(0 == g_contextCount, JS_FALSE);
g_singleContextMode = JS_TRUE;
return JS_TRUE;
}
JSDJContext*
jsdj_CreateContext()
{
JSDJContext* jsdjc;
ASSERT_RETURN_VALUE(!(g_singleContextMode && g_contextCount), NULL);
jsdjc = (JSDJContext*) calloc(1, sizeof(JSDJContext));
if(!g_singleContextMode)
{
jsdjc->envTable = JS_NewHashTable(256, _hash_root,
JS_CompareValues, JS_CompareValues,
NULL, NULL);
if( ! jsdjc->envTable)
return NULL;
}
LOCK();
g_contextCount++;
g_newestContext = jsdjc;
UNLOCK();
return jsdjc;
}
void
jsdj_DestroyContext(JSDJContext* jsdjc)
{
LOCK();
g_contextCount--;
if(g_newestContext == jsdjc)
g_newestContext = NULL;
UNLOCK();
if(jsdjc->envTable)
free(jsdjc->envTable);
free(jsdjc);
}
void
jsdj_SetUserCallbacks(JSDJContext* jsdjc, JSDJ_UserCallbacks* callbacks,
void* user)
{
memset(&jsdjc->callbacks, 0, sizeof(JSDJ_UserCallbacks));
if(callbacks)
memcpy(&jsdjc->callbacks, callbacks,
JS_MIN(sizeof(JSDJ_UserCallbacks), callbacks->size));
}
void
jsdj_SetJNIEnvForCurrentThread(JSDJContext* jsdjc, JNIEnv* env)
{
if(g_singleContextMode && jsdjc->callbacks.getJNIEnv)
return;
LOCK();
if(!g_contextTable)
g_contextTable = JS_NewHashTable(256, _hash_root,
JS_CompareValues, JS_CompareValues,
NULL, NULL);
if(g_contextTable)
JS_HashTableAdd(g_contextTable, env, jsdjc);
JS_HashTableAdd(jsdjc->envTable, JSD_CurrentThread(), (void*)env);
UNLOCK();
}
JNIEnv*
jsdj_GetJNIEnvForCurrentThread(JSDJContext* jsdjc)
{
JNIEnv* env;
if(jsdjc->callbacks.getJNIEnv)
return (*jsdjc->callbacks.getJNIEnv)(jsdjc,jsdjc->user);
LOCK();
env = JS_HashTableLookup(jsdjc->envTable, JSD_CurrentThread());
UNLOCK();
return env;
}
void
jsdj_SetJSDContext(JSDJContext* jsdjc, JSDContext* jsdc)
{
JS_ASSERT(!jsdjc->ownJSDC);
jsdjc->jsdc = jsdc;
}
JSDContext*
jsdj_GetJSDContext(JSDJContext* jsdjc)
{
return jsdjc->jsdc;
}
static JSDJContext*
_getJSDJContext(JNIEnv *env)
{
JSDJContext* jsdjc;
if(g_singleContextMode)
return g_newestContext;
LOCK();
jsdjc = JS_HashTableLookup(g_contextTable, env);
/* XXX HACKAGE! */
if(!jsdjc && g_contextCount == 1 && g_newestContext != NULL)
{
jsdjc = g_newestContext;
jsdj_SetJNIEnvForCurrentThread(jsdjc, env);
}
UNLOCK();
return jsdjc;
}
static JSContext* _getDefaultJSContext(JNIEnv *env)
{
JSDJContext* jsdjc;
ASSERT_RETURN_VALUE(jsdjc = _getJSDJContext(env), NULL);
ASSERT_RETURN_VALUE(jsdjc->jsdc, NULL);
return JSD_GetDefaultJSContext(jsdjc->jsdc);
}
/***************************************************************************/
static JSDValue* _getNativeJSDValue(JNIEnv *env, jobject self)
{
jclass clazz;
jfieldID fid;
clazz = (*env)->GetObjectClass(env, self);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "_nativeJSVal", "I");
ASSERT_RETURN_VALUE(fid, NULL);
return (JSDValue*) (*env)->GetIntField(env, self, fid);
}
static jobject
_constructValue(JNIEnv *env, JSDContext* jsdc, JSDValue* jsdval)
{
jclass clazz;
jmethodID mid;
jfieldID fid;
jobject obj;
clazz = (*env)->FindClass(env, "netscape/jsdebug/Value");
ASSERT_GOTO(clazz, construct_value_fail);
fid = (*env)->GetFieldID(env, clazz, "_nativeJSVal", "I");
ASSERT_GOTO(fid, construct_value_fail);
mid = (*env)->GetMethodID(env, clazz, "<init>", "()V");
ASSERT_GOTO(mid, construct_value_fail);
obj = (*env)->NewObject(env, clazz, mid);
ASSERT_GOTO(obj, construct_value_fail);
(*env)->SetIntField(env, obj, fid, (long) jsdval);
ASSERT_CLEAR_EXCEPTION(env);
return obj;
construct_value_fail:
JSD_DropValue(jsdc, jsdval);
ASSERT_CLEAR_EXCEPTION(env);
return NULL;
}
static void
_destroyValue(JNIEnv *env, jobject self)
{
JSDValue* jsdval;
JSDJContext* jsdjc;
ASSERT_RETURN_VOID(jsdval = _getNativeJSDValue(env, self));
ASSERT_RETURN_VOID(jsdjc = _getJSDJContext(env));
ASSERT_RETURN_VOID(jsdjc->jsdc);
JSD_DropValue(jsdjc->jsdc, jsdval);
}
/***************************************************************************/
/***************************************************************************/
/***************************************************************************/
static jobject
_constructInteger(JNIEnv *env, long i)
{
jclass clazz;
jmethodID mid;
clazz = (*env)->FindClass(env, "java/lang/Integer");
ASSERT_RETURN_VALUE(clazz, NULL);
mid = (*env)->GetMethodID(env, clazz, "<init>", "(I)V");
ASSERT_RETURN_VALUE(mid, NULL);
return (*env)->NewObject(env, clazz, mid, i);
}
static jmethodID
_getObjectMethodID(JNIEnv *env, jobject o, const char* method, const char* sig)
{
jclass clazz = (*env)->GetObjectClass(env, o);
ASSERT_RETURN_VALUE(clazz, NULL);
return (*env)->GetMethodID(env, clazz, method, sig );
}
static jobject
_putHash(JNIEnv *env, jobject tbl, jobject key, jobject ob)
{
jmethodID mid = _getObjectMethodID(env, tbl, "put",
"(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
ASSERT_RETURN_VALUE(mid, NULL);
return (*env)->CallObjectMethod(env, tbl, mid, key, ob);
}
static jobject
_getHash(JNIEnv *env, jobject tbl, jobject key)
{
jmethodID mid = _getObjectMethodID(env, tbl, "get",
"(Ljava/lang/Object;)Ljava/lang/Object;");
ASSERT_RETURN_VALUE(mid, NULL);
return (*env)->CallObjectMethod(env, tbl, mid, key);
}
static jobject
_removeHash(JNIEnv *env, jobject tbl, jobject key)
{
jmethodID mid = _getObjectMethodID(env, tbl, "remove",
"(Ljava/lang/Object;)Ljava/lang/Object;");
ASSERT_RETURN_VALUE(mid, NULL);
return (*env)->CallObjectMethod(env, tbl, mid, key);
}
static jobject
_constructJSStackFrameInfo(JNIEnv *env,
JSDStackFrameInfo* jsdframe,
jobject threadstate)
{
jclass clazz;
jmethodID mid;
jobject frame;
clazz = (*env)->FindClass(env, "netscape/jsdebug/JSStackFrameInfo");
ASSERT_RETURN_VALUE(clazz, NULL);
mid = (*env)->GetMethodID(env, clazz, "<init>",
"(Lnetscape/jsdebug/JSThreadState;)V");
ASSERT_RETURN_VALUE(mid, NULL);
frame = (*env)->NewObject(env, clazz, mid, threadstate);
if( frame )
{
jfieldID fid;
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, frame, fid, (long) jsdframe);
/* XXX fill in additional fields... */
}
return frame;
}
static jobject
_constructJSThreadState(JNIEnv *env,
JSDStackFrameInfo* jsdframe,
JSDThreadState* jsdstate)
{
jclass clazz;
jmethodID mid;
jobject threadState;
clazz = (*env)->FindClass(env, "netscape/jsdebug/JSThreadState");
ASSERT_RETURN_VALUE(clazz, NULL);
mid = (*env)->GetMethodID(env, clazz, "<init>",
"()V");
ASSERT_RETURN_VALUE(mid, NULL);
threadState = (*env)->NewObject(env, clazz, mid);
if( threadState )
{
jfieldID fid;
/* valid */
fid = (*env)->GetFieldID(env, clazz, "valid", "Z");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetBooleanField(env, threadState, fid, JNI_TRUE);
/* currentFramePtr */
fid = (*env)->GetFieldID(env, clazz, "currentFramePtr", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, threadState, fid, (long) jsdframe);
/* nativeThreadState */
fid = (*env)->GetFieldID(env, clazz, "nativeThreadState", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, threadState, fid, (long) jsdstate );
/* continueState */
fid = (*env)->GetFieldID(env, clazz, "continueState", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, threadState, fid, DEBUG_STATE_RUN );
/* XXX fill in additional fields... */
}
return threadState;
}
static jobject
_constructScript(JNIEnv *env, JSDContext* jsdc, JSDScript* jsdscript)
{
jclass clazz;
jmethodID mid;
jobject script;
char* url = (char*)JSD_GetScriptFilename (jsdc, jsdscript);
char* function = (char*)JSD_GetScriptFunctionName (jsdc, jsdscript);
int base = JSD_GetScriptBaseLineNumber (jsdc, jsdscript);
int extent = JSD_GetScriptLineExtent (jsdc, jsdscript);
if( ! url )
{
return NULL;
/* url = ""; */
}
clazz = (*env)->FindClass(env, "netscape/jsdebug/Script");
ASSERT_RETURN_VALUE(clazz, NULL);
mid = (*env)->GetMethodID(env, clazz, "<init>", "()V");
ASSERT_RETURN_VALUE(mid, NULL);
script = (*env)->NewObject(env, clazz, mid);
if( script )
{
jfieldID fid;
/* _url */
fid = (*env)->GetFieldID(env, clazz, "_url", "Ljava/lang/String;");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetObjectField(env, script, fid,
(*env)->NewStringUTF(env, url));
/* _function */
fid = (*env)->GetFieldID(env, clazz, "_function", "Ljava/lang/String;");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetObjectField(env, script, fid,
function ? (*env)->NewStringUTF(env, function) : NULL);
/* _baseLineNumber */
fid = (*env)->GetFieldID(env, clazz, "_baseLineNumber", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, script, fid, base);
/* _lineExtent */
fid = (*env)->GetFieldID(env, clazz, "_lineExtent", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, script, fid, extent);
/* _nativePtr */
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, script, fid, (long)jsdscript);
/* XXX fill in additional fields... */
}
return script;
}
static jobject
_constructJSPC(JNIEnv *env, jobject script, long pc)
{
jclass clazz;
jmethodID mid;
jobject pcOb;
clazz = (*env)->FindClass(env, "netscape/jsdebug/JSPC" );
ASSERT_RETURN_VALUE(clazz, NULL);
mid = (*env)->GetMethodID(env, clazz, "<init>",
"(Lnetscape/jsdebug/Script;I)V");
ASSERT_RETURN_VALUE(mid, NULL);
pcOb = (*env)->NewObject(env, clazz, mid, script, pc);
/* XXX fill in additional fields... */
return pcOb;
}
static jobject
_constructJSSourceLocation(JNIEnv *env, jobject pc, long line)
{
jclass clazz;
jmethodID mid;
jobject loc;
clazz = (*env)->FindClass(env, "netscape/jsdebug/JSSourceLocation");
ASSERT_RETURN_VALUE(clazz, NULL);
mid = (*env)->GetMethodID(env, clazz, "<init>",
"(Lnetscape/jsdebug/JSPC;I)V");
ASSERT_RETURN_VALUE(mid, NULL);
loc = (*env)->NewObject(env, clazz, mid, pc, line);
/* XXX fill in additional fields... */
return loc;
}
static jobject
_getScriptHook(JNIEnv *env, JSDJContext* jsdjc)
{
jclass clazz;
jfieldID fid;
clazz = (*env)->GetObjectClass(env, jsdjc->controller);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "scriptHook",
"Lnetscape/jsdebug/ScriptHook;");
ASSERT_RETURN_VALUE(fid, NULL);
return (*env)->GetObjectField(env, jsdjc->controller, fid);
}
static jobject
_getInterruptHook(JNIEnv *env, JSDJContext* jsdjc)
{
jclass clazz;
jfieldID fid;
clazz = (*env)->GetObjectClass(env, jsdjc->controller);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "interruptHook",
"Lnetscape/jsdebug/InterruptHook;");
ASSERT_RETURN_VALUE(fid, NULL);
return (*env)->GetObjectField(env, jsdjc->controller, fid);
}
static jobject
_getDebugBreakHook(JNIEnv *env, JSDJContext* jsdjc)
{
jclass clazz;
jfieldID fid;
clazz = (*env)->GetObjectClass(env, jsdjc->controller);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "debugBreakHook",
"Lnetscape/jsdebug/DebugBreakHook;");
ASSERT_RETURN_VALUE(fid, NULL);
return (*env)->GetObjectField(env, jsdjc->controller, fid);
}
static jobject
_getInstructionHook(JNIEnv *env, JSDJContext* jsdjc, jobject pc)
{
jmethodID mid;
mid = _getObjectMethodID(env, jsdjc->controller, "getInstructionHook0",
"(Lnetscape/jsdebug/PC;)Lnetscape/jsdebug/InstructionHook;");
ASSERT_RETURN_VALUE(mid, NULL);
return (*env)->CallObjectMethod(env, jsdjc->controller, mid, pc);
}
static jobject
_getErrorReporter(JNIEnv *env, JSDJContext* jsdjc)
{
jclass clazz;
jfieldID fid;
clazz = (*env)->GetObjectClass(env, jsdjc->controller);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "errorReporter",
"Lnetscape/jsdebug/JSErrorReporter;");
ASSERT_RETURN_VALUE(fid, NULL);
return (*env)->GetObjectField(env, jsdjc->controller, fid);
}
static jobject
_getScriptTable(JNIEnv *env, JSDJContext* jsdjc)
{
jclass clazz;
jfieldID fid;
clazz = (*env)->GetObjectClass(env, jsdjc->controller);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "scriptTable",
"Lnetscape/util/Hashtable;");
ASSERT_RETURN_VALUE(fid, NULL);
return (*env)->GetObjectField(env, jsdjc->controller, fid);
}
static jobject
_scriptObFromJSDScriptPtr(JNIEnv *env, JSDJContext* jsdjc, JSDScript* jsdscript)
{
jobject tbl;
jobject key;
tbl = _getScriptTable(env, jsdjc);
ASSERT_RETURN_VALUE(tbl, NULL);
key = _constructInteger(env,(long)jsdscript);
ASSERT_RETURN_VALUE(key, NULL);
return _getHash(env, tbl, key);
}
static JSDThreadState*
_JSDThreadStateFromJSStackFrameInfo(JNIEnv *env, jobject frame)
{
jclass clazz;
jfieldID fid;
jobject threadState;
clazz = (*env)->GetObjectClass(env, frame);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "threadState",
"Lnetscape/jsdebug/ThreadStateBase;");
ASSERT_RETURN_VALUE(fid, NULL);
threadState = (*env)->GetObjectField(env, frame, fid);
ASSERT_RETURN_VALUE(threadState, NULL);
clazz = (*env)->GetObjectClass(env, threadState);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "nativeThreadState", "I");
ASSERT_RETURN_VALUE(fid, NULL);
return (JSDThreadState*) (*env)->GetIntField(env, threadState, fid);
}
static JSDStackFrameInfo*
_JSDStackFrameInfoFromJSStackFrameInfo(JNIEnv *env, jobject frame)
{
jclass clazz;
jfieldID fid;
clazz = (*env)->GetObjectClass(env, frame);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_RETURN_VALUE(fid, NULL);
return (JSDStackFrameInfo*) (*env)->GetIntField(env, frame, fid);
}
static char*
_allocCString(JNIEnv *env, jstring str)
{
jsize len;
char* buf;
len = (*env)->GetStringUTFLength(env, str);
buf = malloc(len+1);
ASSERT_RETURN_VALUE(buf, NULL);
buf[0] = 0;
if(len)
{
const jbyte* temp = (*env)->GetStringUTFChars(env, str, NULL);
if(temp)
{
strncpy(buf, temp, len);
(*env)->ReleaseStringUTFChars(env, str, temp);
buf[len] = 0;
}
}
return buf;
}
static jstring
_NewStringUTF_No_Z(JNIEnv *env, const char* str, uintN len)
{
jstring textOb;
char* temp;
temp = malloc(len+1);
ASSERT_RETURN_VALUE(temp, NULL);
strncpy(temp, str, len);
temp[len] = 0;
textOb = (*env)->NewStringUTF(env, temp);
free(temp);
return textOb;
}
/***************************************************************************/
void JS_DLL_CALLBACK
_scriptHook(JSDContext* jsdc,
JSDScript* jsdscript,
JSBool creating,
void* callerdata)
{
JNIEnv* env;
JSDJContext* jsdjc;
jobject script;
jobject tbl;
jobject key;
jobject hook;
jmethodID mid;
jsdjc = (JSDJContext*) callerdata;
ASSERT_RETURN_VOID(jsdjc && jsdjc->controller);
env = jsdj_GetJNIEnvForCurrentThread(jsdjc);
ASSERT_RETURN_VOID(env);
ASSERT_CLEAR_EXCEPTION(env);
tbl = _getScriptTable(env, jsdjc);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(tbl);
key = _constructInteger(env, (long)jsdscript);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(key);
hook = _getScriptHook(env, jsdjc);
CHECK_CLEAR_EXCEPTION(env);
if( creating )
{
script = _constructScript(env, jsdc, jsdscript);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(script);
/* add it to the hash table */
_putHash( env, tbl, key, script );
ASSERT_CLEAR_EXCEPTION(env);
if( hook )
{
/* call the hook */
mid = _getObjectMethodID(env, hook, "justLoadedScript",
"(Lnetscape/jsdebug/Script;)V" );
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(mid);
(*env)->CallVoidMethod(env, hook, mid, script);
ASSERT_CLEAR_EXCEPTION(env);
}
}
else
{
/* find Java Object for Script */
script = _getHash(env, tbl, key);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(script);
/* remove it from the hash table */
_removeHash(env, tbl, key);
ASSERT_CLEAR_EXCEPTION(env);
if( hook )
{
/* call the hook */
mid = _getObjectMethodID(env, hook, "aboutToUnloadScript",
"(Lnetscape/jsdebug/Script;)V" );
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(mid);
(*env)->CallVoidMethod(env, hook, mid, script);
ASSERT_CLEAR_EXCEPTION(env);
}
/* set the Script as invalid */
mid = _getObjectMethodID(env, script, "_setInvalid",
"()V" );
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(mid);
(*env)->CallVoidMethod(env, script, mid);
ASSERT_CLEAR_EXCEPTION(env);
}
}
/***************************************************************************/
uintN JS_DLL_CALLBACK
_executionHook(JSDContext* jsdc,
JSDThreadState* jsdstate,
uintN type,
void* callerdata,
jsval* rval)
{
JNIEnv* env;
JSDJContext* jsdjc;
JSDStackFrameInfo* jsdframe;
JSDScript* jsdscript;
jobject script;
jobject threadState;
jobject pcOb;
jobject tbl;
jobject key;
jobject hook;
jmethodID mid;
jfieldID fid;
jclass clazz;
int pc;
jsdjc = (JSDJContext*) callerdata;
ASSERT_RETURN_VALUE(jsdjc && jsdjc->controller, JSD_HOOK_RETURN_HOOK_ERROR);
env = jsdj_GetJNIEnvForCurrentThread(jsdjc);
ASSERT_RETURN_VALUE(env, JSD_HOOK_RETURN_HOOK_ERROR);
ASSERT_CLEAR_EXCEPTION(env);
/* get the JSDStackFrameInfo */
jsdframe = JSD_GetStackFrame(jsdc, jsdstate);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdframe, JSD_HOOK_RETURN_HOOK_ERROR);
/* get the JSDScript */
jsdscript = JSD_GetScriptForStackFrame(jsdc, jsdstate, jsdframe);
ASSERT_RETURN_VALUE(jsdscript, JSD_HOOK_RETURN_HOOK_ERROR);
/* find Java Object for Script */
tbl = _getScriptTable(env, jsdjc);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(tbl, JSD_HOOK_RETURN_HOOK_ERROR);
key = _constructInteger(env, (long)jsdscript);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(key, JSD_HOOK_RETURN_HOOK_ERROR);
script = _getHash(env, tbl, key);
CHECK_CLEAR_EXCEPTION(env);
CHECK_RETURN_VALUE(script, JSD_HOOK_RETURN_HOOK_ERROR);
/* generate a JSPC */
pc = JSD_GetPCForStackFrame(jsdc, jsdstate, jsdframe);
pcOb = _constructJSPC(env, script, pc);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(pcOb, JSD_HOOK_RETURN_HOOK_ERROR);
/* build a JSThreadState */
threadState = _constructJSThreadState(env, jsdframe, jsdstate);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(threadState, JSD_HOOK_RETURN_HOOK_ERROR);
/* find and call the appropriate Hook */
if( JSD_HOOK_INTERRUPTED == type )
{
/* clear the JSD level hook (must reset on next sendInterrupt0()*/
JSD_ClearInterruptHook(jsdc);
hook = _getInterruptHook(env, jsdjc);
CHECK_CLEAR_EXCEPTION(env);
CHECK_RETURN_VALUE(hook, JSD_HOOK_RETURN_HOOK_ERROR);
/* call the hook */
mid = _getObjectMethodID(env, hook, "aboutToExecute",
"(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(mid, JSD_HOOK_RETURN_HOOK_ERROR);
(*env)->CallVoidMethod(env, hook, mid, threadState, pcOb);
ASSERT_CLEAR_EXCEPTION(env);
}
else if( JSD_HOOK_DEBUG_REQUESTED == type )
{
hook = _getDebugBreakHook(env, jsdjc);
CHECK_CLEAR_EXCEPTION(env);
CHECK_RETURN_VALUE(hook, JSD_HOOK_RETURN_HOOK_ERROR);
/* call the hook */
mid = _getObjectMethodID(env, hook, "aboutToExecute",
"(Lnetscape/jsdebug/ThreadStateBase;Lnetscape/jsdebug/PC;)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(mid, JSD_HOOK_RETURN_HOOK_ERROR);
(*env)->CallVoidMethod(env, hook, mid, threadState, pcOb);
ASSERT_CLEAR_EXCEPTION(env);
}
else if( JSD_HOOK_BREAKPOINT == type )
{
hook = _getInstructionHook(env, jsdjc, pcOb);
CHECK_CLEAR_EXCEPTION(env);
CHECK_RETURN_VALUE(hook, JSD_HOOK_RETURN_HOOK_ERROR);
/* call the hook */
mid = _getObjectMethodID(env, hook, "aboutToExecute",
"(Lnetscape/jsdebug/ThreadStateBase;)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(mid, JSD_HOOK_RETURN_HOOK_ERROR);
(*env)->CallVoidMethod(env, hook, mid, threadState);
ASSERT_CLEAR_EXCEPTION(env);
}
/* should we abort? */
clazz = (*env)->GetObjectClass(env, threadState);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, JSD_HOOK_RETURN_CONTINUE);
fid = (*env)->GetFieldID(env, clazz, "continueState", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, JSD_HOOK_RETURN_CONTINUE);
if( DEBUG_STATE_THROW == (*env)->GetIntField(env, threadState, fid) )
return JSD_HOOK_RETURN_ABORT;
return JSD_HOOK_RETURN_CONTINUE;
}
/***************************************************************************/
uintN JS_DLL_CALLBACK
_errorReporter( JSDContext* jsdc,
JSContext* cx,
const char* message,
JSErrorReport* report,
void* callerdata )
{
JNIEnv* env;
JSDJContext* jsdjc;
jmethodID mid;
jobject reporter;
jobject msg = NULL;
jobject filename = NULL;
int lineno = 0;
jobject linebuf = NULL;
int tokenOffset = 0;
int retval;
jsdjc = (JSDJContext*) callerdata;
ASSERT_RETURN_VALUE(jsdjc && jsdjc->controller, JSD_ERROR_REPORTER_PASS_ALONG);
env = jsdj_GetJNIEnvForCurrentThread(jsdjc);
ASSERT_RETURN_VALUE(env, JSD_ERROR_REPORTER_PASS_ALONG);
ASSERT_CLEAR_EXCEPTION(env);
reporter = _getErrorReporter(env, jsdjc);
CHECK_CLEAR_EXCEPTION(env);
CHECK_RETURN_VALUE(reporter, JSD_ERROR_REPORTER_PASS_ALONG);
if( message )
msg = (*env)->NewStringUTF(env, message);
if( report && report->filename )
filename = (*env)->NewStringUTF(env, report->filename);
if( report && report->linebuf )
linebuf = (*env)->NewStringUTF(env, report->linebuf);
if( report )
lineno = report->lineno;
if( report && report->linebuf && report->tokenptr )
tokenOffset = report->tokenptr - report->linebuf;
/* call the hook */
mid = _getObjectMethodID(env, reporter, "reportError",
"(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(mid, JSD_HOOK_RETURN_HOOK_ERROR);
retval = (*env)->CallIntMethod(env, reporter, mid,
msg, filename, lineno, linebuf, tokenOffset);
ASSERT_CLEAR_EXCEPTION(env);
return retval;
}
/***************************************************************************/
/*
* Class: netscape_jsdebug_DebugController
* Method: setInstructionHook0
* Signature: (Lnetscape/jsdebug/PC;)V
*/
JNIEXPORT void JNICALL Java_netscape_jsdebug_DebugController_setInstructionHook0
(JNIEnv *env, jobject self, jobject pcOb)
{
jobject script;
JSDScript* jsdscript;
uintN pc;
JSDJContext* jsdjc;
jmethodID mid;
jclass clazz;
jfieldID fid;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VOID(jsdjc && jsdjc->jsdc && jsdjc->controller);
mid = _getObjectMethodID(env, pcOb, "getScript",
"()Lnetscape/jsdebug/Script;");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(mid);
script = (*env)->CallObjectMethod(env, pcOb, mid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(script);
clazz = (*env)->FindClass(env, "netscape/jsdebug/Script");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(clazz);
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(fid);
jsdscript = (JSDScript*) (*env)->GetIntField(env, script, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(jsdscript);
mid = _getObjectMethodID(env, pcOb, "getPC", "()I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(mid);
pc = (uintN) (*env)->CallIntMethod(env, pcOb, mid);
ASSERT_CLEAR_EXCEPTION(env);
JSD_SetExecutionHook(jsdjc->jsdc, jsdscript, pc, _executionHook, jsdjc);
}
/*
* Class: netscape_jsdebug_DebugController
* Method: sendInterrupt0
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_jsdebug_DebugController_sendInterrupt0
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VOID(jsdjc && jsdjc->jsdc && jsdjc->controller);
ASSERT_CLEAR_EXCEPTION(env);
JSD_SetInterruptHook(jsdjc->jsdc, _executionHook, jsdjc);
}
/*
* Class: netscape_jsdebug_DebugController
* Method: _setController
* Signature: (Z)V
*/
JNIEXPORT void JNICALL Java_netscape_jsdebug_DebugController__1setController
(JNIEnv *env, jobject self, jboolean on)
{
/*
** XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
** NOTE: in Navigator we turn native debug support on and off in this
** function. Here we just connect/disconnect from that support.
** XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX XXX
*/
JSDJContext* jsdjc;
jclass clazz;
jfieldID fid;
jsdjc = _getJSDJContext(env);
ASSERT_GOTO(jsdjc, LABEL_FAILURE);
ASSERT_CLEAR_EXCEPTION(env);
if(on)
{
if(!jsdjc->jsdc)
{
/*
* This is a hack to support Navigator. JSD_DebuggerOn ASSERTs in
* JSD that someone has previously called JSD_SetUserCallbacks
* (which is done in libmocha/lm_jsd). Here we are turning on
* debug support because a debugger applet has been started.
*/
ASSERT_GOTO(jsdjc->jsdc = JSD_DebuggerOn(), LABEL_FAILURE);
jsdjc->ownJSDC = JS_TRUE;
}
jsdjc->controller = (*env)->NewGlobalRef(env,self);
JSD_SetScriptHook(jsdjc->jsdc, _scriptHook, jsdjc);
JSD_SetErrorReporter(jsdjc->jsdc, _errorReporter, jsdjc);
JSD_SetDebugBreakHook(jsdjc->jsdc, _executionHook, jsdjc);
}
else
{
JSD_SetDebugBreakHook(jsdjc->jsdc, NULL, NULL);
JSD_SetErrorReporter(jsdjc->jsdc, NULL, NULL);
JSD_SetScriptHook(jsdjc->jsdc, NULL, NULL);
(*env)->DeleteGlobalRef(env,jsdjc->controller);
ASSERT_CLEAR_EXCEPTION(env);
jsdjc->controller = NULL;
jsdjc = NULL; /* for setting below... */
if(jsdjc->ownJSDC)
{
JSD_DebuggerOff(jsdjc->jsdc);
jsdjc->jsdc = NULL;
}
}
/* store the _nativeContext in the controller */
clazz = (*env)->FindClass(env, "netscape/jsdebug/DebugController");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_GOTO(clazz, LABEL_FAILURE);
fid = (*env)->GetFieldID(env, clazz, "_nativeContext", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_GOTO(fid, LABEL_FAILURE);
(*env)->SetIntField(env, self, fid, (long)jsdjc);
ASSERT_CLEAR_EXCEPTION(env);
if(jsdjc->callbacks.startStop)
(*jsdjc->callbacks.startStop)(jsdjc,
on ? JSDJ_START_SUCCESS : JSDJ_STOP,
jsdjc->user);
return;
LABEL_FAILURE:
if(jsdjc->callbacks.startStop)
(*jsdjc->callbacks.startStop)(jsdjc,
on ? JSDJ_START_FAILURE : JSDJ_STOP,
jsdjc->user);
}
/*
* Class: netscape_jsdebug_DebugController
* Method: executeScriptInStackFrame0
* Signature: (Lnetscape/jsdebug/JSStackFrameInfo;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_netscape_jsdebug_DebugController_executeScriptInStackFrame0
(JNIEnv *env, jobject self, jobject frame, jstring text,
jstring filename, jint lineno)
{
JSDJContext* jsdjc;
JSDThreadState* jsdthreadstate;
JSDStackFrameInfo* jsdframe;
char* filenameC;
char* srcC;
JSString* jsstr;
jsval rval;
JSBool success;
int srclen;
jstring retval;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, NULL);
ASSERT_CLEAR_EXCEPTION(env);
jsdthreadstate = _JSDThreadStateFromJSStackFrameInfo(env, frame);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdthreadstate, NULL);
jsdframe = _JSDStackFrameInfoFromJSStackFrameInfo(env, frame);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdframe, NULL);
filenameC = _allocCString(env, filename);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(filenameC, NULL);
srcC = _allocCString(env, text);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(srcC, NULL);
srclen = strlen(srcC);
success = JSD_EvaluateScriptInStackFrame(jsdjc->jsdc,
jsdthreadstate, jsdframe,
srcC, srclen,
filenameC, lineno, &rval);
free(filenameC);
free(srcC);
if( ! success )
return NULL;
if( JSVAL_IS_NULL(rval) || JSVAL_IS_VOID(rval) )
return NULL;
jsstr = JSD_ValToStringInStackFrame(jsdjc->jsdc, jsdthreadstate,
jsdframe, rval);
if( ! jsstr )
return NULL;
retval = (*env)->NewString(env,JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr));
ASSERT_CLEAR_EXCEPTION(env);
return retval;
}
/*
* Class: netscape_jsdebug_DebugController
* Method: executeScriptInStackFrameValue0
* Signature: (Lnetscape/jsdebug/JSStackFrameInfo;Ljava/lang/String;Ljava/lang/String;I)Lnetscape/jsdebug/Value;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_DebugController_executeScriptInStackFrameValue0
(JNIEnv *env, jobject self, jobject frame, jstring text,
jstring filename, jint lineno)
{
JSDJContext* jsdjc;
JSDThreadState* jsdthreadstate;
JSDStackFrameInfo* jsdframe;
char* filenameC;
char* srcC;
jsval rval;
JSBool success;
int srclen;
JSDValue* jsdval;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, NULL);
ASSERT_CLEAR_EXCEPTION(env);
jsdthreadstate = _JSDThreadStateFromJSStackFrameInfo(env, frame);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdthreadstate, NULL);
jsdframe = _JSDStackFrameInfoFromJSStackFrameInfo(env, frame);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdframe, NULL);
filenameC = _allocCString(env, filename);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(filenameC, NULL);
srcC = _allocCString(env, text);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(srcC, NULL);
srclen = strlen(srcC);
success = JSD_EvaluateScriptInStackFrame(jsdjc->jsdc,
jsdthreadstate, jsdframe,
srcC, srclen,
filenameC, lineno, &rval);
free(filenameC);
free(srcC);
if( ! success )
return NULL;
jsdval = JSD_NewValue(jsdjc->jsdc, rval);
if( ! jsdval )
return NULL;
return _constructValue(env, jsdjc->jsdc, jsdval);
}
/*
* Class: netscape_jsdebug_DebugController
* Method: getNativeMajorVersion
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_netscape_jsdebug_DebugController_getNativeMajorVersion
(JNIEnv *env, jclass clazz)
{
ASSERT_CLEAR_EXCEPTION(env);
return (jint) JSD_GetMajorVersion();
}
/*
* Class: netscape_jsdebug_DebugController
* Method: getNativeMinorVersion
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_netscape_jsdebug_DebugController_getNativeMinorVersion
(JNIEnv *env, jclass clazz)
{
ASSERT_CLEAR_EXCEPTION(env);
return (jint) JSD_GetMinorVersion();
}
/***************************************************************************/
/*
* Class: netscape_jsdebug_JSPC
* Method: getSourceLocation
* Signature: ()Lnetscape/jsdebug/SourceLocation;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSPC_getSourceLocation
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
JSDScript* jsdscript;
jobject script;
jobject newPCOb;
jclass clazz;
jfieldID fid;
int line;
int newpc;
int pc;
jobject retval;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, NULL);
ASSERT_CLEAR_EXCEPTION(env);
clazz = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "script", "Lnetscape/jsdebug/Script;");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
script = (*env)->GetObjectField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(script, NULL);
clazz = (*env)->GetObjectClass(env, script);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
jsdscript = (JSDScript*) (*env)->GetIntField(env, script, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdscript, NULL);
clazz = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "pc", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
pc = (*env)->GetIntField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
line = JSD_GetClosestLine(jsdjc->jsdc, jsdscript, pc);
newpc = JSD_GetClosestPC(jsdjc->jsdc, jsdscript, line);
newPCOb = _constructJSPC(env, script, newpc );
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(newPCOb, NULL);
retval = _constructJSSourceLocation(env, newPCOb, line);
ASSERT_CLEAR_EXCEPTION(env);
return retval;
}
/***************************************************************************/
/*
* Class: netscape_jsdebug_JSSourceTextProvider
* Method: loadSourceTextItem0
* Signature: (Ljava/lang/String;)Lnetscape/jsdebug/SourceTextItem;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem0
(JNIEnv *env, jobject self, jstring url)
{
/* this should attempt to load the source for the indicated URL */
ASSERT_CLEAR_EXCEPTION(env);
return NULL;
}
/*
* Class: netscape_jsdebug_JSSourceTextProvider
* Method: refreshSourceTextVector
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
jclass clazz;
jmethodID mid;
jclass clazzSelf;
jclass clazzSTI;
jmethodID midFindItem;
jmethodID midSTIctor;
jmethodID midSTIsetText;
jmethodID midSTIsetStatus;
jmethodID midSTIsetDirty;
jmethodID midVectorAddElement;
jfieldID fid;
jobject vec;
jobject itemOb;
JSDSourceText* iterp = 0;
JSDSourceText* item;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VOID(jsdjc && jsdjc->jsdc && jsdjc->controller);
ASSERT_CLEAR_EXCEPTION(env);
/* gather for later use */
clazzSelf = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(clazzSelf);
midFindItem = (*env)->GetMethodID(env, clazzSelf, "findSourceTextItem0",
"(Ljava/lang/String;)Lnetscape/jsdebug/SourceTextItem;");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(midFindItem);
clazzSTI = (*env)->FindClass(env, "netscape/jsdebug/SourceTextItem");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(clazzSTI);
midSTIctor = (*env)->GetMethodID(env, clazzSTI, "<init>",
"(Ljava/lang/String;Ljava/lang/String;I)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(midSTIctor);
midSTIsetText = (*env)->GetMethodID(env, clazzSTI, "setText",
"(Ljava/lang/String;)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(midSTIsetText);
midSTIsetStatus = (*env)->GetMethodID(env, clazzSTI, "setStatus", "(I)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(midSTIsetStatus);
midSTIsetDirty = (*env)->GetMethodID(env, clazzSTI, "setDirty", "(Z)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(midSTIsetDirty);
/* create new vector */
clazz = (*env)->FindClass(env, "netscape/util/Vector");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(clazz);
mid = (*env)->GetMethodID(env, clazz, "<init>", "()V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(mid);
vec = (*env)->NewObject(env, clazz, mid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(vec);
/* get method id for later */
midVectorAddElement = (*env)->GetMethodID(env, clazz, "addElement",
"(Ljava/lang/Object;)V");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(midVectorAddElement);
/* lock the native subsystem */
JSD_LockSourceTextSubsystem(jsdjc->jsdc);
/* iterate through the native items */
while( 0 != (item = JSD_IterateSources(jsdjc->jsdc, &iterp)) )
{
const char* url;
jstring urlOb;
int status;
status = JSD_GetSourceStatus(jsdjc->jsdc,item);
/* try to find Java object */
url = JSD_GetSourceURL(jsdjc->jsdc, item);
if( ! url || ! strlen(url) ) /* ignoring those with no url */
continue;
urlOb = (*env)->NewStringUTF(env, url);
ASSERT_CLEAR_EXCEPTION(env);
if( ! urlOb )
continue;
itemOb = (*env)->CallObjectMethod(env, self, midFindItem, urlOb);
ASSERT_CLEAR_EXCEPTION(env);
if( ! itemOb )
{
/* if not found then generate new item */
jstring textOb;
const char* str;
int len;
if( ! JSD_GetSourceText(jsdjc->jsdc, item, &str, &len ) )
{
str = "";
len = 0;
}
/*
* XXX this is pretty lame...
* makeJavaString() used to take a string len and
* didn't require zero termination.
* NewStringUTF() ASSUMES zero termination.
* So, this code makes an otherwise unnecessary copy
* of the string.
*
* XXX the JSD function should (in the future)
* allow for Unicode source text :)
*/
textOb = _NewStringUTF_No_Z(env, str, len);
ASSERT_CLEAR_EXCEPTION(env);
if(! textOb)
{
JS_ASSERT(0);
continue;
}
itemOb = (*env)->NewObject(env, clazzSTI, midSTIctor,
urlOb, textOb, status);
ASSERT_CLEAR_EXCEPTION(env);
}
else if( JSD_IsSourceDirty(jsdjc->jsdc, item) &&
JSD_SOURCE_CLEARED != status )
{
/* if found and dirty then update */
jstring textOb;
const char* str;
int len;
if( ! JSD_GetSourceText(jsdjc->jsdc, item, &str, &len ) )
{
str = "";
len = 0;
}
/*
* XXX see "this is pretty lame..." above
*/
textOb = _NewStringUTF_No_Z(env, str, len);
ASSERT_CLEAR_EXCEPTION(env);
if(! textOb)
{
JS_ASSERT(0);
continue;
}
(*env)->CallVoidMethod(env, itemOb, midSTIsetText, textOb);
ASSERT_CLEAR_EXCEPTION(env);
(*env)->CallVoidMethod(env, itemOb, midSTIsetStatus, status);
ASSERT_CLEAR_EXCEPTION(env);
(*env)->CallVoidMethod(env, itemOb, midSTIsetDirty, JNI_TRUE);
ASSERT_CLEAR_EXCEPTION(env);
}
/* we have our copy; clear the native cached text */
if( JSD_SOURCE_INITED != status &&
JSD_SOURCE_PARTIAL != status &&
JSD_SOURCE_CLEARED != status )
{
JSD_ClearSourceText(jsdjc->jsdc, item);
}
/* set the item clean */
JSD_SetSourceDirty(jsdjc->jsdc, item, 0 );
/* add the item to the vector */
if( itemOb )
{
(*env)->CallVoidMethod(env, vec, midVectorAddElement, itemOb);
ASSERT_CLEAR_EXCEPTION(env);
}
}
/* unlock the native subsystem */
JSD_UnlockSourceTextSubsystem(jsdjc->jsdc);
/* set main vector to our new vector */
fid = (*env)->GetFieldID(env, clazzSelf, "_sourceTextVector",
"Lnetscape/util/Vector;");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VOID(fid);
(*env)->SetObjectField(env, self, fid, vec);
ASSERT_CLEAR_EXCEPTION(env);
}
/***************************************************************************/
/*
* Class: netscape_jsdebug_JSStackFrameInfo
* Method: getCaller0
* Signature: ()Lnetscape/jsdebug/StackFrameInfo;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSStackFrameInfo_getCaller0
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
jclass clazz;
jfieldID fid;
JSDStackFrameInfo* jsdframeCur;
JSDStackFrameInfo* jsdframeCaller;
JSDThreadState* jsdthreadstate;
jobject threadState;
jobject retval;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, NULL);
ASSERT_CLEAR_EXCEPTION(env);
clazz = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, NULL);
/* get jsdframeCur */
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
jsdframeCur = (JSDStackFrameInfo*) (*env)->GetIntField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdframeCur, NULL);
/* get threadState */
fid = (*env)->GetFieldID(env, clazz, "threadState",
"Lnetscape/jsdebug/ThreadStateBase;");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
threadState = (*env)->GetObjectField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(threadState, NULL);
/* get jsdthreadState from threadState */
clazz = (*env)->GetObjectClass(env, threadState);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "nativeThreadState", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
jsdthreadstate = (JSDThreadState*) (*env)->GetIntField(env, threadState, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdthreadstate, NULL);
/* get caller frame from JSD */
jsdframeCaller = JSD_GetCallingStackFrame(jsdjc->jsdc, jsdthreadstate, jsdframeCur);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdframeCaller, NULL);
retval = _constructJSStackFrameInfo(env, jsdframeCaller, threadState);
ASSERT_CLEAR_EXCEPTION(env);
return retval;
}
static JSBool _getJSStackFrameInfo(JNIEnv *env, jobject self,
JSDJContext** pjsdjc,
JSDThreadState** pjsdthreadstate,
JSDStackFrameInfo** pjsdframe)
{
JSDJContext* jsdjc;
JSDThreadState* jsdthreadstate;
JSDStackFrameInfo* jsdframe;
jclass clazz;
jfieldID fid;
jobject threadState;
JS_ASSERT(pjsdjc && pjsdframe && pjsdthreadstate);
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, JS_FALSE);
ASSERT_CLEAR_EXCEPTION(env);
clazz = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, JS_FALSE);
/* get jsdframe */
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, JS_FALSE);
jsdframe = (JSDStackFrameInfo*) (*env)->GetIntField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdframe, JS_FALSE);
/* get threadState */
fid = (*env)->GetFieldID(env, clazz, "threadState",
"Lnetscape/jsdebug/ThreadStateBase;");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, JS_FALSE);
threadState = (*env)->GetObjectField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(threadState, JS_FALSE);
/* get jsdthreadState from threadState */
clazz = (*env)->GetObjectClass(env, threadState);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, JS_FALSE);
fid = (*env)->GetFieldID(env, clazz, "nativeThreadState", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, JS_FALSE);
jsdthreadstate = (JSDThreadState*) (*env)->GetIntField(env, threadState, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdthreadstate, JS_FALSE);
*pjsdjc = jsdjc;
*pjsdthreadstate = jsdthreadstate;
*pjsdframe = jsdframe;
return JS_TRUE;
}
/*
* Class: netscape_jsdebug_JSStackFrameInfo
* Method: getPC
* Signature: ()Lnetscape/jsdebug/PC;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSStackFrameInfo_getPC
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
JSDStackFrameInfo* jsdframe;
JSDThreadState* jsdthreadstate;
JSDScript* jsdscript;
jobject script;
int pc;
jobject retval;
if( !_getJSStackFrameInfo(env, self, &jsdjc, &jsdthreadstate, &jsdframe))
return NULL;
/* get jsdscript from JSD */
jsdscript = JSD_GetScriptForStackFrame(jsdjc->jsdc, jsdthreadstate, jsdframe);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdscript, NULL);
script = _scriptObFromJSDScriptPtr(env, jsdjc, jsdscript);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(script, NULL);
pc = JSD_GetPCForStackFrame(jsdjc->jsdc, jsdthreadstate, jsdframe);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(pc, NULL);
retval = _constructJSPC(env, script, pc);
ASSERT_CLEAR_EXCEPTION(env);
return retval;
}
/*
* Class: netscape_jsdebug_JSStackFrameInfo
* Method: getCallObject
* Signature: ()Lnetscape/jsdebug/Value;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSStackFrameInfo_getCallObject
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
JSDStackFrameInfo* jsdframe;
JSDThreadState* jsdthreadstate;
JSDValue* jsdval;
if( !_getJSStackFrameInfo(env, self, &jsdjc, &jsdthreadstate, &jsdframe))
return NULL;
jsdval = JSD_GetCallObjectForStackFrame(jsdjc->jsdc, jsdthreadstate, jsdframe);
if(!jsdval)
return NULL;
return _constructValue(env, jsdjc->jsdc, jsdval);
}
/*
* Class: netscape_jsdebug_JSStackFrameInfo
* Method: getScopeChain
* Signature: ()Lnetscape/jsdebug/Value;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSStackFrameInfo_getScopeChain
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
JSDStackFrameInfo* jsdframe;
JSDThreadState* jsdthreadstate;
JSDValue* jsdval;
if( !_getJSStackFrameInfo(env, self, &jsdjc, &jsdthreadstate, &jsdframe))
return NULL;
jsdval = JSD_GetScopeChainForStackFrame(jsdjc->jsdc, jsdthreadstate, jsdframe);
if(!jsdval)
return NULL;
return _constructValue(env, jsdjc->jsdc, jsdval);
}
/*
* Class: netscape_jsdebug_JSStackFrameInfo
* Method: getThis
* Signature: ()Lnetscape/jsdebug/Value;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSStackFrameInfo_getThis
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
JSDStackFrameInfo* jsdframe;
JSDThreadState* jsdthreadstate;
JSDValue* jsdval;
if( !_getJSStackFrameInfo(env, self, &jsdjc, &jsdthreadstate, &jsdframe))
return NULL;
jsdval = JSD_GetThisForStackFrame(jsdjc->jsdc, jsdthreadstate, jsdframe);
if(!jsdval)
return NULL;
return _constructValue(env, jsdjc->jsdc, jsdval);
}
/***************************************************************************/
/*
* Class: netscape_jsdebug_JSThreadState
* Method: countStackFrames
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_netscape_jsdebug_JSThreadState_countStackFrames
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
jclass clazz;
jfieldID fid;
JSDThreadState* jsdthreadstate;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, 0);
ASSERT_CLEAR_EXCEPTION(env);
clazz = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, 0);
fid = (*env)->GetFieldID(env, clazz, "nativeThreadState", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, 0);
jsdthreadstate = (JSDThreadState*) (*env)->GetIntField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdthreadstate, 0);
return (long) JSD_GetCountOfStackFrames(jsdjc->jsdc, jsdthreadstate);
}
/*
* Class: netscape_jsdebug_JSThreadState
* Method: getCurrentFrame
* Signature: ()Lnetscape/jsdebug/StackFrameInfo;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_JSThreadState_getCurrentFrame
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
jclass clazz;
jfieldID fid;
JSDThreadState* jsdthreadstate;
JSDStackFrameInfo* jsdframe;
jobject retval;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, NULL);
ASSERT_CLEAR_EXCEPTION(env);
clazz = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "nativeThreadState", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
jsdthreadstate = (JSDThreadState*) (*env)->GetIntField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdthreadstate, NULL);
jsdframe = JSD_GetStackFrame(jsdjc->jsdc, jsdthreadstate);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdframe, NULL);
retval = _constructJSStackFrameInfo(env, jsdframe, self);
ASSERT_CLEAR_EXCEPTION(env);
return retval;
}
/***************************************************************************/
/*
* Class: netscape_jsdebug_Script
* Method: getClosestPC
* Signature: (I)Lnetscape/jsdebug/JSPC;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_Script_getClosestPC
(JNIEnv *env, jobject self, jint lineno)
{
JSDJContext* jsdjc;
jclass clazz;
jfieldID fid;
JSDScript* jsdscript;
uintN pc;
jobject retval;
jsdjc = _getJSDJContext(env);
ASSERT_RETURN_VALUE(jsdjc && jsdjc->jsdc && jsdjc->controller, NULL);
ASSERT_CLEAR_EXCEPTION(env);
clazz = (*env)->GetObjectClass(env, self);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(clazz, NULL);
fid = (*env)->GetFieldID(env, clazz, "_nativePtr", "I");
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(fid, NULL);
jsdscript = (JSDScript*) (*env)->GetIntField(env, self, fid);
ASSERT_CLEAR_EXCEPTION(env);
ASSERT_RETURN_VALUE(jsdscript, NULL);
pc = JSD_GetClosestPC(jsdjc->jsdc, jsdscript, lineno);
if( -1 == pc )
return NULL;
retval = _constructJSPC(env, self, pc);
ASSERT_CLEAR_EXCEPTION(env);
return retval;
}
/***************************************************************************/
/***************************************************************************/
#undef IS_VALUE_X
#define IS_VALUE_X(type,e,s) \
JS_BEGIN_MACRO \
JSDValue* jsdval; \
JSDJContext* jsdjc; \
ASSERT_RETURN_VALUE(jsdval = _getNativeJSDValue(e, s), JNI_FALSE); \
ASSERT_RETURN_VALUE(jsdjc = _getJSDJContext(e), JNI_FALSE); \
ASSERT_RETURN_VALUE(jsdjc->jsdc, JNI_FALSE); \
return JSD_IsValue##type(jsdjc->jsdc, jsdval); \
JS_END_MACRO
#undef GET_VALUE_X
#define GET_VALUE_X(type,e,s,r) \
JS_BEGIN_MACRO \
JSDValue* jsdval; \
JSDJContext* jsdjc; \
ASSERT_RETURN_VALUE(jsdval = _getNativeJSDValue(e, s), JNI_FALSE); \
ASSERT_RETURN_VALUE(jsdjc = _getJSDJContext(e), JNI_FALSE); \
ASSERT_RETURN_VALUE(jsdjc->jsdc, JNI_FALSE); \
r = JSD_GetValue##type(jsdjc->jsdc, jsdval); \
JS_END_MACRO
#undef GET_VALUE_THING
#define GET_VALUE_THING(thing,e,s) \
JS_BEGIN_MACRO \
JSDJContext* jsdjc; \
JSDContext* jsdc; \
JSDValue* jsdval; \
JSDValue* result; \
ASSERT_RETURN_VALUE(jsdjc = _getJSDJContext(e), NULL); \
ASSERT_RETURN_VALUE(jsdc = jsdjc->jsdc, NULL); \
CHECK_RETURN_VALUE(jsdval = _getNativeJSDValue(env, s), NULL); \
CHECK_RETURN_VALUE(JSD_IsValueObject(jsdc, jsdval), NULL); \
CHECK_RETURN_VALUE(result = JSD_GetValue##thing(jsdc, jsdval), NULL); \
return _constructValue(env, jsdc, result); \
JS_END_MACRO
/*
* Class: netscape_jsdebug_Value
* Method: isObject
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isObject
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Object, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isNumber
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isNumber
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Number, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isInt
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isInt
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Int, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isDouble
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isDouble
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Double, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isString
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isString
(JNIEnv *env, jobject self)
{
IS_VALUE_X(String, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isBoolean
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isBoolean
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Boolean, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isNull
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isNull
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Null, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isVoid
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isVoid
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Void, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isPrimitive
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isPrimitive
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Primitive, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isFunction
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isFunction
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Function, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: isNative
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_isNative
(JNIEnv *env, jobject self)
{
IS_VALUE_X(Native, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: getBoolean
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value_getBoolean
(JNIEnv *env, jobject self)
{
JSBool retval;
GET_VALUE_X(Boolean, env, self, retval);
return retval;
}
/*
* Class: netscape_jsdebug_Value
* Method: getInt
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_netscape_jsdebug_Value_getInt
(JNIEnv *env, jobject self)
{
int32 retval;
GET_VALUE_X(Int, env, self, retval);
return retval;
}
/*
* Class: netscape_jsdebug_Value
* Method: getDouble
* Signature: ()D
*/
JNIEXPORT jdouble JNICALL Java_netscape_jsdebug_Value_getDouble
(JNIEnv *env, jobject self)
{
jsdouble* retval;
GET_VALUE_X(Double, env, self, retval);
CHECK_RETURN_VALUE(retval, 0);
return *retval;
}
/*
* Class: netscape_jsdebug_Value
* Method: finalize
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_jsdebug_Value_finalize
(JNIEnv *env, jobject self)
{
_destroyValue(env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: _refresh
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_netscape_jsdebug_Value__1refresh
(JNIEnv *env, jobject self)
{
JSDValue* jsdval;
JSDJContext* jsdjc;
ASSERT_RETURN_VOID(jsdval = _getNativeJSDValue(env, self));
ASSERT_RETURN_VOID(jsdjc = _getJSDJContext(env));
ASSERT_RETURN_VOID(jsdjc->jsdc);
JSD_RefreshValue(jsdjc->jsdc, jsdval);
}
/*
* Class: netscape_jsdebug_Value
* Method: _getString
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_netscape_jsdebug_Value__1getString
(JNIEnv *env, jobject self)
{
jstring jstr;
JSString* retval;
GET_VALUE_X(String, env, self, retval);
CHECK_RETURN_VALUE(retval, NULL);
jstr = (*env)->NewString(env, JS_GetStringChars(retval),
JS_GetStringLength(retval));
ASSERT_CLEAR_EXCEPTION(env);
return jstr;
}
/*
* Class: netscape_jsdebug_Value
* Method: _getFunctionName
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_netscape_jsdebug_Value__1getFunctionName
(JNIEnv *env, jobject self)
{
jstring jstr;
const char* retval;
GET_VALUE_X(FunctionName, env, self, retval);
CHECK_RETURN_VALUE(retval, NULL);
jstr = (*env)->NewStringUTF(env, retval);
ASSERT_CLEAR_EXCEPTION(env);
return jstr;
}
/*
* Class: netscape_jsdebug_Value
* Method: _getClassName
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_netscape_jsdebug_Value__1getClassName
(JNIEnv *env, jobject self)
{
jstring jstr;
const char* retval;
GET_VALUE_X(ClassName, env, self, retval);
CHECK_RETURN_VALUE(retval, NULL);
jstr = (*env)->NewStringUTF(env, retval);
ASSERT_CLEAR_EXCEPTION(env);
return jstr;
}
static jobject _constructProperty(JNIEnv *env, jclass clazz,
JSDContext* jsdc, JSDProperty* jsdprop)
{
jobject obj;
jmethodID mid;
jfieldID fid;
JSString* jsstr;
jstring str;
JSDValue* jsdval;
jobject objField;
uintN flags;
uintN slot;
int32 i;
JSBool valid;
short internalFlags = 0;
flags = JSD_GetPropertyFlags(jsdc, jsdprop);
slot = JSD_GetPropertyVarArgSlot(jsdc, jsdprop);
mid = (*env)->GetMethodID(env, clazz, "<init>", "()V");
ASSERT_RETURN_VALUE(mid, NULL);
obj = (*env)->NewObject(env, clazz, mid);
ASSERT_RETURN_VALUE(obj, NULL);
/* set the value */
fid = (*env)->GetFieldID(env, clazz, "_value", "Lnetscape/jsdebug/Value;");
ASSERT_RETURN_VALUE(fid, NULL);
ASSERT_RETURN_VALUE(jsdval = JSD_GetPropertyValue(jsdc, jsdprop), NULL);
ASSERT_RETURN_VALUE(objField = _constructValue(env, jsdc, jsdval), NULL);
(*env)->SetObjectField(env, obj, fid, objField);
ASSERT_RETURN_VALUE(jsdval = JSD_GetPropertyName(jsdc, jsdprop), NULL);
/* set the name */
if(JSD_IsValueString(jsdc, jsdval))
{
internalFlags |= 0x01; /* Property.NAME_IS_STRING */
jsstr = JSD_GetValueString(jsdc, jsdval);
if(jsstr)
str = (*env)->NewString(env,JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr));
JSD_DropValue(jsdc, jsdval);
ASSERT_RETURN_VALUE(jsstr && str, NULL);
fid = (*env)->GetFieldID(env, clazz, "_nameString",
"Ljava/lang/String;");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetObjectField(env, obj, fid, str);
}
else
{
if(valid = JSD_IsValueInt(jsdc, jsdval))
i = JSD_GetValueInt(jsdc, jsdval);
JSD_DropValue(jsdc, jsdval);
ASSERT_RETURN_VALUE(valid, NULL);
fid = (*env)->GetFieldID(env, clazz, "_nameInt", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, obj, fid, i);
}
/* set the alias */
if(flags & JSPD_ALIAS)
{
ASSERT_RETURN_VALUE(jsdval = JSD_GetPropertyAlias(jsdc, jsdprop), NULL);
if(JSD_IsValueString(jsdc, jsdval))
{
internalFlags |= 0x02; /* Property.ALIAS_IS_STRING */
jsstr = JSD_GetValueString(jsdc, jsdval);
if(jsstr)
str = (*env)->NewString(env,JS_GetStringChars(jsstr),
JS_GetStringLength(jsstr));
JSD_DropValue(jsdc, jsdval);
ASSERT_RETURN_VALUE(jsstr && str, NULL);
ASSERT_RETURN_VALUE(str, NULL);
fid = (*env)->GetFieldID(env, clazz, "_aliasString",
"Ljava/lang/String;");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetObjectField(env, obj, fid, str);
}
else
{
if(valid = JSD_IsValueInt(jsdc, jsdval))
i = JSD_GetValueInt(jsdc, jsdval);
JSD_DropValue(jsdc, jsdval);
ASSERT_RETURN_VALUE(valid, NULL);
fid = (*env)->GetFieldID(env, clazz, "_aliasInt", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, obj, fid, i);
}
}
/* set the flags */
fid = (*env)->GetFieldID(env, clazz, "_flags", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, obj, fid, flags);
/* set the slot ; XXX only matters id arg or prop, right?*/
fid = (*env)->GetFieldID(env, clazz, "_slot", "I");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetIntField(env, obj, fid, slot);
/* set the internal flags */
fid = (*env)->GetFieldID(env, clazz, "_internalFlags", "S");
ASSERT_RETURN_VALUE(fid, NULL);
(*env)->SetShortField(env, obj, fid, (jshort) internalFlags);
ASSERT_CLEAR_EXCEPTION(env);
return obj;
}
/*
* Class: netscape_jsdebug_Value
* Method: _getProperties
* Signature: ()[Lnetscape/jsdebug/Property;
*/
JNIEXPORT jobjectArray JNICALL Java_netscape_jsdebug_Value__1getProperties
(JNIEnv *env, jobject self)
{
JSDJContext* jsdjc;
JSDContext* jsdc;
JSDValue* jsdval;
jobjectArray propArray = NULL;
jclass clazz;
uintN i;
uintN count;
jobject prop ;
JSDProperty* iterp = NULL;
JSDProperty* jsdprop;
ASSERT_RETURN_VALUE(jsdjc = _getJSDJContext(env), NULL);
ASSERT_RETURN_VALUE(jsdc = jsdjc->jsdc, NULL);
CHECK_RETURN_VALUE(jsdval = _getNativeJSDValue(env, self), NULL);
CHECK_RETURN_VALUE(JSD_IsValueObject(jsdc, jsdval), NULL);
CHECK_RETURN_VALUE(!JSD_IsValueNull(jsdc, jsdval), NULL);
CHECK_RETURN_VALUE(count = JSD_GetCountOfProperties(jsdc, jsdval), NULL);
clazz = (*env)->FindClass(env, "netscape/jsdebug/Property");
ASSERT_RETURN_VALUE(clazz, NULL);
propArray = (*env)->NewObjectArray(env, count, clazz, NULL);
ASSERT_RETURN_VALUE(propArray, NULL);
for(i = 0; i < count; i++)
{
jsdprop = JSD_IterateProperties(jsdc, jsdval, &iterp);
if(!jsdprop)
{
JS_ASSERT(0);
propArray = NULL;
break;
}
prop = _constructProperty(env, clazz, jsdc, jsdprop);
JSD_DropProperty(jsdc, jsdprop);
if(!prop)
{
JS_ASSERT(0);
propArray = NULL;
break;
}
(*env)->SetObjectArrayElement(env, propArray, i, prop);
ASSERT_CLEAR_EXCEPTION(env);
}
JS_ASSERT(i != count || !JSD_IterateProperties(jsdc, jsdval, &iterp));
return propArray;
}
/*
* Class: netscape_jsdebug_Value
* Method: _getPrototype
* Signature: ()Lnetscape/jsdebug/Value;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_Value__1getPrototype
(JNIEnv *env, jobject self)
{
GET_VALUE_THING(Prototype, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: _getParent
* Signature: ()Lnetscape/jsdebug/Value;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_Value__1getParent
(JNIEnv *env, jobject self)
{
GET_VALUE_THING(Parent, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: _getConstructor
* Signature: ()Lnetscape/jsdebug/Value;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_Value__1getConstructor
(JNIEnv *env, jobject self)
{
GET_VALUE_THING(Constructor, env, self);
}
/*
* Class: netscape_jsdebug_Value
* Method: _equals
* Signature: (II)Z
*/
JNIEXPORT jboolean JNICALL Java_netscape_jsdebug_Value__1equals
(JNIEnv *env, jobject self, jint val1, jint val2)
{
JSDContext* jsdc;
JSDJContext* jsdjc;
JSDValue* jsdval1;
JSDValue* jsdval2;
ASSERT_RETURN_VALUE(jsdjc = _getJSDJContext(env), JNI_FALSE);
ASSERT_RETURN_VALUE(jsdc = jsdjc->jsdc, JNI_FALSE);
ASSERT_RETURN_VALUE(jsdval1 = (JSDValue*) val1, JNI_FALSE);
ASSERT_RETURN_VALUE(jsdval2 = (JSDValue*) val2, JNI_FALSE);
JS_ASSERT(jsdval1 == _getNativeJSDValue(env, self));
return JSD_GetValueWrappedJSVal(jsdc, jsdval1) ==
JSD_GetValueWrappedJSVal(jsdc, jsdval2);
}
/*
* Class: netscape_jsdebug_Value
* Method: _getProperty
* Signature: (Ljava/lang/String;)Lnetscape/jsdebug/Property;
*/
JNIEXPORT jobject JNICALL Java_netscape_jsdebug_Value__1getProperty
(JNIEnv *env, jobject self, jstring jName)
{
JSDContext* jsdc;
JSDJContext* jsdjc;
JSDValue* jsdval;
JSString* jsstr;
JSContext* cx;
const jchar *jchars;
jboolean isCopy;
jsize nameLen;
JSDProperty* jsdprop;
jclass clazz;
jobject prop;
clazz = (*env)->FindClass(env, "netscape/jsdebug/Property");
ASSERT_RETURN_VALUE(clazz, NULL);
ASSERT_RETURN_VALUE(jsdjc = _getJSDJContext(env), NULL);
ASSERT_RETURN_VALUE(jsdc = jsdjc->jsdc, NULL);
CHECK_RETURN_VALUE(jsdval = _getNativeJSDValue(env, self), NULL);
CHECK_RETURN_VALUE(JSD_IsValueObject(jsdc, jsdval), NULL);
ASSERT_RETURN_VALUE(cx = _getDefaultJSContext(env), NULL);
jchars = (*env)->GetStringChars(env, jName, &isCopy);
ASSERT_RETURN_VALUE(jchars, NULL);
nameLen = (*env)->GetStringLength(env, jName);
jsstr = JS_NewUCStringCopyN(cx, jchars, nameLen);
(*env)->ReleaseStringChars(env, jName, jchars);
jsdprop = JSD_GetValueProperty(jsdc, jsdval, jsstr);
if(!jsdprop)
return NULL;
prop = _constructProperty(env, clazz, jsdc, jsdprop);
JSD_DropProperty(jsdc, jsdprop);
return prop;
}
/***************************************************************************/
/***************************************************************************/
/* Registration code... */
static JNINativeMethod _natives_DebugController[] =
{
{"setInstructionHook0",
"(Lnetscape/jsdebug/PC;)V",
Java_netscape_jsdebug_DebugController_setInstructionHook0},
{"sendInterrupt0",
"()V",
Java_netscape_jsdebug_DebugController_sendInterrupt0},
{"_setController",
"(Z)V",
Java_netscape_jsdebug_DebugController__1setController},
{"executeScriptInStackFrame0",
"(Lnetscape/jsdebug/JSStackFrameInfo;Ljava/lang/String;Ljava/lang/String;I)Ljava/lang/String;",
Java_netscape_jsdebug_DebugController_executeScriptInStackFrame0},
{"executeScriptInStackFrameValue0",
"(Lnetscape/jsdebug/JSStackFrameInfo;Ljava/lang/String;Ljava/lang/String;I)Lnetscape/jsdebug/Value;",
Java_netscape_jsdebug_DebugController_executeScriptInStackFrameValue0},
{"getNativeMajorVersion",
"()I",
Java_netscape_jsdebug_DebugController_getNativeMajorVersion},
{"getNativeMinorVersion",
"()I",
Java_netscape_jsdebug_DebugController_getNativeMinorVersion}
};
static JNINativeMethod _natives_JSPC[] =
{
{"getSourceLocation",
"()Lnetscape/jsdebug/SourceLocation;",
Java_netscape_jsdebug_JSPC_getSourceLocation}
};
static JNINativeMethod _natives_JSSourceTextProvider[] =
{
{"loadSourceTextItem0",
"(Ljava/lang/String;)Lnetscape/jsdebug/SourceTextItem;",
Java_netscape_jsdebug_JSSourceTextProvider_loadSourceTextItem0},
{"refreshSourceTextVector",
"()V",
Java_netscape_jsdebug_JSSourceTextProvider_refreshSourceTextVector}
};
static JNINativeMethod _natives_JSStackFrameInfo[] =
{
{"getCaller0",
"()Lnetscape/jsdebug/StackFrameInfo;",
Java_netscape_jsdebug_JSStackFrameInfo_getCaller0},
{"getPC",
"()Lnetscape/jsdebug/PC;",
Java_netscape_jsdebug_JSStackFrameInfo_getPC},
{"getCallObject",
"()Lnetscape/jsdebug/Value;",
Java_netscape_jsdebug_JSStackFrameInfo_getCallObject},
{"getScopeChain",
"()Lnetscape/jsdebug/Value;",
Java_netscape_jsdebug_JSStackFrameInfo_getScopeChain},
{"getThis",
"()Lnetscape/jsdebug/Value;",
Java_netscape_jsdebug_JSStackFrameInfo_getThis}
};
static JNINativeMethod _natives_JSThreadState[] =
{
{"countStackFrames",
"()I",
Java_netscape_jsdebug_JSThreadState_countStackFrames},
{"getCurrentFrame",
"()Lnetscape/jsdebug/StackFrameInfo;",
Java_netscape_jsdebug_JSThreadState_getCurrentFrame}
};
static JNINativeMethod _natives_Script[] =
{
{"getClosestPC",
"(I)Lnetscape/jsdebug/JSPC;",
Java_netscape_jsdebug_Script_getClosestPC}
};
static JNINativeMethod _natives_Value[] =
{
{"isObject",
"()Z",
Java_netscape_jsdebug_Value_isObject},
{"isNumber",
"()Z",
Java_netscape_jsdebug_Value_isNumber},
{"isInt",
"()Z",
Java_netscape_jsdebug_Value_isInt},
{"isDouble",
"()Z",
Java_netscape_jsdebug_Value_isDouble},
{"isString",
"()Z",
Java_netscape_jsdebug_Value_isString},
{"isBoolean",
"()Z",
Java_netscape_jsdebug_Value_isBoolean},
{"isNull",
"()Z",
Java_netscape_jsdebug_Value_isNull},
{"isVoid",
"()Z",
Java_netscape_jsdebug_Value_isVoid},
{"isPrimitive",
"()Z",
Java_netscape_jsdebug_Value_isPrimitive},
{"isFunction",
"()Z",
Java_netscape_jsdebug_Value_isFunction},
{"isNative",
"()Z",
Java_netscape_jsdebug_Value_isNative},
{"getBoolean",
"()Z",
Java_netscape_jsdebug_Value_getBoolean},
{"getInt",
"()I",
Java_netscape_jsdebug_Value_getInt},
{"getDouble",
"()D",
Java_netscape_jsdebug_Value_getDouble},
{"finalize",
"()V",
Java_netscape_jsdebug_Value_finalize},
{"_refresh",
"()V",
Java_netscape_jsdebug_Value__1refresh},
{"_getString",
"()Ljava/lang/String;",
Java_netscape_jsdebug_Value__1getString},
{"_getFunctionName",
"()Ljava/lang/String;",
Java_netscape_jsdebug_Value__1getFunctionName},
{"_getClassName",
"()Ljava/lang/String;",
Java_netscape_jsdebug_Value__1getClassName},
{"_getProperties",
"()[Lnetscape/jsdebug/Property;",
Java_netscape_jsdebug_Value__1getProperties},
{"_getPrototype",
"()Lnetscape/jsdebug/Value;",
Java_netscape_jsdebug_Value__1getPrototype},
{"_getParent",
"()Lnetscape/jsdebug/Value;",
Java_netscape_jsdebug_Value__1getParent},
{"_getConstructor",
"()Lnetscape/jsdebug/Value;",
Java_netscape_jsdebug_Value__1getConstructor},
{"_equals",
"(II)Z",
Java_netscape_jsdebug_Value__1equals},
{"_getProperty",
"(Ljava/lang/String;)Lnetscape/jsdebug/Property;",
Java_netscape_jsdebug_Value__1getProperty},
};
/*************************************************/
typedef struct {
char* classname;
JNINativeMethod* natives;
jint count;
} ClassyJNINativeMethod;
#undef ARRAY_COUNT
#define ARRAY_COUNT(a) (sizeof(a)/sizeof(a[0]))
#undef ITEM
#define ITEM(t) {"netscape/jsdebug/"#t,_natives_##t,ARRAY_COUNT(_natives_##t)}
static ClassyJNINativeMethod _natives[] =
{
ITEM(DebugController),
ITEM(JSPC),
ITEM(JSSourceTextProvider),
ITEM(JSStackFrameInfo),
ITEM(JSThreadState),
ITEM(Script),
ITEM(Value)
};
#define NATIVE_COUNT (ARRAY_COUNT(_natives))
/*************************************************/
JSBool
jsdj_RegisterNatives(JSDJContext* jsdjc)
{
JSBool ok = JS_TRUE;
JNIEnv *env;
int i;
ASSERT_RETURN_VALUE(jsdjc, JS_FALSE);
ASSERT_RETURN_VALUE(env = jsdj_GetJNIEnvForCurrentThread(jsdjc), JS_FALSE);
ASSERT_CLEAR_EXCEPTION(env);
for( i = 0; i < NATIVE_COUNT; i++ )
{
jclass clazz;
if( 0 == (clazz = (*env)->FindClass(env, _natives[i].classname)) )
{
fprintf(stderr, "failed to find class %s while registering natives\n",
_natives[i].classname );
JS_ASSERT(0);
CHECK_CLEAR_EXCEPTION(env);
return JS_FALSE;
}
if( 0 != (*env)->RegisterNatives(env, clazz, _natives[i].natives,
_natives[i].count) )
{
fprintf(stderr, "failed to register natives for %s\n",
_natives[i].classname );
JS_ASSERT(0);
CHECK_CLEAR_EXCEPTION(env);
return JS_FALSE;
}
}
ASSERT_CLEAR_EXCEPTION(env);
return JS_TRUE;
}