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