Implemented new JNI abstraction. We no longer invoke Java methods
directly with JNI, rather we call into the plugin. This allows the
plugin to dispatch the call to the appropriate VM thread. This
change should (will?) fix a whole class of threading related problems with
the Java VM.
Reviewed by Hyatt.
* WebCoreSupport.subproj/WebBridge.m:
(-[WebBridge getAppletInView:]):
WebCore:
Implemented new JNI abstraction. We no longer invoke Java methods
directly with JNI, rather we call into the plugin. This allows the
plugin to dispatch the call to the appropriate VM thread. This
change should (will?) fix a whole class of threading related problems with
the Java VM.
Reviewed by Hyatt.
* kwq/KWQKHTMLPart.mm:
(KWQKHTMLPart::getAppletInstanceForView):
* kwq/WebCoreBridge.mm:
(rootForView):
(-[WebCoreBridge executionContextForView:]):
JavaScriptCore:
Implemented new JNI abstraction. We no longer invoke Java methods
directly with JNI, rather we call into the plugin. This allows the
plugin to dispatch the call to the appropriate VM thread. This
change should (will?) fix a whole class of threading related problems with
the Java VM.
Reviewed by Hyatt.
* JavaScriptCore.pbproj/project.pbxproj:
* bindings/c/c_instance.h:
(KJS::Bindings::CInstance::setExecutionContext):
(KJS::Bindings::CInstance::executionContext):
* bindings/jni/jni_instance.cpp:
(JavaInstance::JavaInstance):
(JavaInstance::invokeMethod):
(JavaInstance::setExecutionContext):
(JavaInstance::executionContext):
* bindings/jni/jni_instance.h:
* bindings/jni/jni_jsobject.cpp:
(JSObject::convertJObjectToValue):
* bindings/jni/jni_runtime.cpp:
(JavaField::JavaField):
(JavaArray::convertJObjectToArray):
(JavaField::valueFromInstance):
(JavaArray::JavaArray):
(JavaArray::valueAt):
* bindings/jni/jni_runtime.h:
(KJS::Bindings::JavaArray::operator=):
(KJS::Bindings::JavaArray::executionContext):
* bindings/jni/jni_utility.h:
* bindings/objc/objc_instance.h:
(KJS::Bindings::ObjcInstance::setExecutionContext):
(KJS::Bindings::ObjcInstance::executionContext):
* bindings/runtime.cpp:
(Instance::createBindingForLanguageInstance):
* bindings/runtime.h:
* bindings/runtime_root.h:
(KJS::Bindings::RootObject::nativeHandle):
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@7316
268f45cc-cd09-0410-ab3c-
d52691b4dbfc
+2004-08-20 Richard Williamson <rjw@apple.com>
+
+ Implemented new JNI abstraction. We no longer invoke Java methods
+ directly with JNI, rather we call into the plugin. This allows the
+ plugin to dispatch the call to the appropriate VM thread. This
+ change should (will?) fix a whole class of threading related problems with
+ the Java VM.
+
+ Reviewed by Hyatt.
+
+ * JavaScriptCore.pbproj/project.pbxproj:
+ * bindings/c/c_instance.h:
+ (KJS::Bindings::CInstance::setExecutionContext):
+ (KJS::Bindings::CInstance::executionContext):
+ * bindings/jni/jni_instance.cpp:
+ (JavaInstance::JavaInstance):
+ (JavaInstance::invokeMethod):
+ (JavaInstance::setExecutionContext):
+ (JavaInstance::executionContext):
+ * bindings/jni/jni_instance.h:
+ * bindings/jni/jni_jsobject.cpp:
+ (JSObject::convertJObjectToValue):
+ * bindings/jni/jni_runtime.cpp:
+ (JavaField::JavaField):
+ (JavaArray::convertJObjectToArray):
+ (JavaField::valueFromInstance):
+ (JavaArray::JavaArray):
+ (JavaArray::valueAt):
+ * bindings/jni/jni_runtime.h:
+ (KJS::Bindings::JavaArray::operator=):
+ (KJS::Bindings::JavaArray::executionContext):
+ * bindings/jni/jni_utility.h:
+ * bindings/objc/objc_instance.h:
+ (KJS::Bindings::ObjcInstance::setExecutionContext):
+ (KJS::Bindings::ObjcInstance::executionContext):
+ * bindings/runtime.cpp:
+ (Instance::createBindingForLanguageInstance):
+ * bindings/runtime.h:
+ * bindings/runtime_root.h:
+ (KJS::Bindings::RootObject::nativeHandle):
+
=== Safari-158 ===
2004-08-19 Vicki Murley <vicki@apple.com>
65AB004A06261CBA0076DE63,
650B68DA0639033F009D42DE,
51863FC506542D3100E9E8DD,
+ 517EF37406D695930007C1BA,
);
isa = PBXSourcesBuildPhase;
runOnlyForDeploymentPostprocessing = 0;
);
};
};
+ 517EF37306D695930007C1BA = {
+ fileEncoding = 30;
+ isa = PBXFileReference;
+ lastKnownFileType = sourcecode.cpp.objcpp;
+ name = jni_objc.mm;
+ path = bindings/jni/jni_objc.mm;
+ refType = 4;
+ sourceTree = "<group>";
+ };
+ 517EF37406D695930007C1BA = {
+ fileRef = 517EF37306D695930007C1BA;
+ isa = PBXBuildFile;
+ settings = {
+ };
+ };
5182A45605FFCF4B00CBD2F2 = {
fileEncoding = 30;
isa = PBXFileReference;
517D5348056BFB5D003851BD,
513DF74005C0861F00F89391,
513DF74105C0861F00F89391,
+ 517EF37306D695930007C1BA,
511B0877056468BB0080E486,
511B0876056468BB0080E486,
51856D8F0562EE95008B9D83,
KJS::Value booleanValue() const;
NPObject *getObject() const { return _object; }
+
+ void setExecutionContext (RootObject *r) { _root = r; }
+ const RootObject *executionContext() const { return _root; }
private:
mutable CClass *_class;
NPObject *_object;
+ RootObject *_root;
};
} // namespace Bindings
#include <jni_runtime.h>
#include <jni_utility.h>
#include <runtime_object.h>
+#include <runtime_root.h>
#ifdef NDEBUG
#define JS_LOG(formatAndArgs...) ((void)0)
using namespace KJS::Bindings;
using namespace KJS;
-JavaInstance::JavaInstance (jobject instance)
+JavaInstance::JavaInstance (jobject instance, const RootObject *r)
{
_instance = new JObjectWrapper (instance);
_class = 0;
+ _root = r;
};
JavaInstance::~JavaInstance ()
_instance->ref();
// Classes are kept around forever.
_class = other._class;
+ _root = other._root;
};
#define NUM_LOCAL_REFS 64
JavaParameter *aParameter = static_cast<JavaParameter *>(jMethod->parameterAt(i));
jArgs[i] = convertValueToJValue (exec, args.at(i), aParameter->getJNIType(), aParameter->type());
}
-
+
+
jvalue result;
- jobject obj = _instance->_instance;
+
+ // Try to use the JNI abstraction first, otherwise fall back to
+ // nornmal JNI. The JNI dispatch abstraction allows the Java plugin
+ // to dispatch the call on the appropriate internal VM thread.
+ const RootObject *execContext = executionContext();
+ bool handled = false;
+ if (execContext && execContext->nativeHandle()) {
+ jobject obj = _instance->_instance;
+ handled = dispatchJNICall (execContext->nativeHandle(), obj, jMethod->methodID(obj), jMethod->JNIReturnType(), jArgs, result);
+ }
+
+ // The following code can be conditionally removed once we have a Tiger update that
+ // contains the new Java plugin. It is needed for builds prior to Tiger.
+ if (!handled) {
+ jobject obj = _instance->_instance;
+ switch (jMethod->JNIReturnType()){
+ case void_type: {
+ callJNIVoidMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case object_type: {
+ result.l = callJNIObjectMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case boolean_type: {
+ result.z = callJNIBooleanMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case byte_type: {
+ result.b = callJNIByteMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case char_type: {
+ result.c = callJNICharMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case short_type: {
+ result.s = callJNIShortMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case int_type: {
+ result.i = callJNIIntMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case long_type: {
+ result.j = callJNILongMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case float_type: {
+ result.f = callJNIFloatMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case double_type: {
+ result.d = callJNIDoubleMethodIDA (obj, jMethod->methodID(obj), jArgs);
+ }
+ break;
+
+ case invalid_type:
+ default: {
+ }
+ break;
+ }
+ }
+
switch (jMethod->JNIReturnType()){
case void_type: {
- callJNIVoidMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Undefined();
}
break;
case object_type: {
- result.l = callJNIObjectMethodIDA (obj, jMethod->methodID(obj), jArgs);
if (result.l != 0) {
const char *arrayType = jMethod->returnType();
if (arrayType[0] == '[') {
- resultValue = JavaArray::convertJObjectToArray (exec, result.l, arrayType);
+ resultValue = JavaArray::convertJObjectToArray (exec, result.l, arrayType, executionContext());
}
else {
- resultValue = Object(new RuntimeObjectImp(new JavaInstance (result.l)));
+ resultValue = Object(new RuntimeObjectImp(new JavaInstance (result.l, executionContext())));
}
}
else {
break;
case boolean_type: {
- result.z = callJNIBooleanMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = KJS::Boolean(result.z);
}
break;
case byte_type: {
- result.b = callJNIByteMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Number(result.b);
}
break;
case char_type: {
- result.c = callJNICharMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Number(result.c);
}
break;
case short_type: {
- result.s = callJNIShortMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Number(result.s);
}
break;
case int_type: {
- result.i = callJNIIntMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Number(result.i);
}
break;
case long_type: {
- result.j = callJNILongMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Number((long int)result.j);
}
break;
case float_type: {
- result.f = callJNIFloatMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Number(result.f);
}
break;
case double_type: {
- result.d = callJNIDoubleMethodIDA (obj, jMethod->methodID(obj), jArgs);
resultValue = Number(result.d);
}
break;
}
break;
}
-
+
free (jArgs);
return resultValue;
return stringValue();
};
+void JavaInstance::setExecutionContext (RootObject *r) { _root = r; }
+const RootObject *JavaInstance::executionContext() const { return _root; }
+
JObjectWrapper::JObjectWrapper(jobject instance)
{
assert (instance != 0);
class JavaInstance : public Instance
{
public:
- JavaInstance (jobject instance);
+ JavaInstance (jobject instance, const RootObject *r);
~JavaInstance ();
virtual KJS::Value invokeMethod (KJS::ExecState *exec, const MethodList &method, const KJS::List &args);
+ virtual void setExecutionContext (RootObject *r);
+ virtual const RootObject *executionContext() const;
+
jobject javaInstance() const { return _instance->_instance; }
KJS::Value stringValue() const;
KJS::Value numberValue() const;
KJS::Value booleanValue() const;
-
+
private:
JObjectWrapper *_instance;
- mutable JavaClass *_class;
+ mutable JavaClass *_class;
+ const RootObject *_root;
};
} // namespace Bindings
}
Interpreter::lock();
- KJS::RuntimeObjectImp *newImp = new KJS::RuntimeObjectImp(new Bindings::JavaInstance (theObject));
+ KJS::RuntimeObjectImp *newImp = new KJS::RuntimeObjectImp(new Bindings::JavaInstance (theObject, _root));
Interpreter::unlock();
return KJS::Object(newImp);
jstring fieldName = (jstring)callJNIObjectMethod (aField, "getName", "()Ljava/lang/String;");
_name = JavaString(env, fieldName);
- _field = new JavaInstance(aField);
+ _field = new JavaInstance(aField, 0);
}
-KJS::Value JavaArray::convertJObjectToArray (KJS::ExecState *exec, jobject anObject, const char *type)
+KJS::Value JavaArray::convertJObjectToArray (KJS::ExecState *exec, jobject anObject, const char *type, const RootObject *r)
{
if (type[0] != '[')
return Undefined();
- return KJS::Object(new RuntimeArrayImp(exec, new JavaArray ((jobject)anObject, type)));
+ return KJS::Object(new RuntimeArrayImp(exec, new JavaArray ((jobject)anObject, type, r)));
}
KJS::Value JavaField::valueFromInstance(KJS::ExecState *exec, const Instance *i) const
const char *arrayType = type();
if (arrayType[0] == '[') {
- return JavaArray::convertJObjectToArray (0, anObject, arrayType);
+ return JavaArray::convertJObjectToArray (exec, anObject, arrayType, instance->executionContext());
}
else {
- return KJS::Object(new RuntimeObjectImp(new JavaInstance ((jobject)anObject)));
+ return KJS::Object(new RuntimeObjectImp(new JavaInstance ((jobject)anObject, instance->executionContext())));
}
}
break;
}
-JavaArray::JavaArray (jobject a, const char *t)
+JavaArray::JavaArray (jobject a, const char *t, const RootObject *r)
{
_array = new JObjectWrapper (a);
// Java array are fixed length, so we can cache length.
JNIEnv *env = getJNIEnv();
_length = env->GetArrayLength((jarray)_array->_instance);
-
_type = strdup(t);
+ _root = r;
};
JavaArray::~JavaArray ()
// Nested array?
if (_type[1] == '[') {
- return JavaArray::convertJObjectToArray (0, anObject, _type+1);
+ return JavaArray::convertJObjectToArray (exec, anObject, _type+1, executionContext());
}
// or array of other object type?
- return KJS::Object(new RuntimeObjectImp(new JavaInstance ((jobject)anObject)));
+ return KJS::Object(new RuntimeObjectImp(new JavaInstance ((jobject)anObject, executionContext())));
}
case boolean_type: {
class JavaArray : public Array
{
public:
- JavaArray (jobject a, const char *type);
+ JavaArray (jobject a, const char *type, const RootObject *r);
JavaArray (const JavaArray &other);
free ((void *)_type);
_type = strdup(other._type);
+ _root = other._root;
JObjectWrapper *_oldArray = _array;
_array = other._array;
jobject javaArray() const { return _array->_instance; }
- static KJS::Value convertJObjectToArray (KJS::ExecState *exec, jobject anObject, const char *type);
+ static KJS::Value convertJObjectToArray (KJS::ExecState *exec, jobject anObject, const char *type, const RootObject *r);
+ const RootObject *executionContext() const { return _root; }
+
private:
JObjectWrapper *_array;
unsigned int _length;
const char *_type;
+ const RootObject *_root;
};
} // namespace Bindings
JavaVM *getJavaVM();
JNIEnv *getJNIEnv();
+bool dispatchJNICall (const void *targetAppletView, jobject obj, jmethodID methodID, JNIType returnType, jvalue *args, jvalue &result);
+
} // namespace Bindings
} // namespace KJS
KJS::Value numberValue() const;
KJS::Value booleanValue() const;
+ void setExecutionContext (RootObject *r) { _root = r; }
+ const RootObject *executionContext() const { return _root; }
+
private:
ObjectStructPtr _instance;
mutable ObjcClass *_class;
ObjectStructPtr _pool;
long _beginCount;
+ RootObject *_root;
};
} // namespace Bindings
Instance *Instance::createBindingForLanguageInstance (BindingLanguage language, void *instance)
{
if (language == Instance::JavaLanguage)
- return new Bindings::JavaInstance ((jobject)instance);
+ return new Bindings::JavaInstance ((jobject)instance, 0);
else if (language == Instance::ObjectiveCLanguage)
return new Bindings::ObjcInstance ((struct objc_object *)instance);
virtual KJS::Value valueOf() const { return KJS::String(getClass()->name()); };
+ virtual void setExecutionContext (RootObject *r) = 0;
+ virtual const RootObject *executionContext () const = 0;
+
virtual ~Instance() {};
+
+private:
};
class Array
static void dispatchToJavaScriptThread(JSObjectCallContext *context);
+ const void *nativeHandle() const { return _nativeHandle; }
+
private:
const void *_nativeHandle;
KJS::ObjectImp *_imp;
+2004-08-20 Richard Williamson <rjw@apple.com>
+
+ Implemented new JNI abstraction. We no longer invoke Java methods
+ directly with JNI, rather we call into the plugin. This allows the
+ plugin to dispatch the call to the appropriate VM thread. This
+ change should (will?) fix a whole class of threading related problems with
+ the Java VM.
+
+ Reviewed by Hyatt.
+
+ * kwq/KWQKHTMLPart.mm:
+ (KWQKHTMLPart::getAppletInstanceForView):
+ * kwq/WebCoreBridge.mm:
+ (rootForView):
+ (-[WebCoreBridge executionContextForView:]):
+
2004-08-19 Maciej Stachowiak <mjs@apple.com>
Reviewed by Darin.
else
applet = [_bridge pollForAppletInView:aView];
- if (applet)
+ if (applet) {
// Wrap the Java instance in a language neutral binding and hand
// off ownership to the APPLET element.
- return KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::JavaLanguage, applet);
+ KJS::Bindings::Instance *instance = KJS::Bindings::Instance::createBindingForLanguageInstance (KJS::Bindings::Instance::JavaLanguage, applet);
+
+ KJS::Bindings::RootObject *root = KJS::Bindings::RootObject::findRootObjectForNativeHandleFunction ()(aView);
+ instance->setExecutionContext (root);
+
+ return instance;
+ }
return 0;
}
NSString *WebCorePageCacheStateKey = @"WebCorePageCacheState";
+@interface WebCoreBridge (WebCoreBridgePrivate)
+- (RootObject *)executionContextForView:(NSView *)aView;
+@end
+
static RootObject *rootForView(void *v)
{
NSView *aView = (NSView *)v;
WebCoreBridge *aBridge = [[WebCoreViewFactory sharedFactory] bridgeForView:aView];
- if (aBridge) {
- KWQKHTMLPart *part = [aBridge part];
- RootObject *root = new RootObject(v); // The root gets deleted by JavaScriptCore.
-
- root->setRootObjectImp (static_cast<KJS::ObjectImp *>(KJS::Window::retrieveWindow(part)));
- root->setInterpreter (KJSProxy::proxy(part)->interpreter());
- part->addPluginRootObject (root);
-
- return root;
- }
+
+ if (aBridge)
+ return [aBridge executionContextForView:aView];
+
return 0;
}
}
@end
+
+
+@implementation WebCoreBridge (WebCoreBridgePrivate)
+
+- (RootObject *)executionContextForView:(NSView *)aView
+{
+ RootObject *root;
+
+ KWQKHTMLPart *part = [self part];
+ root = new RootObject(aView); // The root gets deleted by JavaScriptCore.
+ root->setRootObjectImp (static_cast<KJS::ObjectImp *>(KJS::Window::retrieveWindow(part)));
+ root->setInterpreter (KJSProxy::proxy(part)->interpreter());
+ part->addPluginRootObject (root);
+
+ return root;
+}
+@end
+2004-08-20 Richard Williamson <rjw@apple.com>
+
+ Implemented new JNI abstraction. We no longer invoke Java methods
+ directly with JNI, rather we call into the plugin. This allows the
+ plugin to dispatch the call to the appropriate VM thread. This
+ change should (will?) fix a whole class of threading related problems with
+ the Java VM.
+
+ Reviewed by Hyatt.
+
+ * WebCoreSupport.subproj/WebBridge.m:
+ (-[WebBridge getAppletInView:]):
+
2004-08-20 Trey Matteson <trey@apple.com>
3655407 - Editing: -complete: method unimplemented (WebKit editing API)
{
jobject applet = 0;
- if ([view respondsToSelector: @selector(webPlugInGetApplet:)])
+ if ([view respondsToSelector: @selector(webPlugInGetApplet)])
applet = [view webPlugInGetApplet];
else
applet = [self pollForAppletInView:view];