JSObjectRef.cpp
1 /* 2 * Copyright (C) 2006-2020 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Kelvin W Sherlock (ksherlock@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 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 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 "APIUtils.h" 33 #include "DateConstructor.h" 34 #include "FunctionConstructor.h" 35 #include "Identifier.h" 36 #include "InitializeThreading.h" 37 #include "JSArray.h" 38 #include "JSCInlines.h" 39 #include "JSCallbackConstructor.h" 40 #include "JSCallbackFunction.h" 41 #include "JSCallbackObject.h" 42 #include "JSClassRef.h" 43 #include "JSPromise.h" 44 #include "JSString.h" 45 #include "ObjectConstructor.h" 46 #include "ObjectPrototype.h" 47 #include "PropertyNameArray.h" 48 #include "ProxyObject.h" 49 #include "RegExpConstructor.h" 50 51 #if ENABLE(REMOTE_INSPECTOR) 52 #include "JSGlobalObjectInspectorController.h" 53 #endif 54 55 #ifdef DARLING 56 #include "JSAPIWrapperObject.h" 57 #endif 58 59 using namespace JSC; 60 61 JSClassRef JSClassCreate(const JSClassDefinition* definition) 62 { 63 JSC::initialize(); 64 auto jsClass = (definition->attributes & kJSClassAttributeNoAutomaticPrototype) 65 ? OpaqueJSClass::createNoAutomaticPrototype(definition) 66 : OpaqueJSClass::create(definition); 67 68 return &jsClass.leakRef(); 69 } 70 71 JSClassRef JSClassRetain(JSClassRef jsClass) 72 { 73 jsClass->ref(); 74 return jsClass; 75 } 76 77 void JSClassRelease(JSClassRef jsClass) 78 { 79 jsClass->deref(); 80 } 81 82 JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data) 83 { 84 if (!ctx) { 85 ASSERT_NOT_REACHED(); 86 return nullptr; 87 } 88 JSGlobalObject* globalObject = toJS(ctx); 89 VM& vm = globalObject->vm(); 90 JSLockHolder locker(vm); 91 92 if (!jsClass) 93 return toRef(constructEmptyObject(globalObject)); 94 95 JSCallbackObject<JSNonFinalObject>* object = JSCallbackObject<JSNonFinalObject>::create(globalObject, globalObject->callbackObjectStructure(), jsClass, data); 96 if (JSObject* prototype = jsClass->prototype(globalObject)) 97 object->setPrototypeDirect(vm, prototype); 98 99 return toRef(object); 100 } 101 102 JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction) 103 { 104 if (!ctx) { 105 ASSERT_NOT_REACHED(); 106 return nullptr; 107 } 108 JSGlobalObject* globalObject = toJS(ctx); 109 VM& vm = globalObject->vm(); 110 JSLockHolder locker(vm); 111 return toRef(JSCallbackFunction::create(vm, globalObject, callAsFunction, name ? name->string() : "anonymous"_s)); 112 } 113 114 JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor) 115 { 116 if (!ctx) { 117 ASSERT_NOT_REACHED(); 118 return nullptr; 119 } 120 JSGlobalObject* globalObject = toJS(ctx); 121 VM& vm = globalObject->vm(); 122 JSLockHolder locker(vm); 123 124 JSValue jsPrototype = jsClass ? jsClass->prototype(globalObject) : nullptr; 125 if (!jsPrototype) 126 jsPrototype = globalObject->objectPrototype(); 127 128 JSCallbackConstructor* constructor = JSCallbackConstructor::create(globalObject, globalObject->callbackConstructorStructure(), jsClass, callAsConstructor); 129 constructor->putDirect(vm, vm.propertyNames->prototype, jsPrototype, PropertyAttribute::DontEnum | PropertyAttribute::DontDelete | PropertyAttribute::ReadOnly); 130 return toRef(constructor); 131 } 132 133 JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURLString, int startingLineNumber, JSValueRef* exception) 134 { 135 if (!ctx) { 136 ASSERT_NOT_REACHED(); 137 return nullptr; 138 } 139 JSGlobalObject* globalObject = toJS(ctx); 140 VM& vm = globalObject->vm(); 141 JSLockHolder locker(vm); 142 auto scope = DECLARE_CATCH_SCOPE(vm); 143 144 startingLineNumber = std::max(1, startingLineNumber); 145 Identifier nameID = name ? name->identifier(&vm) : Identifier::fromString(vm, "anonymous"); 146 147 MarkedArgumentBuffer args; 148 for (unsigned i = 0; i < parameterCount; i++) 149 args.append(jsString(vm, parameterNames[i]->string())); 150 args.append(jsString(vm, body->string())); 151 if (UNLIKELY(args.hasOverflowed())) { 152 auto throwScope = DECLARE_THROW_SCOPE(vm); 153 throwOutOfMemoryError(globalObject, throwScope); 154 handleExceptionIfNeeded(scope, ctx, exception); 155 return nullptr; 156 } 157 158 auto sourceURL = sourceURLString ? URL({ }, sourceURLString->string()) : URL(); 159 JSObject* result = constructFunction(globalObject, args, nameID, SourceOrigin { sourceURL }, sourceURL.string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber())); 160 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 161 result = nullptr; 162 return toRef(result); 163 } 164 165 JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 166 { 167 if (!ctx) { 168 ASSERT_NOT_REACHED(); 169 return nullptr; 170 } 171 JSGlobalObject* globalObject = toJS(ctx); 172 VM& vm = globalObject->vm(); 173 JSLockHolder locker(vm); 174 auto scope = DECLARE_CATCH_SCOPE(vm); 175 176 JSObject* result; 177 if (argumentCount) { 178 MarkedArgumentBuffer argList; 179 for (size_t i = 0; i < argumentCount; ++i) 180 argList.append(toJS(globalObject, arguments[i])); 181 if (UNLIKELY(argList.hasOverflowed())) { 182 auto throwScope = DECLARE_THROW_SCOPE(vm); 183 throwOutOfMemoryError(globalObject, throwScope); 184 handleExceptionIfNeeded(scope, ctx, exception); 185 return nullptr; 186 } 187 188 result = constructArray(globalObject, static_cast<ArrayAllocationProfile*>(nullptr), argList); 189 } else 190 result = constructEmptyArray(globalObject, nullptr); 191 192 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 193 result = nullptr; 194 195 return toRef(result); 196 } 197 198 JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 199 { 200 if (!ctx) { 201 ASSERT_NOT_REACHED(); 202 return nullptr; 203 } 204 JSGlobalObject* globalObject = toJS(ctx); 205 VM& vm = globalObject->vm(); 206 JSLockHolder locker(vm); 207 auto scope = DECLARE_CATCH_SCOPE(vm); 208 209 MarkedArgumentBuffer argList; 210 for (size_t i = 0; i < argumentCount; ++i) 211 argList.append(toJS(globalObject, arguments[i])); 212 if (UNLIKELY(argList.hasOverflowed())) { 213 auto throwScope = DECLARE_THROW_SCOPE(vm); 214 throwOutOfMemoryError(globalObject, throwScope); 215 handleExceptionIfNeeded(scope, ctx, exception); 216 return nullptr; 217 } 218 219 JSObject* result = constructDate(globalObject, JSValue(), argList); 220 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 221 result = nullptr; 222 223 return toRef(result); 224 } 225 226 JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 227 { 228 if (!ctx) { 229 ASSERT_NOT_REACHED(); 230 return nullptr; 231 } 232 JSGlobalObject* globalObject = toJS(ctx); 233 VM& vm = globalObject->vm(); 234 JSLockHolder locker(vm); 235 auto scope = DECLARE_CATCH_SCOPE(vm); 236 237 JSValue message = argumentCount ? toJS(globalObject, arguments[0]) : jsUndefined(); 238 Structure* errorStructure = globalObject->errorStructure(); 239 JSObject* result = ErrorInstance::create(globalObject, errorStructure, message); 240 241 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 242 result = nullptr; 243 244 return toRef(result); 245 } 246 247 JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 248 { 249 if (!ctx) { 250 ASSERT_NOT_REACHED(); 251 return nullptr; 252 } 253 JSGlobalObject* globalObject = toJS(ctx); 254 VM& vm = globalObject->vm(); 255 JSLockHolder locker(vm); 256 auto scope = DECLARE_CATCH_SCOPE(vm); 257 258 MarkedArgumentBuffer argList; 259 for (size_t i = 0; i < argumentCount; ++i) 260 argList.append(toJS(globalObject, arguments[i])); 261 if (UNLIKELY(argList.hasOverflowed())) { 262 auto throwScope = DECLARE_THROW_SCOPE(vm); 263 throwOutOfMemoryError(globalObject, throwScope); 264 handleExceptionIfNeeded(scope, ctx, exception); 265 return nullptr; 266 } 267 268 JSObject* result = constructRegExp(globalObject, argList); 269 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 270 result = nullptr; 271 272 return toRef(result); 273 } 274 275 JSObjectRef JSObjectMakeDeferredPromise(JSContextRef ctx, JSObjectRef* resolve, JSObjectRef* reject, JSValueRef* exception) 276 { 277 if (!ctx) { 278 ASSERT_NOT_REACHED(); 279 return nullptr; 280 } 281 282 JSGlobalObject* globalObject = toJS(ctx); 283 VM& vm = globalObject->vm(); 284 JSLockHolder locker(globalObject); 285 auto scope = DECLARE_CATCH_SCOPE(vm); 286 287 JSPromise::DeferredData data = JSPromise::createDeferredData(globalObject, globalObject->promiseConstructor()); 288 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 289 return nullptr; 290 291 if (resolve) 292 *resolve = toRef(data.resolve); 293 if (reject) 294 *reject = toRef(data.reject); 295 return toRef(data.promise); 296 } 297 298 JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object) 299 { 300 if (!ctx) { 301 ASSERT_NOT_REACHED(); 302 return nullptr; 303 } 304 JSGlobalObject* globalObject = toJS(ctx); 305 JSLockHolder locker(globalObject); 306 307 JSObject* jsObject = toJS(object); 308 return toRef(globalObject, jsObject->getPrototypeDirect(globalObject->vm())); 309 } 310 311 void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value) 312 { 313 if (!ctx) { 314 ASSERT_NOT_REACHED(); 315 return; 316 } 317 JSGlobalObject* globalObject = toJS(ctx); 318 VM& vm = globalObject->vm(); 319 JSLockHolder locker(vm); 320 auto scope = DECLARE_CATCH_SCOPE(vm); 321 322 JSObject* jsObject = toJS(object); 323 JSValue jsValue = toJS(globalObject, value); 324 jsObject->setPrototype(vm, globalObject, jsValue.isObject() ? jsValue : jsNull()); 325 handleExceptionIfNeeded(scope, ctx, nullptr); 326 } 327 328 bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) 329 { 330 if (!ctx) { 331 ASSERT_NOT_REACHED(); 332 return false; 333 } 334 JSGlobalObject* globalObject = toJS(ctx); 335 VM& vm = globalObject->vm(); 336 JSLockHolder locker(vm); 337 338 JSObject* jsObject = toJS(object); 339 340 return jsObject->hasProperty(globalObject, propertyName->identifier(&vm)); 341 } 342 343 JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 344 { 345 if (!ctx || !object) { 346 ASSERT_NOT_REACHED(); 347 return nullptr; 348 } 349 JSGlobalObject* globalObject = toJS(ctx); 350 VM& vm = globalObject->vm(); 351 JSLockHolder locker(vm); 352 auto scope = DECLARE_CATCH_SCOPE(vm); 353 354 JSObject* jsObject = toJS(object); 355 356 JSValue jsValue = jsObject->get(globalObject, propertyName->identifier(&vm)); 357 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 358 return nullptr; 359 return toRef(globalObject, jsValue); 360 } 361 362 void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) 363 { 364 if (!ctx) { 365 ASSERT_NOT_REACHED(); 366 return; 367 } 368 JSGlobalObject* globalObject = toJS(ctx); 369 VM& vm = globalObject->vm(); 370 JSLockHolder locker(vm); 371 auto scope = DECLARE_CATCH_SCOPE(vm); 372 373 JSObject* jsObject = toJS(object); 374 Identifier name(propertyName->identifier(&vm)); 375 JSValue jsValue = toJS(globalObject, value); 376 377 bool doesNotHaveProperty = attributes && !jsObject->hasProperty(globalObject, name); 378 if (LIKELY(!scope.exception())) { 379 if (doesNotHaveProperty) { 380 PropertyDescriptor desc(jsValue, attributes); 381 jsObject->methodTable(vm)->defineOwnProperty(jsObject, globalObject, name, desc, false); 382 } else { 383 PutPropertySlot slot(jsObject); 384 jsObject->methodTable(vm)->put(jsObject, globalObject, name, jsValue, slot); 385 } 386 } 387 handleExceptionIfNeeded(scope, ctx, exception); 388 } 389 390 bool JSObjectHasPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception) 391 { 392 if (!ctx) { 393 ASSERT_NOT_REACHED(); 394 return false; 395 } 396 JSGlobalObject* globalObject = toJS(ctx); 397 VM& vm = globalObject->vm(); 398 JSLockHolder locker(vm); 399 auto scope = DECLARE_CATCH_SCOPE(vm); 400 401 JSObject* jsObject = toJS(object); 402 Identifier ident = toJS(globalObject, key).toPropertyKey(globalObject); 403 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 404 return false; 405 406 bool result = jsObject->hasProperty(globalObject, ident); 407 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 408 return false; 409 return result; 410 } 411 412 JSValueRef JSObjectGetPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception) 413 { 414 if (!ctx) { 415 ASSERT_NOT_REACHED(); 416 return nullptr; 417 } 418 JSGlobalObject* globalObject = toJS(ctx); 419 VM& vm = globalObject->vm(); 420 JSLockHolder locker(vm); 421 auto scope = DECLARE_CATCH_SCOPE(vm); 422 423 JSObject* jsObject = toJS(object); 424 Identifier ident = toJS(globalObject, key).toPropertyKey(globalObject); 425 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 426 return nullptr; 427 428 JSValue jsValue = jsObject->get(globalObject, ident); 429 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 430 return nullptr; 431 return toRef(globalObject, jsValue); 432 } 433 434 void JSObjectSetPropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception) 435 { 436 if (!ctx) { 437 ASSERT_NOT_REACHED(); 438 return; 439 } 440 JSGlobalObject* globalObject = toJS(ctx); 441 VM& vm = globalObject->vm(); 442 JSLockHolder locker(vm); 443 auto scope = DECLARE_CATCH_SCOPE(vm); 444 445 JSObject* jsObject = toJS(object); 446 JSValue jsValue = toJS(globalObject, value); 447 448 Identifier ident = toJS(globalObject, key).toPropertyKey(globalObject); 449 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 450 return; 451 452 bool doesNotHaveProperty = attributes && !jsObject->hasProperty(globalObject, ident); 453 if (LIKELY(!scope.exception())) { 454 if (doesNotHaveProperty) { 455 PropertyDescriptor desc(jsValue, attributes); 456 jsObject->methodTable(vm)->defineOwnProperty(jsObject, globalObject, ident, desc, false); 457 } else { 458 PutPropertySlot slot(jsObject); 459 jsObject->methodTable(vm)->put(jsObject, globalObject, ident, jsValue, slot); 460 } 461 } 462 handleExceptionIfNeeded(scope, ctx, exception); 463 } 464 465 bool JSObjectDeletePropertyForKey(JSContextRef ctx, JSObjectRef object, JSValueRef key, JSValueRef* exception) 466 { 467 if (!ctx) { 468 ASSERT_NOT_REACHED(); 469 return false; 470 } 471 JSGlobalObject* globalObject = toJS(ctx); 472 VM& vm = globalObject->vm(); 473 JSLockHolder locker(vm); 474 auto scope = DECLARE_CATCH_SCOPE(vm); 475 476 JSObject* jsObject = toJS(object); 477 Identifier ident = toJS(globalObject, key).toPropertyKey(globalObject); 478 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 479 return false; 480 481 bool result = JSCell::deleteProperty(jsObject, globalObject, ident); 482 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 483 return false; 484 return result; 485 } 486 487 JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception) 488 { 489 if (!ctx) { 490 ASSERT_NOT_REACHED(); 491 return nullptr; 492 } 493 JSGlobalObject* globalObject = toJS(ctx); 494 VM& vm = globalObject->vm(); 495 JSLockHolder locker(vm); 496 auto scope = DECLARE_CATCH_SCOPE(vm); 497 498 JSObject* jsObject = toJS(object); 499 500 JSValue jsValue = jsObject->get(globalObject, propertyIndex); 501 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 502 return nullptr; 503 return toRef(globalObject, jsValue); 504 } 505 506 507 void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception) 508 { 509 if (!ctx) { 510 ASSERT_NOT_REACHED(); 511 return; 512 } 513 JSGlobalObject* globalObject = toJS(ctx); 514 VM& vm = globalObject->vm(); 515 JSLockHolder locker(vm); 516 auto scope = DECLARE_CATCH_SCOPE(vm); 517 518 JSObject* jsObject = toJS(object); 519 JSValue jsValue = toJS(globalObject, value); 520 521 jsObject->methodTable(vm)->putByIndex(jsObject, globalObject, propertyIndex, jsValue, false); 522 handleExceptionIfNeeded(scope, ctx, exception); 523 } 524 525 bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 526 { 527 if (!ctx) { 528 ASSERT_NOT_REACHED(); 529 return false; 530 } 531 JSGlobalObject* globalObject = toJS(ctx); 532 VM& vm = globalObject->vm(); 533 JSLockHolder locker(vm); 534 auto scope = DECLARE_CATCH_SCOPE(vm); 535 536 JSObject* jsObject = toJS(object); 537 538 bool result = JSCell::deleteProperty(jsObject, globalObject, propertyName->identifier(&vm)); 539 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 540 return false; 541 return result; 542 } 543 544 // API objects have private properties, which may get accessed during destruction. This 545 // helper lets us get the ClassInfo of an API object from a function that may get called 546 // during destruction. 547 static const ClassInfo* classInfoPrivate(JSObject* jsObject) 548 { 549 VM& vm = jsObject->vm(); 550 551 if (vm.currentlyDestructingCallbackObject != jsObject) 552 return jsObject->classInfo(vm); 553 554 return vm.currentlyDestructingCallbackObjectClassInfo; 555 } 556 557 void* JSObjectGetPrivate(JSObjectRef object) 558 { 559 JSObject* jsObject = uncheckedToJS(object); 560 VM& vm = jsObject->vm(); 561 562 const ClassInfo* classInfo = classInfoPrivate(jsObject); 563 564 // Get wrapped object if proxied 565 if (classInfo->isSubClassOf(JSProxy::info())) { 566 jsObject = static_cast<JSProxy*>(jsObject)->target(); 567 classInfo = jsObject->classInfo(vm); 568 } 569 570 if (classInfo->isSubClassOf(JSCallbackObject<JSGlobalObject>::info())) 571 return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate(); 572 if (classInfo->isSubClassOf(JSCallbackObject<JSNonFinalObject>::info())) 573 return static_cast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->getPrivate(); 574 #if JSC_OBJC_API_ENABLED 575 if (classInfo->isSubClassOf(JSCallbackObject<JSAPIWrapperObject>::info())) 576 return static_cast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivate(); 577 #endif 578 579 return nullptr; 580 } 581 582 bool JSObjectSetPrivate(JSObjectRef object, void* data) 583 { 584 JSObject* jsObject = uncheckedToJS(object); 585 VM& vm = jsObject->vm(); 586 587 const ClassInfo* classInfo = classInfoPrivate(jsObject); 588 589 // Get wrapped object if proxied 590 if (classInfo->isSubClassOf(JSProxy::info())) { 591 jsObject = static_cast<JSProxy*>(jsObject)->target(); 592 classInfo = jsObject->classInfo(vm); 593 } 594 595 if (classInfo->isSubClassOf(JSCallbackObject<JSGlobalObject>::info())) { 596 static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data); 597 return true; 598 } 599 if (classInfo->isSubClassOf(JSCallbackObject<JSNonFinalObject>::info())) { 600 static_cast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->setPrivate(data); 601 return true; 602 } 603 #if JSC_OBJC_API_ENABLED 604 if (classInfo->isSubClassOf(JSCallbackObject<JSAPIWrapperObject>::info())) { 605 static_cast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivate(data); 606 return true; 607 } 608 #endif 609 610 return false; 611 } 612 613 JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) 614 { 615 JSGlobalObject* globalObject = toJS(ctx); 616 VM& vm = globalObject->vm(); 617 JSLockHolder locker(vm); 618 JSObject* jsObject = toJS(object); 619 JSValue result; 620 Identifier name(propertyName->identifier(&vm)); 621 622 623 // Get wrapped object if proxied 624 if (jsObject->inherits<JSProxy>(vm)) 625 jsObject = jsCast<JSProxy*>(jsObject)->target(); 626 627 if (jsObject->inherits<JSCallbackObject<JSGlobalObject>>(vm)) 628 result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name); 629 else if (jsObject->inherits<JSCallbackObject<JSNonFinalObject>>(vm)) 630 result = jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->getPrivateProperty(name); 631 #if JSC_OBJC_API_ENABLED 632 else if (jsObject->inherits<JSCallbackObject<JSAPIWrapperObject>>(vm)) 633 result = jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivateProperty(name); 634 #endif 635 return toRef(globalObject, result); 636 } 637 638 bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value) 639 { 640 JSGlobalObject* globalObject = toJS(ctx); 641 VM& vm = globalObject->vm(); 642 JSLockHolder locker(vm); 643 JSObject* jsObject = toJS(object); 644 JSValue jsValue = value ? toJS(globalObject, value) : JSValue(); 645 Identifier name(propertyName->identifier(&vm)); 646 647 // Get wrapped object if proxied 648 if (jsObject->inherits<JSProxy>(vm)) 649 jsObject = jsCast<JSProxy*>(jsObject)->target(); 650 651 if (jsObject->inherits<JSCallbackObject<JSGlobalObject>>(vm)) { 652 jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(vm, name, jsValue); 653 return true; 654 } 655 if (jsObject->inherits<JSCallbackObject<JSNonFinalObject>>(vm)) { 656 jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->setPrivateProperty(vm, name, jsValue); 657 return true; 658 } 659 #if JSC_OBJC_API_ENABLED 660 if (jsObject->inherits<JSCallbackObject<JSAPIWrapperObject>>(vm)) { 661 jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivateProperty(vm, name, jsValue); 662 return true; 663 } 664 #endif 665 return false; 666 } 667 668 bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName) 669 { 670 JSGlobalObject* globalObject = toJS(ctx); 671 VM& vm = globalObject->vm(); 672 JSLockHolder locker(vm); 673 JSObject* jsObject = toJS(object); 674 Identifier name(propertyName->identifier(&vm)); 675 676 // Get wrapped object if proxied 677 if (jsObject->inherits<JSProxy>(vm)) 678 jsObject = jsCast<JSProxy*>(jsObject)->target(); 679 680 if (jsObject->inherits<JSCallbackObject<JSGlobalObject>>(vm)) { 681 jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name); 682 return true; 683 } 684 if (jsObject->inherits<JSCallbackObject<JSNonFinalObject>>(vm)) { 685 jsCast<JSCallbackObject<JSNonFinalObject>*>(jsObject)->deletePrivateProperty(name); 686 return true; 687 } 688 #if JSC_OBJC_API_ENABLED 689 if (jsObject->inherits<JSCallbackObject<JSAPIWrapperObject>>(vm)) { 690 jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->deletePrivateProperty(name); 691 return true; 692 } 693 #endif 694 return false; 695 } 696 697 bool JSObjectIsFunction(JSContextRef ctx, JSObjectRef object) 698 { 699 if (!object) 700 return false; 701 JSGlobalObject* globalObject = toJS(ctx); 702 VM& vm = globalObject->vm(); 703 JSLockHolder locker(vm); 704 JSCell* cell = toJS(object); 705 return cell->isCallable(vm); 706 } 707 708 JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 709 { 710 JSGlobalObject* globalObject = toJS(ctx); 711 VM& vm = globalObject->vm(); 712 JSLockHolder locker(vm); 713 auto scope = DECLARE_CATCH_SCOPE(vm); 714 715 if (!object) 716 return nullptr; 717 718 JSObject* jsObject = toJS(object); 719 JSObject* jsThisObject = toJS(thisObject); 720 721 if (!jsThisObject) 722 jsThisObject = globalObject->globalThis(); 723 724 MarkedArgumentBuffer argList; 725 for (size_t i = 0; i < argumentCount; i++) 726 argList.append(toJS(globalObject, arguments[i])); 727 if (UNLIKELY(argList.hasOverflowed())) { 728 auto throwScope = DECLARE_THROW_SCOPE(vm); 729 throwOutOfMemoryError(globalObject, throwScope); 730 handleExceptionIfNeeded(scope, ctx, exception); 731 return nullptr; 732 } 733 734 auto callData = getCallData(vm, jsObject); 735 if (callData.type == CallData::Type::None) 736 return nullptr; 737 738 JSValueRef result = toRef(globalObject, profiledCall(globalObject, ProfilingReason::API, jsObject, callData, jsThisObject, argList)); 739 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 740 result = nullptr; 741 return result; 742 } 743 744 bool JSObjectIsConstructor(JSContextRef ctx, JSObjectRef object) 745 { 746 JSGlobalObject* globalObject = toJS(ctx); 747 VM& vm = globalObject->vm(); 748 JSLockHolder locker(vm); 749 if (!object) 750 return false; 751 return toJS(object)->isConstructor(vm); 752 } 753 754 JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 755 { 756 JSGlobalObject* globalObject = toJS(ctx); 757 VM& vm = globalObject->vm(); 758 JSLockHolder locker(vm); 759 auto scope = DECLARE_CATCH_SCOPE(vm); 760 761 if (!object) 762 return nullptr; 763 764 JSObject* jsObject = toJS(object); 765 766 auto constructData = getConstructData(vm, jsObject); 767 if (constructData.type == CallData::Type::None) 768 return nullptr; 769 770 MarkedArgumentBuffer argList; 771 for (size_t i = 0; i < argumentCount; i++) 772 argList.append(toJS(globalObject, arguments[i])); 773 if (UNLIKELY(argList.hasOverflowed())) { 774 auto throwScope = DECLARE_THROW_SCOPE(vm); 775 throwOutOfMemoryError(globalObject, throwScope); 776 handleExceptionIfNeeded(scope, ctx, exception); 777 return nullptr; 778 } 779 780 JSObjectRef result = toRef(profiledConstruct(globalObject, ProfilingReason::API, jsObject, constructData, argList)); 781 if (handleExceptionIfNeeded(scope, ctx, exception) == ExceptionStatus::DidThrow) 782 result = nullptr; 783 return result; 784 } 785 786 struct OpaqueJSPropertyNameArray { 787 WTF_MAKE_FAST_ALLOCATED; 788 public: 789 // FIXME: Why not inherit from RefCounted? 790 OpaqueJSPropertyNameArray(VM* vm) 791 : refCount(0) 792 , vm(vm) 793 { 794 } 795 796 unsigned refCount; 797 VM* vm; 798 Vector<Ref<OpaqueJSString>> array; 799 }; 800 801 JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object) 802 { 803 if (!ctx) { 804 ASSERT_NOT_REACHED(); 805 return nullptr; 806 } 807 JSGlobalObject* globalObject = toJS(ctx); 808 JSLockHolder locker(globalObject); 809 810 VM& vm = globalObject->vm(); 811 812 JSObject* jsObject = toJS(object); 813 JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(&vm); 814 PropertyNameArray array(vm, PropertyNameMode::Strings, PrivateSymbolMode::Exclude); 815 jsObject->getPropertyNames(globalObject, array, DontEnumPropertiesMode::Exclude); 816 817 size_t size = array.size(); 818 propertyNames->array.reserveInitialCapacity(size); 819 for (size_t i = 0; i < size; ++i) 820 propertyNames->array.uncheckedAppend(OpaqueJSString::tryCreate(array[i].string()).releaseNonNull()); 821 822 return JSPropertyNameArrayRetain(propertyNames); 823 } 824 825 JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array) 826 { 827 ++array->refCount; 828 return array; 829 } 830 831 void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array) 832 { 833 if (--array->refCount == 0) { 834 JSLockHolder locker(array->vm); 835 delete array; 836 } 837 } 838 839 size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array) 840 { 841 return array->array.size(); 842 } 843 844 JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index) 845 { 846 return array->array[static_cast<unsigned>(index)].ptr(); 847 } 848 849 void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName) 850 { 851 PropertyNameArray* propertyNames = toJS(array); 852 VM& vm = propertyNames->vm(); 853 JSLockHolder locker(vm); 854 propertyNames->add(propertyName->identifier(&vm)); 855 } 856 857 JSObjectRef JSObjectGetProxyTarget(JSObjectRef objectRef) 858 { 859 JSObject* object = toJS(objectRef); 860 if (!object) 861 return nullptr; 862 VM& vm = object->vm(); 863 JSLockHolder locker(vm); 864 JSObject* result = nullptr; 865 if (JSProxy* proxy = jsDynamicCast<JSProxy*>(vm, object)) 866 result = proxy->target(); 867 else if (ProxyObject* proxy = jsDynamicCast<ProxyObject*>(vm, object)) 868 result = proxy->target(); 869 return toRef(result); 870 } 871 872 JSGlobalContextRef JSObjectGetGlobalContext(JSObjectRef objectRef) 873 { 874 JSObject* object = toJS(objectRef); 875 if (!object) 876 return nullptr; 877 return reinterpret_cast<JSGlobalContextRef>(object->globalObject()); 878 } 879