gecko-dev/js/jsj/jsStubs.c

628 строки
16 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
*
* 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.
*/
/* ** */
/* FIXME remove when pure JRI if possible */
#include "oobj.h"
#include "interpreter.h"
#include "tree.h"
#include "jsapi.h"
#include "jsjava.h"
#include "jscntxt.h" /* for cx->savedErrors */
#include "jri.h"
#include "prmon.h" /* for PR_XLock and PR_XUnlock */
#include "prprf.h" /* for PR_snprintf */
#include "prthread.h"
#include "prlog.h"
#ifdef JAVA
#define IMPLEMENT_netscape_javascript_JSObject
#include "netscape_javascript_JSObject.h"
#ifndef XP_MAC
#include "netscape_javascript_JSException.h"
#else
#include "n_javascript_JSException.h"
#endif
#endif
#ifdef NSPR20
extern PRLogModuleInfo* Moja;
#define debug PR_LOG_DEBUG
#endif /* NSPR20 */
#define JAVA_JS_STACK_SIZE 8192
typedef struct {
JSErrorReporter errReporter;
} JSSavedState;
static void
js_throwJSException(JRIEnv *env, char *detail)
{
#ifdef JAVA
struct java_lang_String* message =
JRI_NewStringPlatform(env,
(const jbyte *) detail,
(jint) strlen(detail),
(const jbyte *) NULL,
(jint) 0);
struct netscape_javascript_JSException* exc =
netscape_javascript_JSException_new_1(env,
class_netscape_javascript_JSException(env),
/*Java_getGlobalRef(env, js_JSExceptionClass),*/
message);
JRI_Throw(env, (struct java_lang_Throwable*)exc);
#endif /* JAVA */
}
/***********************************************************************/
static bool_t
enterJS(JRIEnv *env,
struct netscape_javascript_JSObject* self,
JSContext **cxp, JSObject **jsop, JSSavedState *saved)
{
#ifndef JAVA
return JS_FALSE;
#else
char *err;
JSJ_EnterJS();
/* check the internal pointer for null while holding the
* js lock to deal with shutdown issues */
if (jsop &&
(! self ||
! (*jsop = (JSObject *)
get_netscape_javascript_JSObject_internal(env, self)))) {
/* FIXME use a better exception */
JRI_ThrowNew(env, JRI_FindClass(env, "java/lang/Exception"),
"not a JavaScript object");
JSJ_ExitJS();
return FALSE;
}
/* PR_LOG(Moja, debug, ("clearing exceptions in ee=0x%x", env)); */
exceptionClear((ExecEnv *)env);
if (! (*cxp = JSJ_CurrentContext(env, &err))) {
JSJ_ExitJS();
if (err) {
js_throwJSException(env, err);
free(err);
}
return FALSE;
}
jsj_ClearSavedErrors(*cxp);
saved->errReporter = JS_SetErrorReporter(*cxp, js_JavaErrorReporter);
return TRUE;
#endif
}
static bool_t
exitJS(JRIEnv *env,
struct netscape_javascript_JSObject* self,
JSContext *cx, JSObject *jso, JSSavedState *saved)
{
#ifndef JAVA
return JS_FALSE;
#else
/* restore saved info */
JS_SetErrorReporter(cx, saved->errReporter);
js_JSErrorToJException(cx, (ExecEnv*)env);
JSJ_ExitJS();
if (exceptionOccurred((ExecEnv*)env))
return FALSE;
return TRUE;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(struct java_lang_Object *)
native_netscape_javascript_JSObject_getMember(
JRIEnv* env,
struct netscape_javascript_JSObject* self,
struct java_lang_String *name)
{
#ifndef JAVA
return NULL;
#else
JSContext *cx;
JSObject *jso;
JSSavedState saved;
const char *cstr;
struct java_lang_Object *member;
jsval val;
int cost = 0;
if (!enterJS(env, self, &cx, &jso, &saved))
return NULL;
if (! name ||
! (cstr = JRI_GetStringPlatformChars(env, name,
NULL, 0))) {
/* XXX - temporarily replace arguments so we can compile
(const jbyte *) cx->charSetName,
(jint) cx->charSetNameLength))) {
*/
/* FIXME this should be an error of some sort */
js_throwJSException(env, "illegal member name");
member = NULL;
goto do_exit;
}
if (! JS_GetProperty(cx, jso, cstr, &val) ||
! js_convertJSValueToJObject(/*FIXME*/(HObject**)&member, cx, val,
0, 0, JS_FALSE, &cost))
member = NULL;
do_exit:
if (!exitJS(env, self, cx, jso, &saved))
return NULL;
return member;
#endif
}
/***********************************************************************/
/* public native getSlot(I)Ljava/lang/Object; */
JRI_PUBLIC_API(struct java_lang_Object *)
native_netscape_javascript_JSObject_getSlot(
JRIEnv* env,
struct netscape_javascript_JSObject* self,
jint slot)
{
#ifndef JAVA
return NULL;
#else
JSContext *cx;
JSObject *jso;
JSSavedState saved;
struct java_lang_Object *member;
jsval val;
int cost = 0;
if (!enterJS(env, self, &cx, &jso, &saved))
return NULL;
if (! JS_GetElement(cx, jso, slot, &val) ||
! js_convertJSValueToJObject(/*FIXME*/(HObject**)&member, cx, val,
0, 0, JS_FALSE, &cost))
member = NULL;
if (!exitJS(env, self, cx, jso, &saved))
return NULL;
return member;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(void)
native_netscape_javascript_JSObject_setMember(
JRIEnv* env,
struct netscape_javascript_JSObject* self,
struct java_lang_String *name,
struct java_lang_Object *value)
{
#ifdef JAVA
JSContext *cx;
JSObject *jso;
JSSavedState saved;
const char *cstr;
jsval val;
if (!enterJS(env, self, &cx, &jso, &saved))
return;
if (! name ||
! (cstr = JRI_GetStringPlatformChars(env, name,
NULL, 0))) {
/* XXX - temporarily replace arguments so we can compile
(const jbyte *) cx->charSetName,
(jint) cx->charSetNameLength))) {
*/
js_throwJSException(env, "illegal member name");
goto do_exit;
}
if (js_convertJObjectToJSValue(cx, &val, (HObject *)value) &&
JS_SetProperty(cx, jso, cstr, &val)) {
}
/* PR_LOG(Moja, debug,
("JSObject.setMember(%s, 0x%x)\n", cstr, value)); */
do_exit:
exitJS(env, self, cx, jso, &saved);
return;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(void)
native_netscape_javascript_JSObject_setSlot(
JRIEnv* env,
struct netscape_javascript_JSObject* self,
jint slot,
struct java_lang_Object *value)
{
#ifdef JAVA
JSContext *cx;
JSObject *jso;
JSSavedState saved;
jsval val;
if (!enterJS(env, self, &cx, &jso, &saved))
return;
if (js_convertJObjectToJSValue(cx, &val, (HObject *)value) &&
JS_SetElement(cx, jso, slot, &val)) {
}
/* PR_LOG(Moja, debug,
("JSObject.setSlot(%d, 0x%x)\n", slot, value)); */
exitJS(env, self, cx, jso, &saved);
return;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(void)
native_netscape_javascript_JSObject_removeMember(
JRIEnv* env,
struct netscape_javascript_JSObject* self,
struct java_lang_String * name)
{
JSContext *cx;
JSObject *jso;
JSSavedState saved;
#ifdef JAVA /* only referenced if defined */
const char *cstr;
#endif
if (!enterJS(env, self, &cx, &jso, &saved))
return;
#ifdef JAVA
if (! name ||
! (cstr = JRI_GetStringPlatformChars(env, name,
NULL, 0))) {
/* XXX - temporarily replace arguments so we can compile
(const jbyte *) cx->charSetName,
(jint) cx->charSetNameLength);
*/
/* FIXME this should be an error of some sort */
js_throwJSException(env, "illegal member name");
goto do_exit;
}
JS_DeleteProperty(cx, jso, cstr);
#endif
/* PR_LOG(Moja, debug,
("JSObject.removeMember(%s)\n", cstr)); */
#ifdef JAVA /* only referenced if defined */
do_exit:
#endif
exitJS(env, self, cx, jso, &saved);
return;
}
/***********************************************************************/
JRI_PUBLIC_API(struct java_lang_Object *)
native_netscape_javascript_JSObject_call(
JRIEnv* env,
struct netscape_javascript_JSObject* self,
struct java_lang_String *method,
jobjectArray args)
{
#ifndef JAVA
return NULL;
#else
JSContext *cx;
JSObject *jso;
JSSavedState saved;
const char *cstr;
struct java_lang_Object *ret;
int total_argc, argc, i;
jsval *argv;
jsval rval;
int cost = 0;
if (!enterJS(env, self, &cx, &jso, &saved))
return NULL;
if (! method ||
! (cstr = JRI_GetStringPlatformChars(env, method,
NULL, 0))) {
/* XXX - temporarily replace arguments so we can compile
(const jbyte *) cx->charSetName,
(jint) cx->charSetNameLength))) {
*/
/* FIXME this should be an error of some sort */
js_throwJSException(env, "illegal member name");
ret = NULL;
goto do_exit;
}
if (args) {
total_argc = JRI_GetObjectArrayLength(env, args);
argv = sysMalloc(total_argc * sizeof(jsval));
} else {
total_argc = 0;
argv = 0;
}
for (argc = 0; argc < total_argc; argc++) {
jref arg = JRI_GetObjectArrayElement(env, args, argc);
if (!js_convertJObjectToJSValue(cx, argv+argc, (HObject*)arg))
goto cleanup_argv;
JS_AddRoot(cx, argv+argc);
}
if (! JS_CallFunctionName(cx, jso, cstr, argc, argv, &rval) ||
! js_convertJSValueToJObject((HObject **) &ret, cx, rval,
0, 0, JS_FALSE, &cost)) {
ret = NULL;
}
cleanup_argv:
for (i = 0; i < argc; i++)
JS_RemoveRoot(cx, argv+i);
sysFree(argv);
do_exit:
if (!exitJS(env, self, cx, jso, &saved))
return NULL;
return ret;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(struct java_lang_Object *)
native_netscape_javascript_JSObject_eval(
JRIEnv* env,
struct netscape_javascript_JSObject* self,
struct java_lang_String *s)
{
#ifndef JAVA
return NULL;
#else
JSContext *cx;
JSObject *jso;
JSSavedState saved;
const char *cstr;
int cstrlen;
struct java_lang_Object *ret;
jsval rval;
int cost = 0;
JSPrincipals *principals;
char *codebase;
if (!enterJS(env, self, &cx, &jso, &saved))
return NULL;
if (! s ||
! (cstr = JRI_GetStringPlatformChars(env, s,
NULL, 0))) {
/* XXX - temporarily replace arguments so we can compile
(const jbyte *) cx->charSetName,
(jint) cx->charSetNameLength))) {
*/
/* FIXME this should be an error of some sort */
js_throwJSException(env, "illegal eval string");
ret = NULL;
goto do_exit;
}
/* subtract 1 for the NUL */
/*
* FIXME There is no JRI_GetStringPlatformLength (what a misnomer, if there
* were!), but JRI_GetStringPlatformChars does NUL-terminate the encoded
* string, so we trust that no charset encoding ever uses a NUL byte as
* part of a multibyte sequence and just call strlen.
*/
cstrlen = strlen(cstr);
principals = js_GetJSPrincipalsFromJavaCaller(cx, 0);
codebase = principals ? principals->codebase : NULL;
if (! JS_EvaluateScriptForPrincipals(cx, jso, principals, cstr, cstrlen,
codebase, 0, &rval) ||
! js_convertJSValueToJObject((HObject**)&ret, cx, rval,
0, 0, JS_FALSE, &cost)) {
ret = NULL;
}
do_exit:
if (!exitJS(env, self, cx, jso, &saved))
return NULL;
return ret;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(void)
native_netscape_javascript_JSObject_finalize(
JRIEnv* env,
struct netscape_javascript_JSObject* self)
{
#ifdef JAVA
JSContext *cx;
JSObject *jso;
JSSavedState saved;
/* FIXME if enterJS fails here we have a memory leak! */
if (!enterJS(env, self, &cx, &jso, &saved))
return;
js_RemoveReflection(cx, jso);
if (!exitJS(env, self, cx, jso, &saved))
return;
return;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(struct java_lang_String *)
native_netscape_javascript_JSObject_toString(
JRIEnv* env,
struct netscape_javascript_JSObject* self)
{
JSContext *cx;
JSObject *jso;
JSSavedState saved;
#ifdef JAVA /* only referenced if defined */
JSString *jsstr;
char *cstr;
#endif
struct java_lang_String *ret = NULL;
if (!enterJS(env, self, &cx, &jso, &saved))
return NULL;
#ifdef JAVA
if ((jsstr = JS_ValueToString(cx, OBJECT_TO_JSVAL(jso))) &&
(cstr = JS_GetStringBytes(jsstr))) {
ret = JRI_NewStringPlatform(env,
(const jbyte *) cstr,
(jint) JS_GetStringLength(jsstr),
NULL, 0);
/* XXX - temporarily replace arguments so we can compile
(const jbyte *) cx->charSetName,
(jint) cx->charSetNameLength);
*/
} else {
/* FIXME could grab the clazz name from the JSObject */
ret = JRI_NewStringPlatform(env,
(const jbyte *) "*JSObject*",
(jint) strlen("*JSObject*"),
NULL, 0);
/* XXX - temporarily replace arguments so we can compile
(const jbyte *) cx->charSetName,
(jint) cx->charSetNameLength);
*/
}
#endif
if (!exitJS(env, self, cx, jso, &saved))
return NULL;
return ret;
}
/***********************************************************************/
JRI_PUBLIC_API(struct netscape_javascript_JSObject*)
native_netscape_javascript_JSObject_getWindow(
JRIEnv* env,
struct java_lang_Class* clazz,
struct java_applet_Applet* hint)
{
#ifndef JAVA
return NULL;
#else
struct netscape_javascript_JSObject *ret = NULL;
JSContext *cx;
JSSavedState saved;
JSObject *jso;
if (!JSJ_IsEnabled()) {
js_throwJSException(env, "Java/JavaScript communication is disabled");
return 0;
}
if (!enterJS(env, NULL, &cx, NULL, &saved))
return NULL;
jso = JSJ_GetDefaultObject(env, (jobject) hint);
if (exceptionOccurred((ExecEnv *)env))
goto out;
ret = (struct netscape_javascript_JSObject *)
js_ReflectJSObjectToJObject(cx, jso);
out:
if (!exitJS(env, NULL, cx, NULL, &saved))
return NULL;
return ret;
#endif
}
/***********************************************************************/
JRI_PUBLIC_API(void)
native_netscape_javascript_JSObject_initClass(
JRIEnv* env,
struct java_lang_Class* myClazz)
{
#ifdef JAVA
struct java_lang_Class* clazz;
/* this is to initialize the field lookup indices, and protect
* the classes from gc. */
clazz = use_netscape_javascript_JSObject(env);
MakeClassSticky((struct Hjava_lang_Class*)clazz);
clazz = use_netscape_javascript_JSException(env);
MakeClassSticky((struct Hjava_lang_Class*)clazz);
/* this does nothing if somebody else has already set
* stuff up (i.e. client or server) */
JSJ_InitStandalone();
#endif
}