Home | History | Annotate | Download | only in JavaScriptGlue
      1 /*
      2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  *
      8  * 1.  Redistributions of source code must retain the above copyright
      9  *     notice, this list of conditions and the following disclaimer.
     10  * 2.  Redistributions in binary form must reproduce the above copyright
     11  *     notice, this list of conditions and the following disclaimer in the
     12  *     documentation and/or other materials provided with the distribution.
     13  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
     14  *     its contributors may be used to endorse or promote products derived
     15  *     from this software without specific prior written permission.
     16  *
     17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
     18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
     21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
     22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
     24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "JavaScriptGlue.h"
     31 #include "JSUtils.h"
     32 #include "JSBase.h"
     33 #include "JSObject.h"
     34 #include "JSRun.h"
     35 #include <JavaScriptCore/Completion.h>
     36 #include <JavaScriptCore/InitializeThreading.h>
     37 
     38 static CFTypeRef sJSCFNullRef = 0;
     39 
     40 static void CFJSObjectDispose(void *data);
     41 static JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName);
     42 static void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue);
     43 static CFTypeRef CFJSObjectCopyCFValue(void *data);
     44 static UInt8 CFJSObjectEqual(void *data1, void *data2);
     45 static CFArrayRef CFJSObjectCopyPropertyNames(void *data);
     46 
     47 void *JSCFRetain(CFAllocatorRef allocator, const void *value);
     48 void JSCFRelease(CFAllocatorRef allocator, const void *value);
     49 
     50 
     51 void JSSetCFNull(CFTypeRef nullRef)
     52 {
     53     ReleaseCFType(sJSCFNullRef);
     54     sJSCFNullRef = RetainCFType(nullRef);
     55 }
     56 
     57 CFTypeRef JSGetCFNull(void)
     58 {
     59     return sJSCFNullRef;
     60 }
     61 
     62 /*
     63     JSRetain
     64 */
     65 JSTypeRef JSRetain(JSTypeRef ref)
     66 {
     67     if (ref)
     68     {
     69         JSBase* ptr = (JSBase*)ref;
     70         ptr->Retain();
     71     }
     72     return ref;
     73 }
     74 
     75 /*
     76     JSRelease
     77 */
     78 void JSRelease(JSTypeRef ref)
     79 {
     80     if (ref)
     81     {
     82         JSBase* ptr = (JSBase*)ref;
     83         ptr->Release();
     84     }
     85 }
     86 
     87 /*
     88     JSCopyDescription
     89 */
     90 CFStringRef JSCopyDescription(JSTypeRef ref)
     91 {
     92     CFStringRef result = 0;
     93     if (ref)
     94     {
     95         JSBase* ptr = (JSBase*)ref;
     96         ptr->CopyDescription();
     97     }
     98     return result;
     99 }
    100 
    101 /*
    102     JSEqual
    103 */
    104 UInt8 JSEqual(JSTypeRef ref1, JSTypeRef ref2)
    105 {
    106     UInt8 result = false;
    107     if (ref1 && ref2)
    108     {
    109         JSBase* ptr = (JSBase*)ref1;
    110         result = ptr->Equal((JSBase*)ref2);
    111     }
    112     return result;
    113 }
    114 
    115 
    116 /*
    117     JSGetTypeID
    118 */
    119 JSTypeID JSGetTypeID(JSTypeRef ref)
    120 {
    121     JSTypeID result = kJSInvalidTypeID;
    122     if (ref)
    123     {
    124         JSBase* ptr = (JSBase*)ref;
    125         result = ptr->GetTypeID();
    126     }
    127     return result;
    128 }
    129 
    130 
    131 /*
    132     JSGetRetainCount
    133 */
    134 CFIndex JSGetRetainCount(JSTypeRef ref)
    135 {
    136     CFIndex result = -1;
    137     if (ref)
    138     {
    139         JSBase* ptr = (JSBase*)ref;
    140         result = ptr->RetainCount();
    141     }
    142     return result;
    143 }
    144 
    145 
    146 
    147 /*
    148     JSObjectCreate
    149 */
    150 JSObjectRef JSObjectCreate(void *data, JSObjectCallBacksPtr callBacks)
    151 {
    152     JSObjectRef result = JSObjectCreateInternal(data, callBacks, 0, kJSUserObjectDataTypeUnknown);
    153     return result;
    154 }
    155 
    156 /*
    157     JSObjectCreateInternal
    158 */
    159 JSObjectRef JSObjectCreateInternal(void *data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int type)
    160 {
    161     JSObjectRef result = 0;
    162     JSUserObject* ptr = new JSUserObject(callBacks, markProc, data, type);
    163     result = (JSObjectRef)ptr;
    164     return result;
    165 }
    166 
    167 /*
    168     JSObjectCopyCFValue
    169 */
    170 CFTypeRef JSObjectCopyCFValue(JSObjectRef ref)
    171 {
    172     CFTypeRef result = 0;
    173     JSUserObject* ptr = (JSUserObject*)ref;
    174     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
    175     {
    176         result = ptr->CopyCFValue();
    177     }
    178     return result;
    179 }
    180 
    181 /*
    182     JSObjectGetData
    183 */
    184 void *JSObjectGetData(JSObjectRef ref)
    185 {
    186     void *result = 0;
    187     JSUserObject* ptr = (JSUserObject*)ref;
    188     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
    189     {
    190         result = ptr->GetData();
    191     }
    192     return result;
    193 }
    194 
    195 
    196 /*
    197     JSObjectCopyProperty
    198 */
    199 JSObjectRef JSObjectCopyProperty(JSObjectRef ref, CFStringRef propertyName)
    200 {
    201     JSObjectRef result = 0;
    202     JSUserObject* ptr = (JSUserObject*)ref;
    203     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
    204     {
    205         result = (JSObjectRef)ptr->CopyProperty(propertyName);
    206     }
    207     return result;
    208 }
    209 
    210 
    211 /*
    212     JSObjectSetProperty
    213 */
    214 void JSObjectSetProperty(JSObjectRef ref, CFStringRef propertyName, JSObjectRef value)
    215 {
    216     JSUserObject* ptr = (JSUserObject*)ref;
    217     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
    218     {
    219         ptr->SetProperty(propertyName, (JSUserObject*)value);
    220     }
    221 }
    222 
    223 
    224 /*
    225     JSObjectCallFunction
    226 */
    227 JSObjectRef JSObjectCallFunction(JSObjectRef ref, JSObjectRef thisObj, CFArrayRef args)
    228 {
    229     JSObjectRef result = 0;
    230     JSUserObject* ptr = (JSUserObject*)ref;
    231     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
    232     {
    233         result = (JSObjectRef)ptr->CallFunction((JSUserObject*)thisObj, args);
    234     }
    235     return result;
    236 }
    237 
    238 
    239 /*
    240     JSRunCreate
    241 */
    242 JSRunRef JSRunCreate(CFStringRef jsSource, JSFlags inFlags)
    243 {
    244     initializeThreading();
    245 
    246     JSRunRef result = 0;
    247     if (jsSource)
    248     {
    249         JSGlueAPIEntry entry;
    250         result = (JSRunRef) new JSRun(jsSource, inFlags);
    251     }
    252     return result;
    253 }
    254 
    255 /*
    256     JSRunCopySource
    257 */
    258 CFStringRef JSRunCopySource(JSRunRef ref)
    259 {
    260     CFStringRef result = 0;
    261     JSRun* ptr = (JSRun*)ref;
    262     if (ptr)
    263     {
    264         result = UStringToCFString(ptr->GetSource());
    265     }
    266     return result;
    267 }
    268 
    269 
    270 /*
    271     JSRunCopyGlobalObject
    272 */
    273 JSObjectRef JSRunCopyGlobalObject(JSRunRef ref)
    274 {
    275     JSObjectRef result = 0;
    276     JSRun* ptr = (JSRun*)ref;
    277     if (ptr)
    278     {
    279         JSGlobalObject* globalObject = ptr->GlobalObject();
    280         result = (JSObjectRef)KJSValueToJSObject(globalObject, globalObject->globalExec());
    281     }
    282     return result;
    283 }
    284 
    285 /*
    286     JSRunEvaluate
    287 */
    288 JSObjectRef JSRunEvaluate(JSRunRef ref)
    289 {
    290     JSObjectRef result = 0;
    291     JSRun* ptr = (JSRun*)ref;
    292     if (ptr)
    293     {
    294         JSGlueAPIEntry entry;
    295         Completion completion = ptr->Evaluate();
    296         if (completion.isValueCompletion())
    297         {
    298             result = (JSObjectRef)KJSValueToJSObject(completion.value(), ptr->GlobalObject()->globalExec());
    299         }
    300 
    301         if (completion.complType() == Throw)
    302         {
    303             JSFlags flags = ptr->Flags();
    304             if (flags & kJSFlagDebug)
    305             {
    306                 CFTypeRef error = JSObjectCopyCFValue(result);
    307                 if (error)
    308                 {
    309                     CFShow(error);
    310                     CFRelease(error);
    311                 }
    312             }
    313         }
    314     }
    315     return result;
    316 }
    317 
    318 /*
    319     JSRunCheckSyntax
    320     Return true if no syntax error
    321 */
    322 bool JSRunCheckSyntax(JSRunRef ref)
    323 {
    324     bool result = false;
    325     JSRun* ptr = (JSRun*)ref;
    326     if (ptr)
    327     {
    328             JSGlueAPIEntry entry;
    329             result = ptr->CheckSyntax();
    330     }
    331     return result;
    332 }
    333 
    334 /*
    335     JSCollect - trigger garbage collection
    336 */
    337 void JSCollect()
    338 {
    339     initializeThreading();
    340 
    341     JSGlueAPIEntry entry;
    342     Heap* heap = getThreadGlobalExecState()->heap();
    343     if (!heap->isBusy())
    344         heap->collectAllGarbage();
    345 }
    346 
    347 /*
    348     JSTypeGetCFArrayCallBacks
    349 */
    350 void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks)
    351 {
    352     if (outCallBacks)
    353     {
    354         outCallBacks->version = 1;
    355         outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain;
    356         outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease;
    357         outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription;
    358         outCallBacks->equal = (CFArrayEqualCallBack)JSEqual;
    359     }
    360 }
    361 
    362 
    363 /*
    364     JSCFRetain
    365 */
    366 void *JSCFRetain(CFAllocatorRef allocator, const void *value)
    367 {
    368     JSRetain((JSTypeRef)value);
    369     return (void*)value;
    370 }
    371 
    372 /*
    373     JSCFRelease
    374 */
    375 void JSCFRelease(CFAllocatorRef allocator, const void *value)
    376 {
    377     JSRelease((JSTypeRef)value);
    378 }
    379 
    380 
    381 /*
    382     JSObjectCreateWithCFType
    383 */
    384 JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef)
    385 {
    386     JSObjectCallBacks callBacks;
    387     JSObjectRef cfJSObject = nil;
    388     if (inRef)
    389     {
    390         callBacks.dispose = CFJSObjectDispose;
    391         callBacks.equal = CFJSObjectEqual;
    392         callBacks.copyCFValue = CFJSObjectCopyCFValue;
    393         callBacks.copyProperty = CFJSObjectCopyProperty;
    394         callBacks.setProperty = CFJSObjectSetProperty;
    395         callBacks.callFunction = 0;
    396         callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames;
    397         cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, 0, kJSUserObjectDataTypeCFType );
    398     }
    399     return cfJSObject;
    400 }
    401 
    402 /*
    403     CFJSObjectDispose
    404 */
    405 void CFJSObjectDispose(void *data)
    406 {
    407     if (data)
    408     {
    409         CFRelease((JSTypeRef)data);
    410     }
    411 }
    412 
    413 CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref)
    414 {
    415     CFArrayRef result = 0;
    416     JSUserObject* ptr = (JSUserObject*)ref;
    417     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
    418     {
    419         result = ptr->CopyPropertyNames();
    420     }
    421     return result;
    422 }
    423 /*
    424     CFJSObjectCopyProperty
    425 */
    426 JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName)
    427 {
    428     JSObjectRef result = 0;
    429     if (data && propertyName)
    430     {
    431         CFTypeRef cfResult = 0;
    432         if (CFGetTypeID(data) == CFDictionaryGetTypeID())
    433         {
    434             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
    435             {
    436                 int len = CFDictionaryGetCount((CFDictionaryRef)data);
    437                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
    438             }
    439             else
    440             {
    441                 cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName));
    442             }
    443         }
    444         else if (CFGetTypeID(data) == CFArrayGetTypeID())
    445         {
    446             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
    447             {
    448                 int len = CFArrayGetCount((CFArrayRef)data);
    449                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
    450             }
    451             else
    452             {
    453                 SInt32 index = CFStringGetIntValue(propertyName);
    454                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
    455                 if (index >= 0 && index < arrayCount)
    456                 {
    457                     cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index));
    458                 }
    459             }
    460         }
    461         else if (CFGetTypeID(data) == CFStringGetTypeID())
    462         {
    463             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
    464             {
    465                 int len = CFStringGetLength((CFStringRef)data);
    466                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
    467             }
    468         }
    469         if (cfResult)
    470         {
    471             result = JSObjectCreateWithCFType(cfResult);
    472             CFRelease(cfResult);
    473         }
    474     }
    475     return result;
    476 }
    477 
    478 
    479 /*
    480     CFJSObjectSetProperty
    481 */
    482 void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue)
    483 {
    484     if (data && propertyName)
    485     {
    486         CFTypeRef cfValue = JSObjectCopyCFValue(jsValue);
    487 
    488         if (cfValue)
    489         {
    490             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
    491             {
    492                 CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue);
    493             }
    494             else if (CFGetTypeID(data) == CFArrayGetTypeID())
    495             {
    496                 SInt32 index = CFStringGetIntValue(propertyName);
    497                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
    498                 if (index >= 0)
    499                 {
    500                     for (; arrayCount < index; arrayCount++)
    501                     {
    502                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
    503                     }
    504                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue);
    505                 }
    506             }
    507             CFRelease(cfValue);
    508         }
    509         else
    510         {
    511             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
    512             {
    513                 CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName);
    514             }
    515             else if (CFGetTypeID(data) == CFArrayGetTypeID())
    516             {
    517                 SInt32 index = CFStringGetIntValue(propertyName);
    518                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
    519                 if (index >= 0)
    520                 {
    521                     for (; arrayCount < index; arrayCount++)
    522                     {
    523                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
    524                     }
    525                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull());
    526                 }
    527             }
    528         }
    529     }
    530 }
    531 
    532 
    533 /*
    534     CFJSObjectCopyCFValue
    535 */
    536 CFTypeRef CFJSObjectCopyCFValue(void *data)
    537 {
    538     CFTypeRef result = 0;
    539     if (data)
    540     {
    541         result = (CFTypeRef)CFRetain(data);
    542     }
    543     return result;
    544 }
    545 
    546 /*
    547     CFJSObjectCopyCFValue
    548 */
    549 UInt8 CFJSObjectEqual(void *data1, void *data2)
    550 {
    551     UInt8 result = false;
    552     if (data1 && data2)
    553     {
    554         CFEqual((CFTypeRef)data1, (CFTypeRef)data2);
    555     }
    556     return result;
    557 }
    558 
    559 
    560 /*
    561     CFJSObjectCopyPropertyNames
    562 */
    563 CFArrayRef CFJSObjectCopyPropertyNames(void *data)
    564 {
    565     CFMutableArrayRef result = 0;
    566     if (data)
    567     {
    568         CFTypeID cfType = CFGetTypeID(data);
    569         if (cfType == CFDictionaryGetTypeID())
    570         {
    571             CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data);
    572             if (count)
    573             {
    574                 CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count);
    575                 if (keys)
    576                 {
    577                     int i;
    578                     CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, 0);
    579                     for (i = 0; i < count; i++)
    580                     {
    581                         CFStringRef key = (CFStringRef)keys[i];
    582                         if (CFGetTypeID(key) != CFStringGetTypeID()) continue;
    583 
    584                         if (!result) result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
    585                         if (!result) continue;
    586 
    587                         CFArrayAppendValue(result, key);
    588                     }
    589                     free(keys);
    590                 }
    591             }
    592         }
    593     }
    594     return result;
    595 }
    596 
    597 
    598 
    599 
    600 CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array)
    601 {
    602     CFIndex count = array ? CFArrayGetCount(array) : 0;
    603     CFMutableArrayRef cfArray = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
    604     CFIndex i;
    605 
    606     for (i = 0; cfArray && i <  count; i++)
    607     {
    608         JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i);
    609         CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue);
    610         if (cfvalue)
    611         {
    612             CFArrayAppendValue(cfArray, cfvalue);
    613             CFRelease(cfvalue);
    614         }
    615         else
    616         {
    617             CFArrayAppendValue(cfArray, GetCFNull());
    618         }
    619     }
    620     return cfArray;
    621 }
    622 
    623 CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array)
    624 {
    625     initializeThreading();
    626 
    627     CFIndex count = array ? CFArrayGetCount(array) : 0;
    628     CFArrayCallBacks arrayCallbacks;
    629     CFMutableArrayRef jsArray;
    630     CFIndex i;
    631 
    632     JSTypeGetCFArrayCallBacks(&arrayCallbacks);
    633     jsArray = CFArrayCreateMutable(0, 0, &arrayCallbacks);
    634 
    635     for (i = 0; array && i <  count; i++)
    636     {
    637         CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i);
    638         JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue);
    639 
    640         if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull());
    641         if (jsValue)
    642         {
    643             CFArrayAppendValue(jsArray, jsValue);
    644             JSRelease(jsValue);
    645         }
    646     }
    647     return jsArray;
    648 }
    649 
    650 
    651 void JSLockInterpreter()
    652 {
    653     initializeThreading();
    654     JSLock::lock(LockForReal);
    655 }
    656 
    657 
    658 void JSUnlockInterpreter()
    659 {
    660     JSLock::unlock(LockForReal);
    661 }
    662