diff -r 000000000000 -r 4f2f89ce4247 JavaScriptGlue/JavaScriptGlue.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/JavaScriptGlue/JavaScriptGlue.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,661 @@ +/* + * Copyright (C) 2005 Apple Computer, Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JavaScriptGlue.h" +#include "JSUtils.h" +#include "JSBase.h" +#include "JSObject.h" +#include "JSRun.h" +#include +#include + +static CFTypeRef sJSCFNullRef = 0; + +static void CFJSObjectDispose(void *data); +static JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName); +static void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue); +static CFTypeRef CFJSObjectCopyCFValue(void *data); +static UInt8 CFJSObjectEqual(void *data1, void *data2); +static CFArrayRef CFJSObjectCopyPropertyNames(void *data); + +void *JSCFRetain(CFAllocatorRef allocator, const void *value); +void JSCFRelease(CFAllocatorRef allocator, const void *value); + + +void JSSetCFNull(CFTypeRef nullRef) +{ + ReleaseCFType(sJSCFNullRef); + sJSCFNullRef = RetainCFType(nullRef); +} + +CFTypeRef JSGetCFNull(void) +{ + return sJSCFNullRef; +} + +/* + JSRetain +*/ +JSTypeRef JSRetain(JSTypeRef ref) +{ + if (ref) + { + JSBase* ptr = (JSBase*)ref; + ptr->Retain(); + } + return ref; +} + +/* + JSRelease +*/ +void JSRelease(JSTypeRef ref) +{ + if (ref) + { + JSBase* ptr = (JSBase*)ref; + ptr->Release(); + } +} + +/* + JSCopyDescription +*/ +CFStringRef JSCopyDescription(JSTypeRef ref) +{ + CFStringRef result = 0; + if (ref) + { + JSBase* ptr = (JSBase*)ref; + ptr->CopyDescription(); + } + return result; +} + +/* + JSEqual +*/ +UInt8 JSEqual(JSTypeRef ref1, JSTypeRef ref2) +{ + UInt8 result = false; + if (ref1 && ref2) + { + JSBase* ptr = (JSBase*)ref1; + result = ptr->Equal((JSBase*)ref2); + } + return result; +} + + +/* + JSGetTypeID +*/ +JSTypeID JSGetTypeID(JSTypeRef ref) +{ + JSTypeID result = kJSInvalidTypeID; + if (ref) + { + JSBase* ptr = (JSBase*)ref; + result = ptr->GetTypeID(); + } + return result; +} + + +/* + JSGetRetainCount +*/ +CFIndex JSGetRetainCount(JSTypeRef ref) +{ + CFIndex result = -1; + if (ref) + { + JSBase* ptr = (JSBase*)ref; + result = ptr->RetainCount(); + } + return result; +} + + + +/* + JSObjectCreate +*/ +JSObjectRef JSObjectCreate(void *data, JSObjectCallBacksPtr callBacks) +{ + JSObjectRef result = JSObjectCreateInternal(data, callBacks, 0, kJSUserObjectDataTypeUnknown); + return result; +} + +/* + JSObjectCreateInternal +*/ +JSObjectRef JSObjectCreateInternal(void *data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int type) +{ + JSObjectRef result = 0; + JSUserObject* ptr = new JSUserObject(callBacks, markProc, data, type); + result = (JSObjectRef)ptr; + return result; +} + +/* + JSObjectCopyCFValue +*/ +CFTypeRef JSObjectCopyCFValue(JSObjectRef ref) +{ + CFTypeRef result = 0; + JSUserObject* ptr = (JSUserObject*)ref; + if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) + { + result = ptr->CopyCFValue(); + } + return result; +} + +/* + JSObjectGetData +*/ +void *JSObjectGetData(JSObjectRef ref) +{ + void *result = 0; + JSUserObject* ptr = (JSUserObject*)ref; + if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) + { + result = ptr->GetData(); + } + return result; +} + + +/* + JSObjectCopyProperty +*/ +JSObjectRef JSObjectCopyProperty(JSObjectRef ref, CFStringRef propertyName) +{ + JSObjectRef result = 0; + JSUserObject* ptr = (JSUserObject*)ref; + if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) + { + result = (JSObjectRef)ptr->CopyProperty(propertyName); + } + return result; +} + + +/* + JSObjectSetProperty +*/ +void JSObjectSetProperty(JSObjectRef ref, CFStringRef propertyName, JSObjectRef value) +{ + JSUserObject* ptr = (JSUserObject*)ref; + if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) + { + ptr->SetProperty(propertyName, (JSUserObject*)value); + } +} + + +/* + JSObjectCallFunction +*/ +JSObjectRef JSObjectCallFunction(JSObjectRef ref, JSObjectRef thisObj, CFArrayRef args) +{ + JSObjectRef result = 0; + JSUserObject* ptr = (JSUserObject*)ref; + if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) + { + result = (JSObjectRef)ptr->CallFunction((JSUserObject*)thisObj, args); + } + return result; +} + + +/* + JSRunCreate +*/ +JSRunRef JSRunCreate(CFStringRef jsSource, JSFlags inFlags) +{ + initializeThreading(); + + JSRunRef result = 0; + if (jsSource) + { + JSGlueAPIEntry entry; + result = (JSRunRef) new JSRun(jsSource, inFlags); + } + return result; +} + +/* + JSRunCopySource +*/ +CFStringRef JSRunCopySource(JSRunRef ref) +{ + CFStringRef result = 0; + JSRun* ptr = (JSRun*)ref; + if (ptr) + { + result = UStringToCFString(ptr->GetSource()); + } + return result; +} + + +/* + JSRunCopyGlobalObject +*/ +JSObjectRef JSRunCopyGlobalObject(JSRunRef ref) +{ + JSObjectRef result = 0; + JSRun* ptr = (JSRun*)ref; + if (ptr) + { + JSGlobalObject* globalObject = ptr->GlobalObject(); + result = (JSObjectRef)KJSValueToJSObject(globalObject, globalObject->globalExec()); + } + return result; +} + +/* + JSRunEvaluate +*/ +JSObjectRef JSRunEvaluate(JSRunRef ref) +{ + JSObjectRef result = 0; + JSRun* ptr = (JSRun*)ref; + if (ptr) + { + JSGlueAPIEntry entry; + Completion completion = ptr->Evaluate(); + if (completion.isValueCompletion()) + { + result = (JSObjectRef)KJSValueToJSObject(completion.value(), ptr->GlobalObject()->globalExec()); + } + + if (completion.complType() == Throw) + { + JSFlags flags = ptr->Flags(); + if (flags & kJSFlagDebug) + { + CFTypeRef error = JSObjectCopyCFValue(result); + if (error) + { + CFShow(error); + CFRelease(error); + } + } + } + } + return result; +} + +/* + JSRunCheckSyntax + Return true if no syntax error +*/ +bool JSRunCheckSyntax(JSRunRef ref) +{ + bool result = false; + JSRun* ptr = (JSRun*)ref; + if (ptr) + { + JSGlueAPIEntry entry; + result = ptr->CheckSyntax(); + } + return result; +} + +/* + JSCollect - trigger garbage collection +*/ +void JSCollect() +{ + initializeThreading(); + + JSGlueAPIEntry entry; + Heap* heap = getThreadGlobalExecState()->heap(); + if (!heap->isBusy()) + heap->collectAllGarbage(); +} + +/* + JSTypeGetCFArrayCallBacks +*/ +void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks) +{ + if (outCallBacks) + { + outCallBacks->version = 1; + outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain; + outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease; + outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription; + outCallBacks->equal = (CFArrayEqualCallBack)JSEqual; + } +} + + +/* + JSCFRetain +*/ +void *JSCFRetain(CFAllocatorRef allocator, const void *value) +{ + JSRetain((JSTypeRef)value); + return (void*)value; +} + +/* + JSCFRelease +*/ +void JSCFRelease(CFAllocatorRef allocator, const void *value) +{ + JSRelease((JSTypeRef)value); +} + + +/* + JSObjectCreateWithCFType +*/ +JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef) +{ + JSObjectCallBacks callBacks; + JSObjectRef cfJSObject = nil; + if (inRef) + { + callBacks.dispose = CFJSObjectDispose; + callBacks.equal = CFJSObjectEqual; + callBacks.copyCFValue = CFJSObjectCopyCFValue; + callBacks.copyProperty = CFJSObjectCopyProperty; + callBacks.setProperty = CFJSObjectSetProperty; + callBacks.callFunction = 0; + callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames; + cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, 0, kJSUserObjectDataTypeCFType ); + } + return cfJSObject; +} + +/* + CFJSObjectDispose +*/ +void CFJSObjectDispose(void *data) +{ + if (data) + { + CFRelease((JSTypeRef)data); + } +} + +CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref) +{ + CFArrayRef result = 0; + JSUserObject* ptr = (JSUserObject*)ref; + if (ptr && (ptr->GetTypeID() == kJSObjectTypeID)) + { + result = ptr->CopyPropertyNames(); + } + return result; +} +/* + CFJSObjectCopyProperty +*/ +JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName) +{ + JSObjectRef result = 0; + if (data && propertyName) + { + CFTypeRef cfResult = 0; + if (CFGetTypeID(data) == CFDictionaryGetTypeID()) + { + if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo) + { + int len = CFDictionaryGetCount((CFDictionaryRef)data); + cfResult = CFNumberCreate(0, kCFNumberIntType, &len); + } + else + { + cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName)); + } + } + else if (CFGetTypeID(data) == CFArrayGetTypeID()) + { + if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo) + { + int len = CFArrayGetCount((CFArrayRef)data); + cfResult = CFNumberCreate(0, kCFNumberIntType, &len); + } + else + { + SInt32 index = CFStringGetIntValue(propertyName); + CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data); + if (index >= 0 && index < arrayCount) + { + cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index)); + } + } + } + else if (CFGetTypeID(data) == CFStringGetTypeID()) + { + if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo) + { + int len = CFStringGetLength((CFStringRef)data); + cfResult = CFNumberCreate(0, kCFNumberIntType, &len); + } + } + if (cfResult) + { + result = JSObjectCreateWithCFType(cfResult); + CFRelease(cfResult); + } + } + return result; +} + + +/* + CFJSObjectSetProperty +*/ +void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue) +{ + if (data && propertyName) + { + CFTypeRef cfValue = JSObjectCopyCFValue(jsValue); + + if (cfValue) + { + if (CFGetTypeID(data) == CFDictionaryGetTypeID()) + { + CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue); + } + else if (CFGetTypeID(data) == CFArrayGetTypeID()) + { + SInt32 index = CFStringGetIntValue(propertyName); + CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data); + if (index >= 0) + { + for (; arrayCount < index; arrayCount++) + { + CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull()); + } + CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue); + } + } + CFRelease(cfValue); + } + else + { + if (CFGetTypeID(data) == CFDictionaryGetTypeID()) + { + CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName); + } + else if (CFGetTypeID(data) == CFArrayGetTypeID()) + { + SInt32 index = CFStringGetIntValue(propertyName); + CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data); + if (index >= 0) + { + for (; arrayCount < index; arrayCount++) + { + CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull()); + } + CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull()); + } + } + } + } +} + + +/* + CFJSObjectCopyCFValue +*/ +CFTypeRef CFJSObjectCopyCFValue(void *data) +{ + CFTypeRef result = 0; + if (data) + { + result = (CFTypeRef)CFRetain(data); + } + return result; +} + +/* + CFJSObjectCopyCFValue +*/ +UInt8 CFJSObjectEqual(void *data1, void *data2) +{ + UInt8 result = false; + if (data1 && data2) + { + CFEqual((CFTypeRef)data1, (CFTypeRef)data2); + } + return result; +} + + +/* + CFJSObjectCopyPropertyNames +*/ +CFArrayRef CFJSObjectCopyPropertyNames(void *data) +{ + CFMutableArrayRef result = 0; + if (data) + { + CFTypeID cfType = CFGetTypeID(data); + if (cfType == CFDictionaryGetTypeID()) + { + CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data); + if (count) + { + CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count); + if (keys) + { + int i; + CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, 0); + for (i = 0; i < count; i++) + { + CFStringRef key = (CFStringRef)keys[i]; + if (CFGetTypeID(key) != CFStringGetTypeID()) continue; + + if (!result) result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); + if (!result) continue; + + CFArrayAppendValue(result, key); + } + free(keys); + } + } + } + } + return result; +} + + + + +CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array) +{ + CFIndex count = array ? CFArrayGetCount(array) : 0; + CFMutableArrayRef cfArray = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks); + CFIndex i; + + for (i = 0; cfArray && i < count; i++) + { + JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i); + CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue); + if (cfvalue) + { + CFArrayAppendValue(cfArray, cfvalue); + CFRelease(cfvalue); + } + else + { + CFArrayAppendValue(cfArray, GetCFNull()); + } + } + return cfArray; +} + +CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array) +{ + initializeThreading(); + + CFIndex count = array ? CFArrayGetCount(array) : 0; + CFArrayCallBacks arrayCallbacks; + CFMutableArrayRef jsArray; + CFIndex i; + + JSTypeGetCFArrayCallBacks(&arrayCallbacks); + jsArray = CFArrayCreateMutable(0, 0, &arrayCallbacks); + + for (i = 0; array && i < count; i++) + { + CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i); + JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue); + + if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull()); + if (jsValue) + { + CFArrayAppendValue(jsArray, jsValue); + JSRelease(jsValue); + } + } + return jsArray; +} + + +void JSLockInterpreter() +{ + initializeThreading(); + JSLock::lock(LockForReal); +} + + +void JSUnlockInterpreter() +{ + JSLock::unlock(LockForReal); +}