mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-12-27 10:50:35 +00:00
617 lines
16 KiB
C
617 lines
16 KiB
C
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "_jni/com_netscape_nativejsengine_JSRuntime.h"
|
|
#include "_jni/com_netscape_nativejsengine_JSContext.h"
|
|
|
|
#include "jsapi.h"
|
|
#include "jstypes.h"
|
|
#include "jsutil.h" /* Added by JSIFY */
|
|
|
|
#ifdef JSDEBUGGER
|
|
#include "jsdebug.h"
|
|
#include "jsdjava.h"
|
|
#endif
|
|
|
|
/***************************************************************************/
|
|
|
|
#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)
|
|
|
|
/***************************************************************************/
|
|
|
|
typedef struct ContextInfo {
|
|
JNIEnv* env;
|
|
jobject contextObject;
|
|
} ContextInfo;
|
|
|
|
/***************************************************************************/
|
|
|
|
#ifdef JSDEBUGGER
|
|
static void
|
|
_jamSourceIntoJSD(JSContext *cx, const char* src, int len, const char* filename)
|
|
{
|
|
jclass clazz_self;
|
|
jclass clazz;
|
|
JSDJContext* jsdjc;
|
|
jobject rtObject;
|
|
jobject contextObject;
|
|
jmethodID mid;
|
|
jfieldID fid;
|
|
ContextInfo* info;
|
|
JNIEnv* env;
|
|
|
|
info = (ContextInfo*) JS_GetContextPrivate(cx);
|
|
ASSERT_RETURN_VOID(info);
|
|
|
|
env = info->env;
|
|
ASSERT_RETURN_VOID(env);
|
|
|
|
contextObject = info->contextObject;
|
|
ASSERT_RETURN_VOID(contextObject);
|
|
|
|
clazz_self = (*env)->GetObjectClass(env, contextObject);
|
|
ASSERT_RETURN_VOID(clazz_self);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz_self, "_runtime",
|
|
"Lcom/netscape/nativejsengine/JSRuntime;");
|
|
ASSERT_RETURN_VOID(fid);
|
|
|
|
rtObject = (*env)->GetObjectField(env, contextObject, fid);
|
|
ASSERT_RETURN_VOID(rtObject);
|
|
|
|
clazz = (*env)->GetObjectClass(env, rtObject);
|
|
ASSERT_RETURN_VOID(clazz);
|
|
|
|
mid = (*env)->GetMethodID(env, clazz, "getNativeDebugSupport", "()J");
|
|
ASSERT_RETURN_VOID(mid);
|
|
|
|
jsdjc = (JSDJContext*) (*env)->CallObjectMethod(env, rtObject, mid);
|
|
if(jsdjc)
|
|
{
|
|
JSDContext* jsdc;
|
|
|
|
jsdc = JSDJ_GetJSDContext(jsdjc);
|
|
ASSERT_RETURN_VOID(jsdc);
|
|
|
|
JSD_AddFullSourceText(jsdc, src, len, filename);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static JSBool
|
|
_loadSingleFile(JSContext *cx, JSObject *obj, const char* filename)
|
|
{
|
|
char* buf;
|
|
FILE* file;
|
|
int file_len;
|
|
jsval result;
|
|
|
|
errno = 0;
|
|
file = fopen(filename, "rb");
|
|
if (!file) {
|
|
JS_ReportError(cx, "can't open %s: %s", filename, strerror(errno));
|
|
return JS_FALSE;
|
|
}
|
|
|
|
fseek(file, 0, SEEK_END);
|
|
file_len = ftell(file);
|
|
fseek(file, 0, SEEK_SET);
|
|
|
|
if(! file_len) {
|
|
fclose(file);
|
|
JS_ReportError(cx, "%s is empty", filename);
|
|
return JS_FALSE;
|
|
}
|
|
|
|
buf = (char*) malloc(file_len);
|
|
if(! buf) {
|
|
fclose(file);
|
|
JS_ReportError(cx, "memory alloc error while trying to read %s", filename);
|
|
return JS_FALSE;
|
|
}
|
|
fread(buf, 1, file_len, file);
|
|
fclose(file);
|
|
|
|
#ifdef JSDEBUGGER
|
|
_jamSourceIntoJSD(cx, buf, file_len, filename);
|
|
#endif
|
|
|
|
JS_EvaluateScript(cx, obj, buf, file_len, filename, 1, &result);
|
|
|
|
free(buf);
|
|
return JS_TRUE;
|
|
}
|
|
|
|
|
|
static void _sendPrintStringToJava(JNIEnv* env, jobject contextObject,
|
|
jmethodID mid, const char* str)
|
|
{
|
|
if(! str)
|
|
return;
|
|
(*env)->CallObjectMethod(env, contextObject, mid,
|
|
(*env)->NewStringUTF(env, str));
|
|
}
|
|
|
|
static JSBool
|
|
Print(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
{
|
|
uintN i, n;
|
|
JSString *str;
|
|
|
|
ContextInfo* info;
|
|
jmethodID mid;
|
|
jclass clazz;
|
|
JNIEnv* env;
|
|
|
|
info = (ContextInfo*) JS_GetContextPrivate(cx);
|
|
ASSERT_RETURN_VALUE(info, JS_FALSE);
|
|
|
|
env = info->env;
|
|
ASSERT_RETURN_VALUE(env, JS_FALSE);
|
|
|
|
clazz = (*env)->GetObjectClass(env, info->contextObject);
|
|
ASSERT_RETURN_VALUE(clazz, JS_FALSE);
|
|
|
|
mid = (*env)->GetMethodID(env, clazz, "_print", "(Ljava/lang/String;)V");
|
|
ASSERT_RETURN_VALUE(mid, JS_FALSE);
|
|
|
|
for (i = n = 0; i < argc; i++) {
|
|
str = JS_ValueToString(cx, argv[i]);
|
|
if (!str)
|
|
return JS_FALSE;
|
|
|
|
if(i)
|
|
_sendPrintStringToJava(env, info->contextObject, mid, "");
|
|
_sendPrintStringToJava(env, info->contextObject, mid, JS_GetStringBytes(str));
|
|
n++;
|
|
}
|
|
if (n)
|
|
_sendPrintStringToJava(env, info->contextObject, mid, "\n");
|
|
return JS_TRUE;
|
|
}
|
|
|
|
static JSBool
|
|
Version(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
{
|
|
if (argc > 0 && JSVAL_IS_INT(argv[0]))
|
|
*rval = INT_TO_JSVAL(JS_SetVersion(cx, JSVAL_TO_INT(argv[0])));
|
|
else
|
|
*rval = INT_TO_JSVAL(JS_GetVersion(cx));
|
|
return JS_TRUE;
|
|
}
|
|
|
|
static JSBool
|
|
Load(JSContext *cx, JSObject *obj, uintN argc, jsval *argv, jsval *rval)
|
|
{
|
|
uintN i;
|
|
JSString *str;
|
|
const char *filename;
|
|
|
|
for (i = 0; i < argc; i++) {
|
|
str = JS_ValueToString(cx, argv[i]);
|
|
if (!str)
|
|
return JS_FALSE;
|
|
argv[i] = STRING_TO_JSVAL(str);
|
|
filename = JS_GetStringBytes(str);
|
|
|
|
if(! _loadSingleFile(cx, obj, filename))
|
|
return JS_FALSE;
|
|
}
|
|
return JS_TRUE;
|
|
}
|
|
|
|
static JSFunctionSpec shell_functions[] = {
|
|
{"version", Version, 0},
|
|
{"load", Load, 1},
|
|
{"print", Print, 0},
|
|
{0}
|
|
};
|
|
|
|
static void
|
|
my_ErrorReporter(JSContext *cx, const char *message, JSErrorReport *report)
|
|
{
|
|
ContextInfo* info;
|
|
jmethodID mid;
|
|
jclass clazz;
|
|
JNIEnv* env;
|
|
|
|
jobject msg = NULL;
|
|
jobject filename = NULL;
|
|
jobject lineBuf = NULL;
|
|
int lineno = 0;
|
|
int offset = 0;
|
|
|
|
info = (ContextInfo*) JS_GetContextPrivate(cx);
|
|
ASSERT_RETURN_VOID(info);
|
|
|
|
env = info->env;
|
|
ASSERT_RETURN_VOID(env);
|
|
|
|
clazz = (*env)->GetObjectClass(env, info->contextObject);
|
|
ASSERT_RETURN_VOID(clazz);
|
|
|
|
mid = (*env)->GetMethodID(env, clazz, "_reportError",
|
|
"(Ljava/lang/String;Ljava/lang/String;ILjava/lang/String;I)V");
|
|
ASSERT_RETURN_VOID(mid);
|
|
|
|
|
|
if(message)
|
|
msg = (*env)->NewStringUTF(env, message);
|
|
|
|
if(report)
|
|
{
|
|
lineno = report->lineno;
|
|
if(report->filename)
|
|
filename = (*env)->NewStringUTF(env, report->filename);
|
|
|
|
if(report->linebuf)
|
|
{
|
|
lineBuf = (*env)->NewStringUTF(env, report->linebuf);
|
|
if(report->tokenptr)
|
|
offset = report->tokenptr - report->linebuf;
|
|
}
|
|
}
|
|
|
|
(*env)->CallObjectMethod(env, info->contextObject, mid,
|
|
msg, filename, lineno, lineBuf, offset);
|
|
|
|
}
|
|
|
|
static JSClass global_class = {
|
|
"global", 0,
|
|
JS_PropertyStub, JS_PropertyStub, JS_PropertyStub, JS_PropertyStub,
|
|
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub, JS_FinalizeStub
|
|
};
|
|
|
|
/*
|
|
* Class: com_netscape_nativejsengine_JSRuntime
|
|
* Method: _init
|
|
* Signature: (Z)Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_com_netscape_nativejsengine_JSRuntime__1init
|
|
(JNIEnv * env, jobject self, jboolean enableDebugging)
|
|
{
|
|
JSRuntime *rt;
|
|
jclass clazz;
|
|
jfieldID fid;
|
|
|
|
rt = JS_NewRuntime(8L * 1024L * 1024L);
|
|
ASSERT_RETURN_VALUE(rt, JNI_FALSE);
|
|
|
|
clazz = (*env)->GetObjectClass(env, self);
|
|
ASSERT_RETURN_VALUE(clazz, JNI_FALSE);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz, "_nativeRuntime", "J");
|
|
ASSERT_RETURN_VALUE(fid, JNI_FALSE);
|
|
(*env)->SetLongField(env, self, fid, (long) rt);
|
|
|
|
|
|
#ifdef JSDEBUGGER
|
|
if(enableDebugging)
|
|
{
|
|
JSDJContext* jsdjc;
|
|
JSDContext* jsdc;
|
|
|
|
jsdc = JSD_DebuggerOnForUser(rt, NULL, NULL);
|
|
ASSERT_RETURN_VALUE(jsdc, JNI_FALSE);
|
|
|
|
jsdjc = JSDJ_CreateContext();
|
|
ASSERT_RETURN_VALUE(jsdjc, JNI_FALSE);
|
|
|
|
JSDJ_SetJSDContext(jsdjc, jsdc);
|
|
JSDJ_SetJNIEnvForCurrentThread(jsdjc, env);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz, "_nativeDebugSupport", "J");
|
|
ASSERT_RETURN_VALUE(fid, JNI_FALSE);
|
|
(*env)->SetLongField(env, self, fid, (long) jsdjc);
|
|
}
|
|
#else
|
|
if(enableDebugging)
|
|
printf("ERROR - Context created with enableDebugging flag, but no debugging support compiled in!");
|
|
#endif
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Class: com_netscape_nativejsengine_JSRuntime
|
|
* Method: _exit
|
|
* Signature: ()V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_com_netscape_nativejsengine_JSRuntime__1exit
|
|
(JNIEnv * env, jobject self)
|
|
{
|
|
jfieldID fid;
|
|
jclass clazz;
|
|
JSRuntime *rt;
|
|
JSContext *iterp = NULL;
|
|
|
|
clazz = (*env)->GetObjectClass(env, self);
|
|
ASSERT_RETURN_VOID(clazz);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz, "_nativeRuntime", "J");
|
|
ASSERT_RETURN_VOID(fid);
|
|
rt = (JSRuntime *) (*env)->GetLongField(env, self, fid);
|
|
ASSERT_RETURN_VOID(rt);
|
|
|
|
|
|
/*
|
|
* Can't kill runtime if it holds any contexts
|
|
*
|
|
* However, JSD may make it's own context(s), so don't ASSERT
|
|
*/
|
|
CHECK_RETURN_VOID(!JS_ContextIterator(rt, &iterp));
|
|
|
|
printf("runtime = %d\n", (int)rt);
|
|
|
|
JS_DestroyRuntime(rt);
|
|
}
|
|
|
|
/***************************************************************************/
|
|
|
|
/*
|
|
* Class: com_netscape_nativejsengine_JSContext
|
|
* Method: _init
|
|
* Signature: ()Z
|
|
*/
|
|
JNIEXPORT jboolean JNICALL Java_com_netscape_nativejsengine_JSContext__1init
|
|
(JNIEnv *env, jobject self)
|
|
{
|
|
JSContext *cx;
|
|
JSObject *glob;
|
|
jfieldID fid;
|
|
jmethodID mid;
|
|
JSRuntime *rt;
|
|
jobject rtObject;
|
|
jclass clazz;
|
|
jclass clazz_self;
|
|
JSBool ok;
|
|
ContextInfo* info;
|
|
|
|
#ifdef JSDEBUGGER
|
|
JSDJContext* jsdjc;
|
|
#endif
|
|
|
|
clazz_self = (*env)->GetObjectClass(env, self);
|
|
ASSERT_RETURN_VALUE(clazz_self, JNI_FALSE);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz_self, "_runtime",
|
|
"Lcom/netscape/nativejsengine/JSRuntime;");
|
|
ASSERT_RETURN_VALUE(fid, JNI_FALSE);
|
|
|
|
rtObject = (*env)->GetObjectField(env, self, fid);
|
|
ASSERT_RETURN_VALUE(rtObject, JNI_FALSE);
|
|
|
|
clazz = (*env)->GetObjectClass(env, rtObject);
|
|
ASSERT_RETURN_VALUE(clazz, JNI_FALSE);
|
|
|
|
mid = (*env)->GetMethodID(env, clazz, "getNativeRuntime", "()J");
|
|
ASSERT_RETURN_VALUE(mid, JNI_FALSE);
|
|
|
|
rt = (JSRuntime *) (*env)->CallObjectMethod(env, rtObject, mid);
|
|
ASSERT_RETURN_VALUE(rt, JNI_FALSE);
|
|
|
|
cx = JS_NewContext(rt, 8192);
|
|
ASSERT_RETURN_VALUE(cx, JNI_FALSE);
|
|
|
|
JS_SetErrorReporter(cx, my_ErrorReporter);
|
|
|
|
glob = JS_NewObject(cx, &global_class, NULL, NULL);
|
|
ASSERT_RETURN_VALUE(glob, JNI_FALSE);
|
|
|
|
ok = JS_InitStandardClasses(cx, glob);
|
|
ASSERT_RETURN_VALUE(ok, JNI_FALSE);
|
|
|
|
ok = JS_DefineFunctions(cx, glob, shell_functions);
|
|
ASSERT_RETURN_VALUE(ok, JNI_FALSE);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz_self, "_nativeContext", "J");
|
|
ASSERT_RETURN_VALUE(fid, JNI_FALSE);
|
|
(*env)->SetLongField(env, self, fid, (long) cx);
|
|
|
|
|
|
info = (ContextInfo*) malloc(sizeof(ContextInfo));
|
|
ASSERT_RETURN_VALUE(info, JNI_FALSE);
|
|
|
|
info->env = env;
|
|
info->contextObject = self;
|
|
|
|
JS_SetContextPrivate(cx, info);
|
|
|
|
#ifdef JSDEBUGGER
|
|
mid = (*env)->GetMethodID(env, clazz, "getNativeDebugSupport", "()J");
|
|
ASSERT_RETURN_VALUE(mid, JNI_FALSE);
|
|
|
|
jsdjc = (JSDJContext*) (*env)->CallObjectMethod(env, rtObject, mid);
|
|
if(jsdjc)
|
|
{
|
|
JSDContext* jsdc = JSDJ_GetJSDContext(jsdjc);
|
|
ASSERT_RETURN_VALUE(jsdc, JNI_FALSE);
|
|
|
|
JSDJ_SetJNIEnvForCurrentThread(jsdjc, env);
|
|
JSD_JSContextInUse(jsdc, cx);
|
|
}
|
|
#endif
|
|
|
|
return JNI_TRUE;
|
|
}
|
|
|
|
/*
|
|
* Class: com_netscape_nativejsengine_JSContext
|
|
* Method: _exit
|
|
* Signature: ()V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_com_netscape_nativejsengine_JSContext__1exit
|
|
(JNIEnv *env, jobject self)
|
|
{
|
|
jfieldID fid;
|
|
jclass clazz;
|
|
JSContext *cx;
|
|
ContextInfo* info;
|
|
|
|
clazz = (*env)->GetObjectClass(env, self);
|
|
ASSERT_RETURN_VOID(clazz);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz, "_nativeContext", "J");
|
|
ASSERT_RETURN_VOID(fid);
|
|
|
|
cx = (JSContext *) (*env)->GetLongField(env, self, fid);
|
|
ASSERT_RETURN_VOID(cx);
|
|
|
|
info = (ContextInfo*) JS_GetContextPrivate(cx);
|
|
ASSERT_RETURN_VOID(info);
|
|
free(info);
|
|
|
|
printf("context = %d\n", (int)cx);
|
|
|
|
JS_DestroyContext(cx);
|
|
}
|
|
|
|
/*
|
|
* Class: com_netscape_nativejsengine_JSContext
|
|
* Method: _eval
|
|
* Signature: (Ljava/lang/String;)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_com_netscape_nativejsengine_JSContext__1eval
|
|
(JNIEnv * env, jobject self, jstring str, jstring filename, jint lineno)
|
|
{
|
|
jfieldID fid;
|
|
jclass clazz_self;
|
|
JSContext *cx;
|
|
JSObject *glob;
|
|
jsval rval;
|
|
int len;
|
|
const char* Cstr;
|
|
const char* Cfilename;
|
|
jboolean isCopy;
|
|
|
|
clazz_self = (*env)->GetObjectClass(env, self);
|
|
ASSERT_RETURN_VOID(clazz_self);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz_self, "_nativeContext", "J");
|
|
ASSERT_RETURN_VOID(fid);
|
|
|
|
cx = (JSContext *) (*env)->GetLongField(env, self, fid);
|
|
ASSERT_RETURN_VOID(cx);
|
|
|
|
glob = JS_GetGlobalObject(cx);
|
|
ASSERT_RETURN_VOID(glob);
|
|
|
|
len = (*env)->GetStringUTFLength(env, str);
|
|
Cstr = (*env)->GetStringUTFChars(env, str, &isCopy);
|
|
Cfilename = (*env)->GetStringUTFChars(env, filename, &isCopy);
|
|
|
|
#ifdef JSDEBUGGER
|
|
/*
|
|
* XXX this just overwrites any previous source for this url!
|
|
*/
|
|
_jamSourceIntoJSD(cx, Cstr, len, Cfilename);
|
|
#endif
|
|
|
|
JS_EvaluateScript(cx, glob, Cstr, len, Cfilename, lineno, &rval);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, str, Cstr);
|
|
(*env)->ReleaseStringUTFChars(env, filename, Cfilename);
|
|
}
|
|
|
|
/*
|
|
* Class: com_netscape_nativejsengine_JSContext
|
|
* Method: _load
|
|
* Signature: (Ljava/lang/String;)V
|
|
*/
|
|
JNIEXPORT void JNICALL Java_com_netscape_nativejsengine_JSContext__1load
|
|
(JNIEnv *env, jobject self, jstring filename)
|
|
{
|
|
jfieldID fid;
|
|
jclass clazz;
|
|
JSContext *cx;
|
|
const char* Cfilename;
|
|
jboolean isCopy;
|
|
JSObject *glob;
|
|
|
|
clazz = (*env)->GetObjectClass(env, self);
|
|
ASSERT_RETURN_VOID(clazz);
|
|
|
|
fid = (*env)->GetFieldID(env, clazz, "_nativeContext", "J");
|
|
ASSERT_RETURN_VOID(fid);
|
|
|
|
cx = (JSContext *) (*env)->GetLongField(env, self, fid);
|
|
ASSERT_RETURN_VOID(cx);
|
|
|
|
glob = JS_GetGlobalObject(cx);
|
|
ASSERT_RETURN_VOID(glob);
|
|
|
|
Cfilename = (*env)->GetStringUTFChars(env, filename, &isCopy);
|
|
|
|
_loadSingleFile(cx, glob, Cfilename);
|
|
|
|
(*env)->ReleaseStringUTFChars(env, filename, Cfilename);
|
|
}
|