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