/ API / JSObjectRef.cpp
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