Back to index

lightning-sunbird  0.9+nobinonly
Classes | Defines | Typedefs | Functions | Variables
jsj_JavaObject.c File Reference
#include <stdlib.h>
#include <string.h>
#include "jsobj.h"
#include "jsj_private.h"
#include "jsj_hash.h"

Go to the source code of this file.

Classes

struct  JSJPropertyInfo

Defines

#define JSJ_SLOT_COUNT   (JSSLOT_PRIVATE+1)

Typedefs

typedef struct JSJPropertyInfo

Functions

static JSBool JS_DLL_CALLBACK jsj_GC_callback (JSContext *cx, JSGCStatus status)
JSBool jsj_InitJavaObjReflectionsTable (void)
JSObjectjsj_WrapJavaObject (JSContext *cx, JNIEnv *jEnv, jobject java_obj, jclass java_class)
static void remove_java_obj_reflection_from_hashtable (jobject java_obj, JSJHashNumber hash_code)
 JavaObject_finalize (JSContext *cx, JSObject *obj)
static JSIntn enumerate_remove_java_obj (JSJHashEntry *he, JSIntn i, void *arg)
void jsj_DiscardJavaObjReflections (JNIEnv *jEnv)
JSBool JS_DLL_CALLBACK JavaObject_convert (JSContext *cx, JSObject *obj, JSType type, jsval *vp)
static JSBool inherit_props_from_JS_natives (JSContext *cx, const char *js_constructor_name, const char *member_name, jsval *vp)
static JSBool lookup_member_by_id (JSContext *cx, JNIEnv *jEnv, JSObject *obj, JavaObjectWrapper **java_wrapperp, jsid id, JavaMemberDescriptor **member_descriptorp, jsval *vp, JSObject **proto_chainp, JSJPropertyInfo *prop_infop)
 JavaObject_getPropertyById (JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 JavaObject_setPropertyById (JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 JavaObject_lookupProperty (JSContext *cx, JSObject *obj, jsid id, JSObject **objp, JSProperty **propp)
 JavaObject_defineProperty (JSContext *cx, JSObject *obj, jsid id, jsval value, JSPropertyOp getter, JSPropertyOp setter, uintN attrs, JSProperty **propp)
 JavaObject_getAttributes (JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, uintN *attrsp)
 JavaObject_setAttributes (JSContext *cx, JSObject *obj, jsid id, JSProperty *prop, uintN *attrsp)
 JavaObject_deleteProperty (JSContext *cx, JSObject *obj, jsid id, jsval *vp)
 JavaObject_defaultValue (JSContext *cx, JSObject *obj, JSType type, jsval *vp)
 JavaObject_newEnumerate (JSContext *cx, JSObject *obj, JSIterateOp enum_op, jsval *statep, jsid *idp)
 JavaObject_checkAccess (JSContext *cx, JSObject *obj, jsid id, JSAccessMode mode, jsval *vp, uintN *attrsp)
JSObjectMap *JS_DLL_CALLBACK jsj_wrapper_newObjectMap (JSContext *cx, jsrefcount nrefs, JSObjectOps *ops, JSClass *clasp, JSObject *obj)
void JS_DLL_CALLBACK jsj_wrapper_destroyObjectMap (JSContext *cx, JSObjectMap *map)
jsval JS_DLL_CALLBACK jsj_wrapper_getRequiredSlot (JSContext *cx, JSObject *obj, uint32 slot)
JSBool JS_DLL_CALLBACK jsj_wrapper_setRequiredSlot (JSContext *cx, JSObject *obj, uint32 slot, jsval v)
 JavaObject_getObjectOps (JSContext *cx, JSClass *clazz)
 JS_IMPORT_DATA (JSObjectOps)

Variables

static JSJHashTablejava_obj_reflections = NULL
static JSBool installed_GC_callback = JS_FALSE
static JSGCCallback old_GC_callback = NULL
static JavaObjectWrapperdeferred_wrappers = NULL
JSObjectOps JavaObject_ops
JSClass JavaObject_class

Class Documentation

struct JSJPropertyInfo

Definition at line 471 of file jsj_JavaObject.c.

Collaboration diagram for JSJPropertyInfo:
Class Members
uintN attributes
const char * name
JSProperty * prop
JSBool wantProp

Define Documentation

Definition at line 990 of file jsj_JavaObject.c.


Typedef Documentation

typedef struct JSJPropertyInfo

Definition at line 478 of file jsj_JavaObject.c.


Function Documentation

static JSIntn enumerate_remove_java_obj ( JSJHashEntry he,
JSIntn  i,
void arg 
) [static]

Definition at line 324 of file jsj_JavaObject.c.

{
    JSJavaThreadState *jsj_env = (JSJavaThreadState *)arg;
    JNIEnv *jEnv = jsj_env->jEnv;
    jobject java_obj;
    JavaObjectWrapper *java_wrapper;
    JSObject *java_wrapper_obj;

    java_wrapper_obj = (JSObject *)he->value;

    /* Warning: NULL argument may cause assertion in JS engine, but it's actually OK */
    java_wrapper = JS_GetPrivate(jsj_env->cx, java_wrapper_obj);
    java_obj = java_wrapper->java_obj;
    (*jEnv)->DeleteGlobalRef(jEnv, java_obj);
    java_wrapper->java_obj = NULL;
    return HT_ENUMERATE_REMOVE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static JSBool inherit_props_from_JS_natives ( JSContext cx,
const char *  js_constructor_name,
const char *  member_name,
jsval vp 
) [static]

Definition at line 449 of file jsj_JavaObject.c.

{
    JSObject *global_obj, *constructor_obj, *prototype_obj;
    jsval constructor_val, prototype_val;

    global_obj = JS_GetGlobalObject(cx);
    JS_ASSERT(global_obj);
    if (!global_obj)
        return JS_FALSE;

    JS_GetProperty(cx, global_obj, js_constructor_name, &constructor_val);
    JS_ASSERT(JSVAL_IS_OBJECT(constructor_val));
    constructor_obj = JSVAL_TO_OBJECT(constructor_val);

    JS_GetProperty(cx, constructor_obj, "prototype", &prototype_val);
    JS_ASSERT(JSVAL_IS_OBJECT(prototype_val));
    prototype_obj = JSVAL_TO_OBJECT(prototype_val);

    return JS_GetProperty(cx, prototype_obj, member_name, vp) && *vp != JSVAL_VOID;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JavaObject_checkAccess ( JSContext cx,
JSObject obj,
jsid  id,
JSAccessMode  mode,
jsval vp,
uintN attrsp 
)

Definition at line 971 of file jsj_JavaObject.c.

{
    switch (mode) {
    case JSACC_WATCH:
        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                             JSJMSG_JOBJECT_PROP_WATCH);
        return JS_FALSE;

    case JSACC_IMPORT:
        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                             JSJMSG_JOBJECT_PROP_EXPORT);
        return JS_FALSE;

    default:
        return JS_TRUE;
    }
}

Here is the call graph for this function:

JSBool JS_DLL_CALLBACK JavaObject_convert ( JSContext cx,
JSObject obj,
JSType  type,
jsval vp 
)

Definition at line 367 of file jsj_JavaObject.c.

{
    JavaObjectWrapper *java_wrapper;
    JavaClassDescriptor *class_descriptor;
    jobject java_obj;
    JNIEnv *jEnv;
    JSJavaThreadState *jsj_env;
    JSBool result;

    java_wrapper = JS_GetPrivate(cx, obj);
    if (!java_wrapper) {
        if (type == JSTYPE_OBJECT) {
            *vp = OBJECT_TO_JSVAL(obj);
            return JS_TRUE;
        }

        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                             JSJMSG_BAD_OP_JOBJECT);
        return JS_FALSE;
    }

    java_obj = java_wrapper->java_obj;
    class_descriptor = java_wrapper->class_descriptor;

    switch (type) {
    case JSTYPE_OBJECT:
        *vp = OBJECT_TO_JSVAL(obj);
        return JS_TRUE;

    case JSTYPE_FUNCTION:
        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                             JSJMSG_CONVERT_TO_FUNC);
        return JS_FALSE;

    case JSTYPE_VOID:
    case JSTYPE_STRING:
        /* Get the Java per-thread environment pointer for this JSContext */
        jsj_env = jsj_EnterJava(cx, &jEnv);
        if (!jEnv)
            return JS_FALSE;

        /* Either extract a C-string from the java.lang.String object
           or call the Java toString() method */
        result = jsj_ConvertJavaObjectToJSString(cx, jEnv, class_descriptor, java_obj, vp);
        jsj_ExitJava(jsj_env);
        return result;

    case JSTYPE_NUMBER:
        /* Get the Java per-thread environment pointer for this JSContext */
        jsj_env = jsj_EnterJava(cx, &jEnv);
        if (!jEnv)
            return JS_FALSE;

        /* Call Java doubleValue() method, if applicable */
        result = jsj_ConvertJavaObjectToJSNumber(cx, jEnv, class_descriptor, java_obj, vp);
        jsj_ExitJava(jsj_env);
        return result;

    case JSTYPE_BOOLEAN:
        /* Get the Java per-thread environment pointer for this JSContext */
        jsj_env = jsj_EnterJava(cx, &jEnv);
        if (!jEnv)
            return JS_FALSE;

        /* Call booleanValue() method, if applicable */
        result = jsj_ConvertJavaObjectToJSBoolean(cx, jEnv, class_descriptor, java_obj, vp);
        jsj_ExitJava(jsj_env);
        return result;

    default:
        JS_ASSERT(0);
        return JS_FALSE;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

JavaObject_defaultValue ( JSContext cx,
JSObject obj,
JSType  type,
jsval vp 
)

Definition at line 897 of file jsj_JavaObject.c.

{
    /* printf("In JavaObject_defaultValue()\n"); */
    return JavaObject_convert(cx, obj, type, vp);
}

Here is the call graph for this function:

JavaObject_defineProperty ( JSContext cx,
JSObject obj,
jsid  id,
jsval  value,
JSPropertyOp  getter,
JSPropertyOp  setter,
uintN  attrs,
JSProperty **  propp 
)

Definition at line 846 of file jsj_JavaObject.c.

{
    JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                         JSJMSG_JOBJECT_PROP_DEFINE);
    return JS_FALSE;
}

Here is the call graph for this function:

JavaObject_deleteProperty ( JSContext cx,
JSObject obj,
jsid  id,
jsval vp 
)

Definition at line 879 of file jsj_JavaObject.c.

{
    JSVersion version = JS_GetVersion(cx);

    *vp = JSVAL_FALSE;

    if (!JSVERSION_IS_ECMA(version)) {
        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                                        JSJMSG_JOBJECT_PROP_DELETE);
        return JS_FALSE;
    } else {
        /* Attempts to delete permanent properties are silently ignored
           by ECMAScript. */
        return JS_TRUE;
    }
}

Here is the call graph for this function:

JavaObject_finalize ( JSContext cx,
JSObject obj 
)

Definition at line 292 of file jsj_JavaObject.c.

{
    JavaObjectWrapper *java_wrapper;
    jobject java_obj;
    JNIEnv *jEnv;
    JSJavaThreadState *jsj_env;

    java_wrapper = JS_GetPrivate(cx, obj);
    if (!java_wrapper)
        return;
    java_obj = java_wrapper->java_obj;

    if (java_obj) {
        remove_java_obj_reflection_from_hashtable(java_obj, java_wrapper->u.hash_code);
        /* defer releasing global refs until it is safe to do so. */
        java_wrapper->u.next = deferred_wrappers;
        deferred_wrappers = java_wrapper;
    } else {
        jsj_env = jsj_EnterJava(cx, &jEnv);
        if (jEnv) {
            jsj_ReleaseJavaClassDescriptor(cx, jEnv, java_wrapper->class_descriptor);
            JS_free(cx, java_wrapper);
            jsj_ExitJava(jsj_env);
        } else {
            java_wrapper->u.next = deferred_wrappers;
            deferred_wrappers = java_wrapper;
        }
    }
}

Here is the call graph for this function:

JavaObject_getAttributes ( JSContext cx,
JSObject obj,
jsid  id,
JSProperty prop,
uintN attrsp 
)

Definition at line 856 of file jsj_JavaObject.c.

{
    /* We don't maintain JS property attributes for Java class members */
    *attrsp = JSPROP_PERMANENT|JSPROP_ENUMERATE;
    return JS_TRUE;
}
JavaObject_getObjectOps ( JSContext cx,
JSClass clazz 
)

Definition at line 1066 of file jsj_JavaObject.c.

{
    return &JavaObject_ops;
}
JavaObject_getPropertyById ( JSContext cx,
JSObject obj,
jsid  id,
jsval vp 
)

Definition at line 617 of file jsj_JavaObject.c.

{
    jobject java_obj;
    JavaMemberDescriptor *member_descriptor;
    JavaObjectWrapper *java_wrapper;
    JNIEnv *jEnv;
    JSObject *funobj;
    jsval field_val, method_val;
    JSBool success;
    JSJavaThreadState *jsj_env;
    JSObject *proto_chain;
    JSJPropertyInfo prop_info;

    /* printf("In JavaObject_getProperty\n"); */

    /* Get the Java per-thread environment pointer for this JSContext */
    jsj_env = jsj_EnterJava(cx, &jEnv);
    if (!jEnv)
        return JS_FALSE;

    if (vp)
        *vp = JSVAL_VOID;
    prop_info.wantProp = JS_FALSE;
    if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor, vp,
                             &proto_chain, &prop_info)) {
        jsj_ExitJava(jsj_env);
        return JS_FALSE;
    }

    /* Handle access to special, non-Java properties of JavaObjects, e.g. the
       "constructor" property of the prototype object */
    if (!member_descriptor) {
        jsj_ExitJava(jsj_env);
        if (proto_chain)
            return JS_GetProperty(cx, proto_chain, prop_info.name, vp);
        return JS_TRUE;
    }

    java_obj = java_wrapper->java_obj;
    field_val = method_val = JSVAL_VOID;

    if (jaApplet && (*jEnv)->IsInstanceOf(jEnv, java_obj, jaApplet)) {
        jsj_JSIsCallingApplet = JS_TRUE;
    }

    /* If a field member, get the value of the field */
    if (member_descriptor->field) {
        success = jsj_GetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, &field_val);
        if (!success) {
            jsj_ExitJava(jsj_env);
            return JS_FALSE;
        }
    }

    /* If a method member, build a wrapper around the Java method */
    if (member_descriptor->methods) {
        /* Create a function object with this JavaObject as its parent, so that
           JSFUN_BOUND_METHOD binds it as the default 'this' for the function. */
        funobj = JS_CloneFunctionObject(cx, member_descriptor->invoke_func_obj, obj);
        if (!funobj) {
            jsj_ExitJava(jsj_env);
            return JS_FALSE;
        }
        method_val = OBJECT_TO_JSVAL(funobj);
    }

#if TEST_JAVAMEMBER
    /* Always create a JavaMember object, even though it's inefficient */
    obj = jsj_CreateJavaMember(cx, method_val, field_val);
    if (!obj) {
        jsj_ExitJava(jsj_env);
        return JS_FALSE;
    }
    *vp = OBJECT_TO_JSVAL(obj);
#else   /* !TEST_JAVAMEMBER */

    if (member_descriptor->field) {
        if (!member_descriptor->methods) {
            /* Return value of Java field */
            *vp = field_val;
        } else {
            /* Handle special case of access to a property that could refer
               to either a Java field or a method that share the same name.
               In Java, such ambiguity is not possible because the compiler
               can statically determine which is being accessed. */
            obj = jsj_CreateJavaMember(cx, method_val, field_val);
            if (!obj) {
                jsj_ExitJava(jsj_env);
                return JS_FALSE;
            }
            *vp = OBJECT_TO_JSVAL(obj);
        }

    } else {
        /* Return wrapper around Java method */
        *vp = method_val;
    }

#endif  /* !TEST_JAVAMEMBER */

    jsj_ExitJava(jsj_env);
    return JS_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JavaObject_lookupProperty ( JSContext cx,
JSObject obj,
jsid  id,
JSObject **  objp,
JSProperty **  propp 
)

Definition at line 806 of file jsj_JavaObject.c.

{
    JNIEnv *jEnv;
    JSErrorReporter old_reporter;
    jsval dummy_val;
    JSObject *proto_chain;
    JSJPropertyInfo prop_info;
    JSJavaThreadState *jsj_env;

    /* printf("In JavaObject_lookupProperty()\n"); */

    /* Get the Java per-thread environment pointer for this JSContext */
    jsj_env = jsj_EnterJava(cx, &jEnv);
    if (!jEnv)
        return JS_FALSE;

    old_reporter = JS_SetErrorReporter(cx, NULL);
    prop_info.wantProp = JS_TRUE;
    if (lookup_member_by_id(cx, jEnv, obj, NULL, id, NULL, &dummy_val,
                            &proto_chain, &prop_info)) {
        /* signify that the property is in the prototype chain or the object itself. */
        if (proto_chain) {
            *objp = proto_chain;
            *propp = prop_info.prop;
        } else {
            *objp = obj;
            *propp = (JSProperty*)1;
        }
    } else {
        *objp = NULL;
        *propp = NULL;
    }

    JS_SetErrorReporter(cx, old_reporter);
    jsj_ExitJava(jsj_env);
    return JS_TRUE;
}

Here is the call graph for this function:

JavaObject_newEnumerate ( JSContext cx,
JSObject obj,
JSIterateOp  enum_op,
jsval statep,
jsid idp 
)

Definition at line 904 of file jsj_JavaObject.c.

{
    JavaObjectWrapper *java_wrapper;
    JavaMemberDescriptor *member_descriptor;
    JavaClassDescriptor *class_descriptor;
    JNIEnv *jEnv;
    JSJavaThreadState *jsj_env;

    java_wrapper = JS_GetPrivate(cx, obj);
    /* Check for prototype object */
    if (!java_wrapper) {
        *statep = JSVAL_NULL;
        if (idp)
            *idp = INT_TO_JSVAL(0);
        return JS_TRUE;
    }

    class_descriptor = java_wrapper->class_descriptor;

    switch(enum_op) {
    case JSENUMERATE_INIT:

        /* Get the Java per-thread environment pointer for this JSContext */
        jsj_env = jsj_EnterJava(cx, &jEnv);
        if (!jEnv)
            return JS_FALSE;

        member_descriptor = jsj_GetClassInstanceMembers(cx, jEnv, class_descriptor);
        *statep = PRIVATE_TO_JSVAL(member_descriptor);
        if (idp)
            *idp = INT_TO_JSVAL(class_descriptor->num_instance_members);
        jsj_ExitJava(jsj_env);
        return JS_TRUE;

    case JSENUMERATE_NEXT:
        member_descriptor = JSVAL_TO_PRIVATE(*statep);
        if (member_descriptor) {

            /* Don't enumerate explicit-signature methods, i.e. enumerate toValue,
               but not toValue(int), toValue(double), etc. */
            while (member_descriptor->methods && member_descriptor->methods->is_alias) {
                member_descriptor = member_descriptor->next;
                if (!member_descriptor) {
                    *statep = JSVAL_NULL;
                    return JS_TRUE;
                }
            }

            *idp = member_descriptor->id;
            *statep = PRIVATE_TO_JSVAL(member_descriptor->next);
            return JS_TRUE;
        }

        /* Fall through ... */

    case JSENUMERATE_DESTROY:
        *statep = JSVAL_NULL;
        return JS_TRUE;

    default:
        JS_ASSERT(0);
        return JS_FALSE;
    }
}

Here is the call graph for this function:

JavaObject_setAttributes ( JSContext cx,
JSObject obj,
jsid  id,
JSProperty prop,
uintN attrsp 
)

Definition at line 865 of file jsj_JavaObject.c.

{
    /* We don't maintain JS property attributes for Java class members */
    if (*attrsp != (JSPROP_PERMANENT|JSPROP_ENUMERATE)) {
        JS_ASSERT(0);
        return JS_FALSE;
    }

    /* Silently ignore all setAttribute attempts */
    return JS_TRUE;
}
JavaObject_setPropertyById ( JSContext cx,
JSObject obj,
jsid  id,
jsval vp 
)

Definition at line 722 of file jsj_JavaObject.c.

{
    jobject java_obj;
    const char *member_name;
    JavaObjectWrapper *java_wrapper;
    JavaClassDescriptor *class_descriptor;
    JavaMemberDescriptor *member_descriptor;
    jsval idval;
    JNIEnv *jEnv;
    JSJavaThreadState *jsj_env;
    JSObject *proto_chain;
    JSJPropertyInfo prop_info;
    JSBool result;

    /* printf("In JavaObject_setProperty\n"); */

    /* Get the Java per-thread environment pointer for this JSContext */
    jsj_env = jsj_EnterJava(cx, &jEnv);
    if (!jEnv)
        return JS_FALSE;

    prop_info.wantProp = JS_FALSE;
    if (!lookup_member_by_id(cx, jEnv, obj, &java_wrapper, id, &member_descriptor, NULL,
                             &proto_chain, &prop_info)) {
        jsj_ExitJava(jsj_env);
        return JS_FALSE;
    }

    /* Could be assignment to magic JS __proto__ property rather than a Java field */
    if (!member_descriptor) {
        if (proto_chain && (prop_info.attributes & JSPROP_SHARED)) {
            JS_SetProperty(cx, proto_chain, prop_info.name, vp);
        } else {
            JS_IdToValue(cx, id, &idval);
            if (!JSVAL_IS_STRING(idval))
                goto no_such_field;
            member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
            if (strcmp(member_name, "__proto__"))
                goto no_such_field;
            if (!JSVAL_IS_OBJECT(*vp)) {
                JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                                     JSJMSG_BAD_PROTO_ASSIGNMENT);
                jsj_ExitJava(jsj_env);
                return JS_FALSE;
            }
            JS_SetPrototype(cx, obj, JSVAL_TO_OBJECT(*vp));
        }
        jsj_ExitJava(jsj_env);
        return JS_TRUE;
    }

    /* Check for the case where there is a method with the given name, but no field
       with that name */
    if (!member_descriptor->field)
        goto no_such_field;

    /* Silently fail if field value is final (immutable), as required by ECMA spec */
    if (member_descriptor->field->modifiers & ACC_FINAL) {
        jsj_ExitJava(jsj_env);
        return JS_TRUE;
    }

    java_obj = java_wrapper->java_obj;

    if (jaApplet && (*jEnv)->IsInstanceOf(jEnv, java_obj, jaApplet)) {
        jsj_JSIsCallingApplet = JS_TRUE;
    }

    result = jsj_SetJavaFieldValue(cx, jEnv, member_descriptor->field, java_obj, *vp);
    jsj_ExitJava(jsj_env);
    return result;

no_such_field:
    JS_IdToValue(cx, id, &idval);
    member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));
    class_descriptor = java_wrapper->class_descriptor;
    JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL,
                         JSJMSG_NO_NAME_IN_CLASS,
                         member_name, class_descriptor->name);
    jsj_ExitJava(jsj_env);
    return JS_FALSE;
}

Here is the call graph for this function:

Definition at line 1087 of file jsj_JavaObject.c.

{
    return JS_InitClass(cx, global_obj,
                        0, &JavaObject_class, 0, 0,
                        0, 0,
                        0, 0) != 0;
}

Here is the call graph for this function:

Definition at line 346 of file jsj_JavaObject.c.

{
    JSJavaThreadState *jsj_env;
    char *err_msg;

    /* Get the per-thread state corresponding to the current Java thread */
    jsj_env = jsj_MapJavaThreadToJSJavaThreadState(jEnv, &err_msg);
    JS_ASSERT(jsj_env);
    if (!jsj_env)
        return;

    if (java_obj_reflections) {
        JSJ_HashTableEnumerateEntries(java_obj_reflections,
                                      enumerate_remove_java_obj,
                                      (void*)jsj_env);
        JSJ_HashTableDestroy(java_obj_reflections);
        java_obj_reflections = NULL;
    }
}

Here is the call graph for this function:

Here is the caller graph for this function:

static JSBool JS_DLL_CALLBACK jsj_GC_callback ( JSContext cx,
JSGCStatus  status 
) [static]

Definition at line 93 of file jsj_JavaObject.c.

{
    if (status == JSGC_END && deferred_wrappers) {
        JNIEnv *jEnv;
        JSJavaThreadState *jsj_env = jsj_EnterJava(cx, &jEnv);
        if (jEnv) {
            JavaObjectWrapper* java_wrapper = deferred_wrappers;
            while (java_wrapper) {
                deferred_wrappers = java_wrapper->u.next;
                if (java_wrapper->java_obj)
                    (*jEnv)->DeleteGlobalRef(jEnv, java_wrapper->java_obj);
                jsj_ReleaseJavaClassDescriptor(cx, jEnv, java_wrapper->class_descriptor);
                JS_free(cx, java_wrapper);
                java_wrapper = deferred_wrappers;
            }
            jsj_ExitJava(jsj_env);
        }
    }
    /* always chain to old GC callback if non-null. */
    return old_GC_callback ? old_GC_callback(cx, status) : JS_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 116 of file jsj_JavaObject.c.

{
    JS_ASSERT(!java_obj_reflections);

    java_obj_reflections =
        JSJ_NewHashTable(512, jsj_HashJavaObject, jsj_JavaObjectComparator,
                         NULL, NULL, NULL);
    if (!java_obj_reflections)
        return JS_FALSE;

#ifdef JSJ_THREADSAFE
    java_obj_reflections_monitor = (struct PRMonitor *) PR_NewMonitor();
    if (!java_obj_reflections_monitor) {
        JSJ_HashTableDestroy(java_obj_reflections);
        return JS_FALSE;
    }
#endif

    return JS_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

JSObject* jsj_WrapJavaObject ( JSContext cx,
JNIEnv jEnv,
jobject  java_obj,
jclass  java_class 
)

Definition at line 138 of file jsj_JavaObject.c.

{
    JSJHashNumber hash_code;
    JSClass *js_class;
    JSObject *js_wrapper_obj;
    JavaObjectWrapper *java_wrapper;
    JavaClassDescriptor *class_descriptor;
    JSJHashEntry *he, **hep;

#ifdef JSJ_THREADSAFE
    int mutation_count;
#endif

    js_wrapper_obj = NULL;

    hash_code = jsj_HashJavaObject((void*)java_obj, (void*)jEnv);

#ifdef JSJ_THREADSAFE
    PR_EnterMonitor(java_obj_reflections_monitor);
#endif

    if (!installed_GC_callback) {
        /*
         * Hook into GC callback mechanism, so we can defer deleting global
         * references until it's safe.
         */
        old_GC_callback =  JS_SetGCCallback(cx, jsj_GC_callback);
        installed_GC_callback = JS_TRUE;
    }

    hep = JSJ_HashTableRawLookup(java_obj_reflections,
                                 hash_code, java_obj, (void*)jEnv);
    he = *hep;

#ifdef JSJ_THREADSAFE
    /* Track mutations to hash table */
    mutation_count = java_obj_reflections_mutation_count;

    /* We must temporarily release this monitor so as to avoid
       deadlocks with the JS GC.  See Bugsplat #354852 */
    PR_ExitMonitor(java_obj_reflections_monitor);
#endif

    if (he) {
        js_wrapper_obj = (JSObject *)he->value;
        if (js_wrapper_obj)
            return js_wrapper_obj;
    }

    /* No existing reflection found.  Construct a new one */
    class_descriptor = jsj_GetJavaClassDescriptor(cx, jEnv, java_class);
    if (!class_descriptor)
        return NULL;
    if (class_descriptor->type == JAVA_SIGNATURE_ARRAY) {
        js_class = &JavaArray_class;
    } else {
        JS_ASSERT(IS_OBJECT_TYPE(class_descriptor->type));
        js_class = &JavaObject_class;
    }

    /* Create new JS object to reflect Java object */
    js_wrapper_obj = JS_NewObject(cx, js_class, NULL, NULL);
    if (!js_wrapper_obj)
        return NULL;

    /* Create private, native portion of JavaObject */
    java_wrapper =
        (JavaObjectWrapper *)JS_malloc(cx, sizeof(JavaObjectWrapper));
    if (!java_wrapper) {
        jsj_ReleaseJavaClassDescriptor(cx, jEnv, class_descriptor);
        return NULL;
    }
    JS_SetPrivate(cx, js_wrapper_obj, java_wrapper);
    java_wrapper->class_descriptor = class_descriptor;
    java_wrapper->java_obj = NULL;

#ifdef JSJ_THREADSAFE
    PR_EnterMonitor(java_obj_reflections_monitor);

    /* We may need to do the hash table lookup again, since some other
       thread may have updated it while the lock wasn't being held. */
    if (mutation_count != java_obj_reflections_mutation_count) {
        hep = JSJ_HashTableRawLookup(java_obj_reflections,
                                     hash_code, java_obj, (void*)jEnv);
        he = *hep;
        if (he) {
            js_wrapper_obj = (JSObject *)he->value;
            if (js_wrapper_obj) {
                PR_ExitMonitor(java_obj_reflections_monitor);
                return js_wrapper_obj;
            }
        }
    }

    java_obj_reflections_mutation_count++;

#endif

    java_obj = (*jEnv)->NewGlobalRef(jEnv, java_obj);
    java_wrapper->java_obj = java_obj;
    if (!java_obj)
        goto out_of_memory;

    /* cache the hash code for all time. */
    java_wrapper->u.hash_code = hash_code;

    /* Add the JavaObject to the hash table */
    he = JSJ_HashTableRawAdd(java_obj_reflections, hep, hash_code,
                             java_obj, js_wrapper_obj, (void*)jEnv);
#ifdef JSJ_THREADSAFE
    PR_ExitMonitor(java_obj_reflections_monitor);
#endif

    if (!he) {
        (*jEnv)->DeleteGlobalRef(jEnv, java_obj);
        goto out_of_memory;
    }

    return js_wrapper_obj;

out_of_memory:
    /* No need to free js_wrapper_obj, as it will be finalized by GC. */
    JS_ReportOutOfMemory(cx);
    return NULL;
}

Here is the call graph for this function:

Here is the caller graph for this function:

Definition at line 1009 of file jsj_JavaObject.c.

{
    JS_free(cx, map);
}

Here is the call graph for this function:

Definition at line 1015 of file jsj_JavaObject.c.

Definition at line 993 of file jsj_JavaObject.c.

{
    JSObjectMap * map;

    map = (JSObjectMap *) JS_malloc(cx, sizeof(JSObjectMap));
    if (map) {
        map->nrefs = nrefs;
        map->ops = ops;
        map->nslots = JSJ_SLOT_COUNT;
        map->freeslot = JSJ_SLOT_COUNT;
    }
    return map;
}

Here is the call graph for this function:

Definition at line 1025 of file jsj_JavaObject.c.

static JSBool lookup_member_by_id ( JSContext cx,
JNIEnv jEnv,
JSObject obj,
JavaObjectWrapper **  java_wrapperp,
jsid  id,
JavaMemberDescriptor **  member_descriptorp,
jsval vp,
JSObject **  proto_chainp,
JSJPropertyInfo prop_infop 
) [static]

Definition at line 481 of file jsj_JavaObject.c.

{
    jsval idval;
    JavaObjectWrapper *java_wrapper;
    JavaMemberDescriptor *member_descriptor;
    const char *member_name;
    JavaClassDescriptor *class_descriptor;
    JSObject *proto_chain;
    JSBool found_in_proto;

    found_in_proto = JS_FALSE;
    member_descriptor = NULL;
    java_wrapper = JS_GetPrivate(cx, obj);

    /* Handle accesses to prototype object */
    if (!java_wrapper) {
        if (JS_IdToValue(cx, id, &idval) && JSVAL_IS_STRING(idval) &&
            (member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval))) != NULL) {
            if (!strcmp(member_name, "constructor"))
                goto done;
        }
        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_OP_JOBJECT);
        return JS_FALSE;
    }

    class_descriptor = java_wrapper->class_descriptor;
    JS_ASSERT(IS_REFERENCE_TYPE(class_descriptor->type));

    member_descriptor = jsj_LookupJavaMemberDescriptorById(cx, jEnv, class_descriptor, id);
    if (member_descriptor)
        goto done;

    /* Instances can reference static methods and fields */
    member_descriptor = jsj_LookupJavaStaticMemberDescriptorById(cx, jEnv, class_descriptor, id);
    if (member_descriptor)
        goto done;

    /* Ensure that the property we're searching for is string-valued. */
    JS_IdToValue(cx, id, &idval);
    if (!JSVAL_IS_STRING(idval)) {
        JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_BAD_JOBJECT_EXPR);
        return JS_FALSE;
    }
    member_name = JS_GetStringBytes(JSVAL_TO_STRING(idval));

    /*
     * A little LC3 feature magic:
     *   + Instances of java.lang.String "inherit" the standard ECMA string methods
     *     of String.prototype.  All of the ECMA string methods convert the Java
     *     string to a JS string before performing the string operation.  For example,
     *         s = new java.lang.String("foobar");
     *         return s.slice(2);
     *   + Similarly, instances of Java arrays "inherit" the standard ECMA array
     *     methods of Array.prototype.  (Not all of these methods work properly
     *     on JavaArray objects, however, since the 'length' property is read-only.)
     */
    if (vp) {
        if ((class_descriptor->type == JAVA_SIGNATURE_JAVA_LANG_STRING) &&
            inherit_props_from_JS_natives(cx, "String", member_name, vp))
            goto done;
        if ((class_descriptor->type == JAVA_SIGNATURE_ARRAY) &&
            inherit_props_from_JS_natives(cx, "Array", member_name, vp))
            goto done;
    }

    /* Check for access to magic prototype chain property */
    if (!strcmp(member_name, "__proto__")) {
        proto_chain = JS_GetPrototype(cx, obj);
        if (vp)
            *vp = OBJECT_TO_JSVAL(proto_chain);
        goto done;
    }

    /*
     * See if the property looks like the explicit resolution of an
     * overloaded method, e.g. "max(double,double)", first as an instance method,
     * then as a static method.  If we find such a method, it will be cached
     * so future accesses won't run this code.
     */
    member_descriptor = jsj_ResolveExplicitMethod(cx, jEnv, class_descriptor, id, JS_FALSE);
    if (member_descriptor)
        goto done;
    member_descriptor = jsj_ResolveExplicitMethod(cx, jEnv, class_descriptor, id, JS_TRUE);
    if (member_descriptor)
        goto done;

    /* Is the property defined in the prototype chain? */
    if (proto_chainp && prop_infop) {
        /* If so, follow __proto__ link to search prototype chain */
        proto_chain = JS_GetPrototype(cx, obj);

        /* Use OBJ_LOOKUP_PROPERTY to determine if and where the property
           actually exists in the prototype chain. */
        if (proto_chain) {
            if (!OBJ_LOOKUP_PROPERTY(cx, proto_chain, id, proto_chainp,
                                     &prop_infop->prop)) {
                return JS_FALSE;
            }
            if (prop_infop->prop) {
                if (!OBJ_GET_ATTRIBUTES(cx, *proto_chainp, id, prop_infop->prop,
                                        &prop_infop->attributes)) {
                    OBJ_DROP_PROPERTY(cx, *proto_chainp, prop_infop->prop);
                    return JS_FALSE;
                }
                if (!prop_infop->wantProp) {
                    OBJ_DROP_PROPERTY(cx, *proto_chainp, prop_infop->prop);
                    prop_infop->prop = NULL;
                }
                prop_infop->name = member_name;
                found_in_proto = JS_TRUE;
                goto done;
            }
        }
    }

    /* Report lack of Java member with the given property name */
    JS_ReportErrorNumber(cx, jsj_GetErrorMessage, NULL, JSJMSG_NO_INSTANCE_NAME,
                         class_descriptor->name, member_name);
    return JS_FALSE;

done:
    /* Success.  Handle the multiple return values */
    if (java_wrapperp)
        *java_wrapperp = java_wrapper;
    if (member_descriptorp)
        *member_descriptorp = member_descriptor;
    if (proto_chainp && !found_in_proto)
        *proto_chainp = NULL;
    return JS_TRUE;
}

Here is the call graph for this function:

Here is the caller graph for this function:

static void remove_java_obj_reflection_from_hashtable ( jobject  java_obj,
JSJHashNumber  hash_code 
) [static]

Definition at line 268 of file jsj_JavaObject.c.

{
    JSJHashEntry *he, **hep;

#ifdef JSJ_THREADSAFE
    PR_EnterMonitor(java_obj_reflections_monitor);
#endif

    hep = JSJ_HashTableRawLookup(java_obj_reflections, hash_code,
                                 java_obj, NULL);
    he = *hep;

    JS_ASSERT(he);
    if (he)
        JSJ_HashTableRawRemove(java_obj_reflections, hep, he, NULL);

#ifdef JSJ_THREADSAFE
    java_obj_reflections_mutation_count++;

    PR_ExitMonitor(java_obj_reflections_monitor);
#endif
}

Here is the call graph for this function:

Here is the caller graph for this function:


Variable Documentation

Definition at line 91 of file jsj_JavaObject.c.

Definition at line 89 of file jsj_JavaObject.c.

Definition at line 82 of file jsj_JavaObject.c.

Initial value:

Definition at line 1071 of file jsj_JavaObject.c.

JSGCCallback old_GC_callback = NULL [static]

Definition at line 90 of file jsj_JavaObject.c.