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