#include <jni_jsobject.h>
#include <runtime_root.h>
using namespace KJS;
using namespace KJS::Bindings;
static CFMutableDictionaryRef referencesByRootDictionary = 0;
static CFMutableDictionaryRef getReferencesByRootDictionary()
{
if (!referencesByRootDictionary)
referencesByRootDictionary = CFDictionaryCreateMutable(NULL, 0, NULL, &kCFTypeDictionaryValueCallBacks);
return referencesByRootDictionary;
}
static CFMutableDictionaryRef getReferencesDictionary(const Bindings::RootObject *root)
{
CFMutableDictionaryRef refsByRoot = getReferencesByRootDictionary();
CFMutableDictionaryRef referencesDictionary = 0;
referencesDictionary = (CFMutableDictionaryRef)CFDictionaryGetValue (refsByRoot, (const void *)root);
if (!referencesDictionary) {
referencesDictionary = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
CFDictionaryAddValue (refsByRoot, root, referencesDictionary);
CFRelease (referencesDictionary);
}
return referencesDictionary;
}
CFMutableDictionaryRef KJS::Bindings::findReferenceDictionary(ObjectImp *imp)
{
CFMutableDictionaryRef refsByRoot = getReferencesByRootDictionary ();
CFMutableDictionaryRef foundDictionary = 0;
if (refsByRoot) {
const void **allValues = 0;
CFIndex count, i;
count = CFDictionaryGetCount(refsByRoot);
allValues = (const void **)malloc (sizeof(void *) * count);
CFDictionaryGetKeysAndValues (refsByRoot, NULL, allValues);
for(i = 0; i < count; i++) {
CFMutableDictionaryRef referencesDictionary = (CFMutableDictionaryRef)allValues[i];
if (CFDictionaryGetValue(referencesDictionary, imp) != 0) {
foundDictionary = referencesDictionary;
break;
}
}
free ((void *)allValues);
}
return foundDictionary;
}
const Bindings::RootObject *KJS::Bindings::rootForImp (ObjectImp *imp)
{
CFMutableDictionaryRef refsByRoot = getReferencesByRootDictionary ();
const Bindings::RootObject *rootObject = 0;
if (refsByRoot) {
const void **allValues = 0;
const void **allKeys = 0;
CFIndex count, i;
count = CFDictionaryGetCount(refsByRoot);
allKeys = (const void **)malloc (sizeof(void *) * count);
allValues = (const void **)malloc (sizeof(void *) * count);
CFDictionaryGetKeysAndValues (refsByRoot, allKeys, allValues);
for(i = 0; i < count; i++) {
CFMutableDictionaryRef referencesDictionary = (CFMutableDictionaryRef)allValues[i];
if (CFDictionaryGetValue(referencesDictionary, imp) != 0) {
rootObject = (const Bindings::RootObject *)allKeys[i];
break;
}
}
free ((void *)allKeys);
free ((void *)allValues);
}
return rootObject;
}
const Bindings::RootObject *KJS::Bindings::rootForInterpreter (KJS::Interpreter *interpreter)
{
CFMutableDictionaryRef refsByRoot = getReferencesByRootDictionary ();
const Bindings::RootObject *aRootObject = 0, *result = 0;
if (refsByRoot) {
const void **allValues = 0;
const void **allKeys = 0;
CFIndex count, i;
count = CFDictionaryGetCount(refsByRoot);
allKeys = (const void **)malloc (sizeof(void *) * count);
allValues = (const void **)malloc (sizeof(void *) * count);
CFDictionaryGetKeysAndValues (refsByRoot, allKeys, allValues);
for(i = 0; i < count; i++) {
aRootObject = (const Bindings::RootObject *)allKeys[i];
if (aRootObject->interpreter() == interpreter) {
result = aRootObject;
break;
}
}
free ((void *)allKeys);
free ((void *)allValues);
}
return result;
}
void KJS::Bindings::addNativeReference (const Bindings::RootObject *root, ObjectImp *imp)
{
if (root) {
CFMutableDictionaryRef referencesDictionary = getReferencesDictionary (root);
unsigned int numReferences = (unsigned int)CFDictionaryGetValue (referencesDictionary, imp);
if (numReferences == 0) {
#if !USE_CONSERVATIVE_GC
imp->ref();
#endif
#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
InterpreterLock lock;
gcProtect(imp);
#endif
CFDictionaryAddValue (referencesDictionary, imp, (const void *)1);
}
else {
CFDictionaryReplaceValue (referencesDictionary, imp, (const void *)(numReferences+1));
}
}
}
void KJS::Bindings::removeNativeReference (ObjectImp *imp)
{
if (!imp)
return;
CFMutableDictionaryRef referencesDictionary = findReferenceDictionary (imp);
if (referencesDictionary) {
unsigned int numReferences = (unsigned int)CFDictionaryGetValue (referencesDictionary, imp);
if (numReferences == 1) {
#if !USE_CONSERVATIVE_GC
imp->deref();
#endif
#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
InterpreterLock lock;
gcUnprotect(imp);
#endif
CFDictionaryRemoveValue (referencesDictionary, imp);
}
else {
CFDictionaryReplaceValue (referencesDictionary, imp, (const void *)(numReferences-1));
}
}
}
static CFRunLoopSourceRef completionSource;
static void completedJavaScriptAccess (void *i);
static void completedJavaScriptAccess (void *i)
{
assert (CFRunLoopGetCurrent() != RootObject::runLoop());
JSObjectCallContext *callContext = (JSObjectCallContext *)i;
CFRunLoopRef runLoop = (CFRunLoopRef)callContext->originatingLoop;
assert (CFRunLoopGetCurrent() == runLoop);
CFRunLoopStop(runLoop);
}
static pthread_once_t javaScriptAccessLockOnce = PTHREAD_ONCE_INIT;
static pthread_mutex_t javaScriptAccessLock;
static int javaScriptAccessLockCount = 0;
static void initializeJavaScriptAccessLock()
{
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr);
pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE);
pthread_mutex_init(&javaScriptAccessLock, &attr);
}
static inline void lockJavaScriptAccess()
{
pthread_once(&javaScriptAccessLockOnce, initializeJavaScriptAccessLock);
pthread_mutex_lock(&javaScriptAccessLock);
javaScriptAccessLockCount++;
}
static inline void unlockJavaScriptAccess()
{
javaScriptAccessLockCount--;
pthread_mutex_unlock(&javaScriptAccessLock);
}
void RootObject::dispatchToJavaScriptThread(JSObjectCallContext *context)
{
lockJavaScriptAccess();
CFRunLoopRef currentRunLoop = CFRunLoopGetCurrent();
assert (currentRunLoop != RootObject::runLoop());
context->originatingLoop = currentRunLoop;
CFRunLoopSourceContext sourceContext = {0, context, NULL, NULL, NULL, NULL, NULL, NULL, NULL, completedJavaScriptAccess};
completionSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
CFRunLoopAddSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode);
CFRunLoopSourceSignal(RootObject::performJavaScriptSource());
if (CFRunLoopIsWaiting(RootObject::runLoop())) {
CFRunLoopWakeUp(RootObject::runLoop());
}
CFRunLoopRun ();
CFRunLoopRemoveSource(currentRunLoop, completionSource, kCFRunLoopDefaultMode);
CFRelease (completionSource);
unlockJavaScriptAccess();
}
static void performJavaScriptAccess(void *info);
static void performJavaScriptAccess(void *i)
{
assert (CFRunLoopGetCurrent() == RootObject::runLoop());
CFRunLoopSourceContext sourceContext;
CFRunLoopSourceGetContext (completionSource, &sourceContext);
JSObjectCallContext *callContext = (JSObjectCallContext *)sourceContext.info;
CFRunLoopRef originatingLoop = callContext->originatingLoop;
JSObject::invoke (callContext);
CFRunLoopSourceSignal (completionSource);
if (CFRunLoopIsWaiting(originatingLoop)) {
CFRunLoopWakeUp(originatingLoop);
}
}
FindRootObjectForNativeHandleFunctionPtr RootObject::_findRootObjectForNativeHandleFunctionPtr = 0;
CFRunLoopRef RootObject::_runLoop = 0;
CFRunLoopSourceRef RootObject::_performJavaScriptSource = 0;
void RootObject::setFindRootObjectForNativeHandleFunction(FindRootObjectForNativeHandleFunctionPtr aFunc) {
assert (_findRootObjectForNativeHandleFunctionPtr == 0);
_findRootObjectForNativeHandleFunctionPtr = aFunc;
_runLoop = (CFRunLoopRef)CFRetain (CFRunLoopGetCurrent ());
CFRunLoopSourceContext sourceContext = {0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, performJavaScriptAccess};
Bindings::RootObject::_performJavaScriptSource = CFRunLoopSourceCreate(NULL, 0, &sourceContext);
CFRunLoopAddSource(Bindings::RootObject::_runLoop, Bindings::RootObject::_performJavaScriptSource, kCFRunLoopDefaultMode);
}
void RootObject::removeAllNativeReferences ()
{
CFMutableDictionaryRef referencesDictionary = getReferencesDictionary (this);
if (referencesDictionary) {
void **allImps = 0;
CFIndex count, i;
count = CFDictionaryGetCount(referencesDictionary);
allImps = (void **)malloc (sizeof(void *) * count);
CFDictionaryGetKeysAndValues (referencesDictionary, (const void **)allImps, NULL);
for(i = 0; i < count; i++) {
#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
InterpreterLock lock;
#endif
ObjectImp *anImp = static_cast<ObjectImp*>(allImps[i]);
#if !USE_CONSERVATIVE_GC
anImp->deref();
#endif
#if USE_CONSERVATIVE_GC | TEST_CONSERVATIVE_GC
gcUnprotect(anImp);
#endif
}
free ((void *)allImps);
CFDictionaryRemoveAllValues (referencesDictionary);
CFMutableDictionaryRef refsByRoot = getReferencesByRootDictionary();
CFDictionaryRemoveValue (refsByRoot, (const void *)this);
delete this;
}
}
void RootObject::setInterpreter (KJS::Interpreter *i)
{
_interpreter = i;
}