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