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 #include "JSObjectRefPrivate.h"
     30 
     31 #include "APICast.h"
     32 #include "CodeBlock.h"
     33 #include "DateConstructor.h"
     34 #include "ErrorConstructor.h"
     35 #include "FunctionConstructor.h"
     36 #include "Identifier.h"
     37 #include "InitializeThreading.h"
     38 #include "JSArray.h"
     39 #include "JSCallbackConstructor.h"
     40 #include "JSCallbackFunction.h"
     41 #include "JSCallbackObject.h"
     42 #include "JSClassRef.h"
     43 #include "JSFunction.h"
     44 #include "JSGlobalObject.h"
     45 #include "JSObject.h"
     46 #include "JSRetainPtr.h"
     47 #include "JSString.h"
     48 #include "JSValueRef.h"
     49 #include "ObjectPrototype.h"
     50 #include "PropertyNameArray.h"
     51 #include "RegExpConstructor.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().leakRef();
     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(constructEmptyObject(exec));
     83 
     84     JSCallbackObject<JSObjectWithGlobalObject>* object = new (exec) JSCallbackObject<JSObjectWithGlobalObject>(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
     85     if (JSObject* prototype = jsClass->prototype(exec))
     86         object->setPrototype(exec->globalData(), 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, exec->lexicalGlobalObject(), 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(), exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
    111     constructor->putDirect(exec->globalData(), 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, exec->lexicalGlobalObject(), 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, exec->lexicalGlobalObject(), 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     JSValue message = argumentCount ? toJS(exec, arguments[0]) : jsUndefined();
    188     Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure();
    189     JSObject* result = ErrorInstance::create(exec, errorStructure, message);
    190 
    191     if (exec->hadException()) {
    192         if (exception)
    193             *exception = toRef(exec, exec->exception());
    194         exec->clearException();
    195         result = 0;
    196     }
    197 
    198     return toRef(result);
    199 }
    200 
    201 JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
    202 {
    203     ExecState* exec = toJS(ctx);
    204     APIEntryShim entryShim(exec);
    205 
    206     MarkedArgumentBuffer argList;
    207     for (size_t i = 0; i < argumentCount; ++i)
    208         argList.append(toJS(exec, arguments[i]));
    209 
    210     JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(),  argList);
    211     if (exec->hadException()) {
    212         if (exception)
    213             *exception = toRef(exec, exec->exception());
    214         exec->clearException();
    215         result = 0;
    216     }
    217 
    218     return toRef(result);
    219 }
    220 
    221 JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object)
    222 {
    223     ExecState* exec = toJS(ctx);
    224     APIEntryShim entryShim(exec);
    225 
    226     JSObject* jsObject = toJS(object);
    227     return toRef(exec, jsObject->prototype());
    228 }
    229 
    230 void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value)
    231 {
    232     ExecState* exec = toJS(ctx);
    233     APIEntryShim entryShim(exec);
    234 
    235     JSObject* jsObject = toJS(object);
    236     JSValue jsValue = toJS(exec, value);
    237 
    238     jsObject->setPrototypeWithCycleCheck(exec->globalData(), jsValue.isObject() ? jsValue : jsNull());
    239 }
    240 
    241 bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
    242 {
    243     ExecState* exec = toJS(ctx);
    244     APIEntryShim entryShim(exec);
    245 
    246     JSObject* jsObject = toJS(object);
    247 
    248     return jsObject->hasProperty(exec, propertyName->identifier(&exec->globalData()));
    249 }
    250 
    251 JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
    252 {
    253     ExecState* exec = toJS(ctx);
    254     APIEntryShim entryShim(exec);
    255 
    256     JSObject* jsObject = toJS(object);
    257 
    258     JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->globalData()));
    259     if (exec->hadException()) {
    260         if (exception)
    261             *exception = toRef(exec, exec->exception());
    262         exec->clearException();
    263     }
    264     return toRef(exec, jsValue);
    265 }
    266 
    267 void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
    268 {
    269     ExecState* exec = toJS(ctx);
    270     APIEntryShim entryShim(exec);
    271 
    272     JSObject* jsObject = toJS(object);
    273     Identifier name(propertyName->identifier(&exec->globalData()));
    274     JSValue jsValue = toJS(exec, value);
    275 
    276     if (attributes && !jsObject->hasProperty(exec, name))
    277         jsObject->putWithAttributes(exec, name, jsValue, attributes);
    278     else {
    279         PutPropertySlot slot;
    280         jsObject->put(exec, name, jsValue, slot);
    281     }
    282 
    283     if (exec->hadException()) {
    284         if (exception)
    285             *exception = toRef(exec, exec->exception());
    286         exec->clearException();
    287     }
    288 }
    289 
    290 JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
    291 {
    292     ExecState* exec = toJS(ctx);
    293     APIEntryShim entryShim(exec);
    294 
    295     JSObject* jsObject = toJS(object);
    296 
    297     JSValue jsValue = jsObject->get(exec, propertyIndex);
    298     if (exec->hadException()) {
    299         if (exception)
    300             *exception = toRef(exec, exec->exception());
    301         exec->clearException();
    302     }
    303     return toRef(exec, jsValue);
    304 }
    305 
    306 
    307 void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception)
    308 {
    309     ExecState* exec = toJS(ctx);
    310     APIEntryShim entryShim(exec);
    311 
    312     JSObject* jsObject = toJS(object);
    313     JSValue jsValue = toJS(exec, value);
    314 
    315     jsObject->put(exec, propertyIndex, jsValue);
    316     if (exec->hadException()) {
    317         if (exception)
    318             *exception = toRef(exec, exec->exception());
    319         exec->clearException();
    320     }
    321 }
    322 
    323 bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
    324 {
    325     ExecState* exec = toJS(ctx);
    326     APIEntryShim entryShim(exec);
    327 
    328     JSObject* jsObject = toJS(object);
    329 
    330     bool result = jsObject->deleteProperty(exec, propertyName->identifier(&exec->globalData()));
    331     if (exec->hadException()) {
    332         if (exception)
    333             *exception = toRef(exec, exec->exception());
    334         exec->clearException();
    335     }
    336     return result;
    337 }
    338 
    339 void* JSObjectGetPrivate(JSObjectRef object)
    340 {
    341     JSObject* jsObject = toJS(object);
    342 
    343     if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
    344         return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
    345     if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info))
    346         return static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->getPrivate();
    347 
    348     return 0;
    349 }
    350 
    351 bool JSObjectSetPrivate(JSObjectRef object, void* data)
    352 {
    353     JSObject* jsObject = toJS(object);
    354 
    355     if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
    356         static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
    357         return true;
    358     }
    359     if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info)) {
    360         static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->setPrivate(data);
    361         return true;
    362     }
    363 
    364     return false;
    365 }
    366 
    367 JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
    368 {
    369     ExecState* exec = toJS(ctx);
    370     APIEntryShim entryShim(exec);
    371     JSObject* jsObject = toJS(object);
    372     JSValue result;
    373     Identifier name(propertyName->identifier(&exec->globalData()));
    374     if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info))
    375         result = static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
    376     else if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info))
    377         result = static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->getPrivateProperty(name);
    378     return toRef(exec, result);
    379 }
    380 
    381 bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value)
    382 {
    383     ExecState* exec = toJS(ctx);
    384     APIEntryShim entryShim(exec);
    385     JSObject* jsObject = toJS(object);
    386     JSValue jsValue = value ? toJS(exec, value) : JSValue();
    387     Identifier name(propertyName->identifier(&exec->globalData()));
    388     if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
    389         static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
    390         return true;
    391     }
    392     if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info)) {
    393         static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->setPrivateProperty(exec->globalData(), name, jsValue);
    394         return true;
    395     }
    396     return false;
    397 }
    398 
    399 bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
    400 {
    401     ExecState* exec = toJS(ctx);
    402     APIEntryShim entryShim(exec);
    403     JSObject* jsObject = toJS(object);
    404     Identifier name(propertyName->identifier(&exec->globalData()));
    405     if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::s_info)) {
    406         static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name);
    407         return true;
    408     }
    409     if (jsObject->inherits(&JSCallbackObject<JSObjectWithGlobalObject>::s_info)) {
    410         static_cast<JSCallbackObject<JSObjectWithGlobalObject>*>(jsObject)->deletePrivateProperty(name);
    411         return true;
    412     }
    413     return false;
    414 }
    415 
    416 bool JSObjectIsFunction(JSContextRef, JSObjectRef object)
    417 {
    418     CallData callData;
    419     return toJS(object)->getCallData(callData) != CallTypeNone;
    420 }
    421 
    422 JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    423 {
    424     ExecState* exec = toJS(ctx);
    425     APIEntryShim entryShim(exec);
    426 
    427     JSObject* jsObject = toJS(object);
    428     JSObject* jsThisObject = toJS(thisObject);
    429 
    430     if (!jsThisObject)
    431         jsThisObject = exec->globalThisValue();
    432 
    433     MarkedArgumentBuffer argList;
    434     for (size_t i = 0; i < argumentCount; i++)
    435         argList.append(toJS(exec, arguments[i]));
    436 
    437     CallData callData;
    438     CallType callType = jsObject->getCallData(callData);
    439     if (callType == CallTypeNone)
    440         return 0;
    441 
    442     JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
    443     if (exec->hadException()) {
    444         if (exception)
    445             *exception = toRef(exec, exec->exception());
    446         exec->clearException();
    447         result = 0;
    448     }
    449     return result;
    450 }
    451 
    452 bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
    453 {
    454     JSObject* jsObject = toJS(object);
    455     ConstructData constructData;
    456     return jsObject->getConstructData(constructData) != ConstructTypeNone;
    457 }
    458 
    459 JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
    460 {
    461     ExecState* exec = toJS(ctx);
    462     APIEntryShim entryShim(exec);
    463 
    464     JSObject* jsObject = toJS(object);
    465 
    466     ConstructData constructData;
    467     ConstructType constructType = jsObject->getConstructData(constructData);
    468     if (constructType == ConstructTypeNone)
    469         return 0;
    470 
    471     MarkedArgumentBuffer argList;
    472     for (size_t i = 0; i < argumentCount; i++)
    473         argList.append(toJS(exec, arguments[i]));
    474     JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
    475     if (exec->hadException()) {
    476         if (exception)
    477             *exception = toRef(exec, exec->exception());
    478         exec->clearException();
    479         result = 0;
    480     }
    481     return result;
    482 }
    483 
    484 struct OpaqueJSPropertyNameArray {
    485     WTF_MAKE_FAST_ALLOCATED;
    486 public:
    487     OpaqueJSPropertyNameArray(JSGlobalData* globalData)
    488         : refCount(0)
    489         , globalData(globalData)
    490     {
    491     }
    492 
    493     unsigned refCount;
    494     JSGlobalData* globalData;
    495     Vector<JSRetainPtr<JSStringRef> > array;
    496 };
    497 
    498 JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
    499 {
    500     JSObject* jsObject = toJS(object);
    501     ExecState* exec = toJS(ctx);
    502     APIEntryShim entryShim(exec);
    503 
    504     JSGlobalData* globalData = &exec->globalData();
    505 
    506     JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(globalData);
    507     PropertyNameArray array(globalData);
    508     jsObject->getPropertyNames(exec, array);
    509 
    510     size_t size = array.size();
    511     propertyNames->array.reserveInitialCapacity(size);
    512     for (size_t i = 0; i < size; ++i)
    513         propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).leakRef()));
    514 
    515     return JSPropertyNameArrayRetain(propertyNames);
    516 }
    517 
    518 JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)
    519 {
    520     ++array->refCount;
    521     return array;
    522 }
    523 
    524 void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)
    525 {
    526     if (--array->refCount == 0) {
    527         APIEntryShim entryShim(array->globalData, false);
    528         delete array;
    529     }
    530 }
    531 
    532 size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
    533 {
    534     return array->array.size();
    535 }
    536 
    537 JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
    538 {
    539     return array->array[static_cast<unsigned>(index)].get();
    540 }
    541 
    542 void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
    543 {
    544     PropertyNameArray* propertyNames = toJS(array);
    545     APIEntryShim entryShim(propertyNames->globalData());
    546     propertyNames->add(propertyName->identifier(propertyNames->globalData()));
    547 }
    548