📄 jsj_javaobject.c
字号:
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- * * ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is Mozilla Communicator client code, released * March 31, 1998. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * * Alternatively, the contents of this file may be used under the terms of * either of the GNU General Public License Version 2 or later (the "GPL"), * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * This Original Code has been modified by IBM Corporation. Modifications made * by IBM described herein are Copyright (c) International Business Machines * Corporation, 2000. * Modifications to Mozilla code or documentation identified per MPL Section 3.3 * * Date Modified by Description of modification * 04/20/2000 IBM Corp. OS/2 VisualAge build. * * ***** END LICENSE BLOCK ***** *//* * This file is part of the Java-vendor-neutral implementation of LiveConnect * * It contains the native code implementation of JS's JavaObject class. * * An instance of JavaObject is the JavaScript reflection of a Java object. * */#include <stdlib.h>#include <string.h>#include "jsobj.h"#include "jsj_private.h" /* LiveConnect internals */#include "jsj_hash.h" /* Hash table with Java object as key */#ifdef JSJ_THREADSAFE#include "prmon.h"#endif/* * This is a hash table that maps from Java objects to JS objects. * It is used to ensure that the same JS object is obtained when a Java * object is reflected more than once, so that JS object equality tests * work in the expected manner, i.e. the "==" and "===" operators. * * The table entry keys are Java objects (of type jobject) and the entry values * are JSObject pointers. Because the jobject type is an opaque handle and * not necessarily a pointer, the hashing and key comparison functions must * invoke the appropriate JVM functions. * * When the corresponding JS object instance is finalized, the entry is * removed from the table, and a Java GC root for the Java object is removed. */static JSJHashTable *java_obj_reflections = NULL;#ifdef JSJ_THREADSAFEstatic PRMonitor *java_obj_reflections_monitor = NULL;static int java_obj_reflections_mutation_count = 0;#endifstatic JSBool installed_GC_callback = JS_FALSE;static JSGCCallback old_GC_callback = NULL;static JavaObjectWrapper* deferred_wrappers = NULL;static JSBool JS_DLL_CALLBACK jsj_GC_callback(JSContext *cx, JSGCStatus status){ 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;}JSBooljsj_InitJavaObjReflectionsTable(void){ 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;}JSObject *jsj_WrapJavaObject(JSContext *cx, JNIEnv *jEnv, jobject java_obj, jclass java_class){ 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;}static voidremove_java_obj_reflection_from_hashtable(jobject java_obj, JSJHashNumber hash_code){ 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}JS_EXPORT_API(void)JavaObject_finalize(JSContext *cx, JSObject *obj){ 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; } }}/* Trivial helper for jsj_DiscardJavaObjReflections(), below */static JSIntnenumerate_remove_java_obj(JSJHashEntry *he, JSIntn i, void *arg){ 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;}/* This shutdown routine discards all JNI references to Java objects that have been reflected into JS, even if there are still references to them from JS. */voidjsj_DiscardJavaObjReflections(JNIEnv *jEnv){ 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; }}JSBool JS_DLL_CALLBACK
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -