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