Home | History | Annotate | Download | only in API
      1 /*
      2  * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 Kelvin W Sherlock (ksherlock (at) gmail.com)
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      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  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     25  */
     26 
     27 #include "config.h"
     28 #include "JSObjectRef.h"
     29 
     30 #include "APICast.h"
     31 #include "CodeBlock.h"
     32 #include "DateConstructor.h"
     33 #include "ErrorConstructor.h"
     34 #include "FunctionConstructor.h"
     35 #include "Identifier.h"
     36 #include "InitializeThreading.h"
     37 #include "JSArray.h"
     38 #include "JSCallbackConstructor.h"
     39 #include "JSCallbackFunction.h"
     40 #include "JSCallbackObject.h"
     41 #include "JSClassRef.h"
     42 #include "JSFunction.h"
     43 #include "JSGlobalObject.h"
     44 #include "JSObject.h"
     45 #include "JSRetainPtr.h"
     46 #include "JSString.h"
     47 #include "JSValueRef.h"
     48 #include "ObjectPrototype.h"
     49 #include "PropertyNameArray.h"
     50 #include "RegExpConstructor.h"
     51 #include <wtf/Platform.h>
     52 
     53 using namespace JSC;
     54 
     55 JSClassRef JSClassCreate(const JSClassDefinition* definition)
     56 {
     57     initializeThreading();
     58     RefPtr<OpaqueJSClass> jsClass = (definition->attributes & kJSClassAttributeNoAutomaticPrototype)
     59         ? OpaqueJSClass::createNoAutomaticPrototype(definition)
     60         : OpaqueJSClass::create(definition);
     61 
     62     return jsClass.release().releaseRef();
     63 }
     64 
     65 JSClassRef JSClassRetain(JSClassRef jsClass)
     66 {
     67     jsClass->ref();
     68     return jsClass;
     69 }
     70 
     71 void JSClassRelease(JSClassRef jsClass)
     72 {
     73     jsClass->deref();
     74 }
     75 
     76 JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
     77 {
     78     ExecState* exec = toJS(ctx);
     79     APIEntryShim entryShim(exec);
     80 
     81     if (!jsClass)
     82         return toRef(new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure())); // slightly more efficient
     83 
     84     JSCallbackObject<JSObject>* object = new (exec) JSCallbackObject<JSObject>(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
     85     if (JSObject* prototype = jsClass->prototype(exec))
     86         object->setPrototype(prototype);
     87 
     88     return toRef(object);
     89 }
     90 
     91 JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction)
     92 {
     93     ExecState* exec = toJS(ctx);
     94     APIEntryShim entryShim(exec);
     95 
     96     Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous");
     97 
     98     return toRef(new (exec) JSCallbackFunction(exec, callAsFunction, nameID));
     99 }
    100 
    101 JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
    102 {
    103     ExecState* exec = toJS(ctx);
    104     APIEntryShim entryShim(exec);
    105 
    106     JSValue jsPrototype = jsClass ? jsClass->prototype(exec) : 0;
    107     if (!jsPrototype)
    108         jsPrototype = exec->lexicalGlobalObject()->objectPrototype();
    109 
    110     JSCallbackConstructor* constructor = new (exec) JSCallbackConstructor(exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
    111     constructor->putDirect(exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
    112     return toRef(constructor);
    113 }
    114 
    115 JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
    116 {
    117     ExecState* exec = toJS(ctx);
    118     APIEntryShim entryShim(exec);
    119 
    120     Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous");
    121 
    122     MarkedArgumentBuffer args;
    123     for (unsigned i = 0; i < parameterCount; i++)
    124         args.append(jsString(exec, parameterNames[i]->ustring()));
    125     args.append(jsString(exec, body->ustring()));
    126 
    127     JSObject* result = constructFunction(exec, args, nameID, sourceURL->ustring(), startingLineNumber);
    128     if (exec->hadException()) {
    129         if (exception)
    130             *exception = toRef(exec, exec->exception());
    131         exec->clearException();
    132         result = 0;
    133     }
    134     return toRef(result);
    135 }
    136 
    137 JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
    138 {
    139     ExecState* exec = toJS(ctx);
    140     APIEntryShim entryShim(exec);
    141 
    142     JSObject* result;
    143     if (argumentCount) {
    144         MarkedArgumentBuffer argList;
    145         for (size_t i = 0; i < argumentCount; ++i)
    146             argList.append(toJS(exec, arguments[i]));
    147 
    148         result = constructArray(exec, argList);
    149     } else
    150         result = constructEmptyArray(exec);
    151 
    152     if (exec->hadException()) {
    153         if (exception)
    154             *exception = toRef(exec, exec->exception());
    155         exec->clearException();
    156         result = 0;
    157     }
    158 
    159     return toRef(result);
    160 }
    161 
    162 JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
    163 {
    164     ExecState* exec = toJS(ctx);
    165     APIEntryShim entryShim(exec);
    166 
    167     MarkedArgumentBuffer argList;
    168     for (size_t i = 0; i < argumentCount; ++i)
    169         argList.append(toJS(exec, arguments[i]));
    170 
    171     JSObject* result = constructDate(exec, argList);
    172     if (exec->hadException()) {
    173         if (exception)
    174             *exception = toRef(exec, exec->exception());
    175         exec->clearException();
    176         result = 0;
    177     }
    178 
    179     return toRef(result);
    180 }
    181 
    182 JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
    183 {
    184     ExecState* exec = toJS(ctx);
    185     APIEntryShim entryShim(exec);
    186 
    187     MarkedArgumentBuffer argList;
    188     for (size_t i = 0; i < argumentCount; ++i)
    189         argList.append(toJS(exec, arguments[i]));
    190 
    191     JSObject* result = constructError(exec, argList);
    192     if (exec->hadException()) {
    193         if (exception)
    194             *exception = toRef(exec, exec->exception());
    195         exec->clearException();
    196         result = 0;
    197     }
    198 
    199     return toRef(result);
    200 }
    201 
    202 JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
    203 {
    204     ExecState* exec = toJS(ctx);
    205     APIEntryShim entryShim(exec);
    206 
    207     MarkedArgumentBuffer argList;
    208     for (size_t i = 0; i < argumentCount; ++i)
    209         argList.append(toJS(exec, arguments[i]));
    210 
    211     JSObject* result = constructRegExp(exec, argList);
    212     if (exec->hadException()) {
    213         if (exception)
    214             *exception = toRef(exec, exec->exception());
    215         exec->clearException();
    216         result = 0;
    217     }
    218 
    219     return toRef(result);
    220 }
    221 
    222 JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object)
    223 {
    224     ExecState* exec = toJS(ctx);
    225     APIEntryShim entryShim(exec);
    226 
    227     JSObject* jsObject = toJS(object);
    228     return toRef(exec, jsObject->prototype());
    229 }
    230 
    231 void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value)
    232 {
    233     ExecState* exec = toJS(ctx);
    234     APIEntryShim entryShim(exec);
    235 
    236     JSObject* jsObject = toJS(object);
    237     JSValue jsValue = toJS(exec, value);
    238 
    239     jsObject->setPrototype(jsValue.isObject() ? jsValue : jsNull());
    240 }
    241 
    242 bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
    243 {
    244     ExecState* exec = toJS(ctx);
    245     APIEntryShim entryShim(exec);
    246 
    247     JSObject* jsObject = toJS(object);
    248 
    249     return jsObject->hasProperty(exec, propertyName->identifier(&exec->globalData()));
    250 }
    251 
    252 JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
    253 {
    254     ExecState* exec = toJS(ctx);
    255     APIEntryShim entryShim(exec);
    256 
    257     JSObject* jsObject = toJS(object);
    258 
    259     JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->globalData()));
    260     if (exec->hadException()) {
    261         if (exception)
    262             *exception = toRef(exec, exec->exception());
    263         exec->clearException();
    264     }
    265     return toRef(exec, jsValue);
    266 }
    267 
    268 void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
    269 {
    270     ExecState* exec = toJS(ctx);
    271     APIEntryShim entryShim(exec);
    272 
    273     JSObject* jsObject = toJS(object);
    274     Identifier name(propertyName->identifier(&exec->globalData()));
    275     JSValue jsValue = toJS(exec, value);
    276 
    277     if (attributes && !jsObject->hasProperty(exec, name))
    278         jsObject->putWithAttributes(exec, name, jsValue, attributes);
    279     else {
    280         PutPropertySlot slot;
    281         jsObject->put(exec, name, jsValue, slot);
    282     }
    283 
    284     if (exec->hadException()) {
    285         if (exception)
    286             *exception = toRef(exec, exec->exception());
    287         exec->clearException();
    288     }
    289 }
    290 
    291 JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
    292 {
    293     ExecState* exec = toJS(ctx);
    294     APIEntryShim entryShim(exec);
    295 
    296     JSObject* jsObject = toJS(object);
    297 
    298     JSValue jsValue = jsObject->get(exec, propertyIndex);
    299     if (exec->hadException()) {
    300         if (exception)
    301             *exception = toRef(exec, exec->exception());
    302         exec->clearException();
    303     }
    304     return toRef(exec, jsValue);
    305 }
    306 
    307 
    308 void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception)
    309 {
    310     ExecState* exec = toJS(ctx);
    311     APIEntryShim entryShim(exec);
    312 
    313     JSObject* jsObject = toJS(object);
    314     JSValue jsValue = toJS(exec, value);
    315 
    316     jsObject->put(exec, propertyIndex, jsValue);
    317     if (exec->hadException()) {
    318         if (exception)
    319             *exception = toRef(exec, exec->exception());
    320         exec->clearException();
    321     }
    322 }
    323 
    324 bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
    325 {
    326     ExecState* exec = toJS(ctx);
    327     APIEntryShim entryShim(exec);
    328 
    329     JSObject* jsObject = toJS(object);
    330 
    331     bool result = jsObject->deleteProperty(exec, propertyName->identifier(&exec->globalData()));
    332     if (exec->hadException()) {
    333         if (exception)
    334             *exception = toRef(exec, exec->exception());
    335         exec->clearException();
    336     }
    337     return result;
    338 }
    339 
    340 void* JSObjectGetPrivate(JSObjectRef object)
    341 {
    342     JSObject* jsObject = toJS(object);
    343 
    344     if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info))
    345         return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
    346     else if (jsObject->inherits(&JSCallbackObject<JSObject>::info))
    347         return static_cast<JSCallbackObject<JSObject>*>(jsObject)->getPrivate();
    348 
    349     return 0;
    350 }
    351 
    352 bool JSObjectSetPrivate(JSObjectRef object, void* data)
    353 {
    354     JSObject* jsObject = toJS(object);
    355 
    356     if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
    357         static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
    358         return true;
    359     } else if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
    360         static_cast<JSCallbackObject<JSObject>*>(jsObject)->setPrivate(data);
    361         return true;
    362     }
    363 
    364     return false;
    365 }
    366 
    367 bool JSObjectIsFunction(JSContextRef, JSObjectRef object)
    368 {
    369     CallData callData;
    370     return toJS(object)->getCallData(callData) != CallTypeNone;
    371 }
    372 
    373 JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    374 {
    375     ExecState* exec = toJS(ctx);
    376     APIEntryShim entryShim(exec);
    377 
    378     JSObject* jsObject = toJS(object);
    379     JSObject* jsThisObject = toJS(thisObject);
    380 
    381     if (!jsThisObject)
    382         jsThisObject = exec->globalThisValue();
    383 
    384     MarkedArgumentBuffer argList;
    385     for (size_t i = 0; i < argumentCount; i++)
    386         argList.append(toJS(exec, arguments[i]));
    387 
    388     CallData callData;
    389     CallType callType = jsObject->getCallData(callData);
    390     if (callType == CallTypeNone)
    391         return 0;
    392 
    393     JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
    394     if (exec->hadException()) {
    395         if (exception)
    396             *exception = toRef(exec, exec->exception());
    397         exec->clearException();
    398         result = 0;
    399     }
    400     return result;
    401 }
    402 
    403 bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
    404 {
    405     JSObject* jsObject = toJS(object);
    406     ConstructData constructData;
    407     return jsObject->getConstructData(constructData) != ConstructTypeNone;
    408 }
    409 
    410 JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    411 {
    412     ExecState* exec = toJS(ctx);
    413     APIEntryShim entryShim(exec);
    414 
    415     JSObject* jsObject = toJS(object);
    416 
    417     ConstructData constructData;
    418     ConstructType constructType = jsObject->getConstructData(constructData);
    419     if (constructType == ConstructTypeNone)
    420         return 0;
    421 
    422     MarkedArgumentBuffer argList;
    423     for (size_t i = 0; i < argumentCount; i++)
    424         argList.append(toJS(exec, arguments[i]));
    425     JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
    426     if (exec->hadException()) {
    427         if (exception)
    428             *exception = toRef(exec, exec->exception());
    429         exec->clearException();
    430         result = 0;
    431     }
    432     return result;
    433 }
    434 
    435 struct OpaqueJSPropertyNameArray : FastAllocBase {
    436     OpaqueJSPropertyNameArray(JSGlobalData* globalData)
    437         : refCount(0)
    438         , globalData(globalData)
    439     {
    440     }
    441 
    442     unsigned refCount;
    443     JSGlobalData* globalData;
    444     Vector<JSRetainPtr<JSStringRef> > array;
    445 };
    446 
    447 JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
    448 {
    449     JSObject* jsObject = toJS(object);
    450     ExecState* exec = toJS(ctx);
    451     APIEntryShim entryShim(exec);
    452 
    453     JSGlobalData* globalData = &exec->globalData();
    454 
    455     JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(globalData);
    456     PropertyNameArray array(globalData);
    457     jsObject->getPropertyNames(exec, array);
    458 
    459     size_t size = array.size();
    460     propertyNames->array.reserveInitialCapacity(size);
    461     for (size_t i = 0; i < size; ++i)
    462         propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).releaseRef()));
    463 
    464     return JSPropertyNameArrayRetain(propertyNames);
    465 }
    466 
    467 JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)
    468 {
    469     ++array->refCount;
    470     return array;
    471 }
    472 
    473 void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)
    474 {
    475     if (--array->refCount == 0) {
    476         APIEntryShim entryShim(array->globalData, false);
    477         delete array;
    478     }
    479 }
    480 
    481 size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
    482 {
    483     return array->array.size();
    484 }
    485 
    486 JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
    487 {
    488     return array->array[static_cast<unsigned>(index)].get();
    489 }
    490 
    491 void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
    492 {
    493     PropertyNameArray* propertyNames = toJS(array);
    494     APIEntryShim entryShim(propertyNames->globalData());
    495     propertyNames->add(propertyName->identifier(propertyNames->globalData()));
    496 }
    497