1/*
2 * Copyright (C) 2006, 2007, 2008 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 "ButterflyInlines.h"
33#include "CodeBlock.h"
34#include "CopiedSpaceInlines.h"
35#include "DateConstructor.h"
36#include "ErrorConstructor.h"
37#include "FunctionConstructor.h"
38#include "Identifier.h"
39#include "InitializeThreading.h"
40#include "JSAPIWrapperObject.h"
41#include "JSArray.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 "JSRetainPtr.h"
50#include "JSString.h"
51#include "JSValueRef.h"
52#include "ObjectConstructor.h"
53#include "ObjectPrototype.h"
54#include "JSCInlines.h"
55#include "PropertyNameArray.h"
56#include "RegExpConstructor.h"
57
58#if ENABLE(REMOTE_INSPECTOR)
59#include "JSGlobalObjectInspectorController.h"
60#endif
61
62using namespace JSC;
63
64JSClassRef JSClassCreate(const JSClassDefinition* definition)
65{
66    initializeThreading();
67    RefPtr<OpaqueJSClass> jsClass = (definition->attributes & kJSClassAttributeNoAutomaticPrototype)
68        ? OpaqueJSClass::createNoAutomaticPrototype(definition)
69        : OpaqueJSClass::create(definition);
70
71    return jsClass.release().leakRef();
72}
73
74JSClassRef JSClassRetain(JSClassRef jsClass)
75{
76    jsClass->ref();
77    return jsClass;
78}
79
80void JSClassRelease(JSClassRef jsClass)
81{
82    jsClass->deref();
83}
84
85JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
86{
87    if (!ctx) {
88        ASSERT_NOT_REACHED();
89        return 0;
90    }
91    ExecState* exec = toJS(ctx);
92    JSLockHolder locker(exec);
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->setPrototype(exec->vm(), prototype);
100
101    return toRef(object);
102}
103
104JSObjectRef 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    JSLockHolder locker(exec);
112    return toRef(JSCallbackFunction::create(exec->vm(), exec->lexicalGlobalObject(), callAsFunction, name ? name->string() : ASCIILiteral("anonymous")));
113}
114
115JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
116{
117    if (!ctx) {
118        ASSERT_NOT_REACHED();
119        return 0;
120    }
121    ExecState* exec = toJS(ctx);
122    JSLockHolder locker(exec);
123
124    JSValue jsPrototype = jsClass ? jsClass->prototype(exec) : 0;
125    if (!jsPrototype)
126        jsPrototype = exec->lexicalGlobalObject()->objectPrototype();
127
128    JSCallbackConstructor* constructor = JSCallbackConstructor::create(exec, exec->lexicalGlobalObject(), exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
129    constructor->putDirect(exec->vm(), exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
130    return toRef(constructor);
131}
132
133JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
134{
135    if (!ctx) {
136        ASSERT_NOT_REACHED();
137        return 0;
138    }
139    ExecState* exec = toJS(ctx);
140    JSLockHolder locker(exec);
141
142    startingLineNumber = std::max(1, startingLineNumber);
143    Identifier nameID = name ? name->identifier(&exec->vm()) : Identifier(exec, "anonymous");
144
145    MarkedArgumentBuffer args;
146    for (unsigned i = 0; i < parameterCount; i++)
147        args.append(jsString(exec, parameterNames[i]->string()));
148    args.append(jsString(exec, body->string()));
149
150    JSObject* result = constructFunction(exec, exec->lexicalGlobalObject(), args, nameID, sourceURL->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber), OrdinalNumber::first()));
151    if (exec->hadException()) {
152        JSValue exceptionValue = exec->exception();
153        if (exception)
154            *exception = toRef(exec, exceptionValue);
155        exec->clearException();
156#if ENABLE(REMOTE_INSPECTOR)
157        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
158#endif
159        result = 0;
160    }
161    return toRef(result);
162}
163
164JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
165{
166    if (!ctx) {
167        ASSERT_NOT_REACHED();
168        return 0;
169    }
170    ExecState* exec = toJS(ctx);
171    JSLockHolder locker(exec);
172
173    JSObject* result;
174    if (argumentCount) {
175        MarkedArgumentBuffer argList;
176        for (size_t i = 0; i < argumentCount; ++i)
177            argList.append(toJS(exec, arguments[i]));
178
179        result = constructArray(exec, static_cast<ArrayAllocationProfile*>(0), argList);
180    } else
181        result = constructEmptyArray(exec, 0);
182
183    if (exec->hadException()) {
184        JSValue exceptionValue = exec->exception();
185        if (exception)
186            *exception = toRef(exec, exceptionValue);
187        exec->clearException();
188#if ENABLE(REMOTE_INSPECTOR)
189        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
190#endif
191        result = 0;
192    }
193
194    return toRef(result);
195}
196
197JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
198{
199    if (!ctx) {
200        ASSERT_NOT_REACHED();
201        return 0;
202    }
203    ExecState* exec = toJS(ctx);
204    JSLockHolder locker(exec);
205
206    MarkedArgumentBuffer argList;
207    for (size_t i = 0; i < argumentCount; ++i)
208        argList.append(toJS(exec, arguments[i]));
209
210    JSObject* result = constructDate(exec, exec->lexicalGlobalObject(), argList);
211    if (exec->hadException()) {
212        JSValue exceptionValue = exec->exception();
213        if (exception)
214            *exception = toRef(exec, exceptionValue);
215        exec->clearException();
216#if ENABLE(REMOTE_INSPECTOR)
217        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
218#endif
219        result = 0;
220    }
221
222    return toRef(result);
223}
224
225JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[],  JSValueRef* exception)
226{
227    if (!ctx) {
228        ASSERT_NOT_REACHED();
229        return 0;
230    }
231    ExecState* exec = toJS(ctx);
232    JSLockHolder locker(exec);
233
234    JSValue message = argumentCount ? toJS(exec, arguments[0]) : jsUndefined();
235    Structure* errorStructure = exec->lexicalGlobalObject()->errorStructure();
236    JSObject* result = ErrorInstance::create(exec, errorStructure, message);
237
238    if (exec->hadException()) {
239        JSValue exceptionValue = exec->exception();
240        if (exception)
241            *exception = toRef(exec, exceptionValue);
242        exec->clearException();
243#if ENABLE(REMOTE_INSPECTOR)
244        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
245#endif
246        result = 0;
247    }
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    JSLockHolder locker(exec);
260
261    MarkedArgumentBuffer argList;
262    for (size_t i = 0; i < argumentCount; ++i)
263        argList.append(toJS(exec, arguments[i]));
264
265    JSObject* result = constructRegExp(exec, exec->lexicalGlobalObject(),  argList);
266    if (exec->hadException()) {
267        JSValue exceptionValue = exec->exception();
268        if (exception)
269            *exception = toRef(exec, exceptionValue);
270        exec->clearException();
271#if ENABLE(REMOTE_INSPECTOR)
272        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
273#endif
274        result = 0;
275    }
276
277    return toRef(result);
278}
279
280JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object)
281{
282    if (!ctx) {
283        ASSERT_NOT_REACHED();
284        return 0;
285    }
286    ExecState* exec = toJS(ctx);
287    JSLockHolder locker(exec);
288
289    JSObject* jsObject = toJS(object);
290    return toRef(exec, jsObject->prototype());
291}
292
293void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value)
294{
295    if (!ctx) {
296        ASSERT_NOT_REACHED();
297        return;
298    }
299    ExecState* exec = toJS(ctx);
300    JSLockHolder locker(exec);
301
302    JSObject* jsObject = toJS(object);
303    JSValue jsValue = toJS(exec, value);
304
305    jsObject->setPrototypeWithCycleCheck(exec, jsValue.isObject() ? jsValue : jsNull());
306}
307
308bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
309{
310    if (!ctx) {
311        ASSERT_NOT_REACHED();
312        return false;
313    }
314    ExecState* exec = toJS(ctx);
315    JSLockHolder locker(exec);
316
317    JSObject* jsObject = toJS(object);
318
319    return jsObject->hasProperty(exec, propertyName->identifier(&exec->vm()));
320}
321
322JSValueRef 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    JSLockHolder locker(exec);
330
331    JSObject* jsObject = toJS(object);
332
333    JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->vm()));
334    if (exec->hadException()) {
335        JSValue exceptionValue = exec->exception();
336        if (exception)
337            *exception = toRef(exec, exceptionValue);
338        exec->clearException();
339#if ENABLE(REMOTE_INSPECTOR)
340        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
341#endif
342    }
343    return toRef(exec, jsValue);
344}
345
346void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
347{
348    if (!ctx) {
349        ASSERT_NOT_REACHED();
350        return;
351    }
352    ExecState* exec = toJS(ctx);
353    JSLockHolder locker(exec);
354
355    JSObject* jsObject = toJS(object);
356    Identifier name(propertyName->identifier(&exec->vm()));
357    JSValue jsValue = toJS(exec, value);
358
359    if (attributes && !jsObject->hasProperty(exec, name)) {
360        PropertyDescriptor desc(jsValue, attributes);
361        jsObject->methodTable()->defineOwnProperty(jsObject, exec, name, desc, false);
362    } else {
363        PutPropertySlot slot(jsObject);
364        jsObject->methodTable()->put(jsObject, exec, name, jsValue, slot);
365    }
366
367    if (exec->hadException()) {
368        JSValue exceptionValue = exec->exception();
369        if (exception)
370            *exception = toRef(exec, exceptionValue);
371        exec->clearException();
372#if ENABLE(REMOTE_INSPECTOR)
373        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
374#endif
375    }
376}
377
378JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
379{
380    if (!ctx) {
381        ASSERT_NOT_REACHED();
382        return 0;
383    }
384    ExecState* exec = toJS(ctx);
385    JSLockHolder locker(exec);
386
387    JSObject* jsObject = toJS(object);
388
389    JSValue jsValue = jsObject->get(exec, propertyIndex);
390    if (exec->hadException()) {
391        JSValue exceptionValue = exec->exception();
392        if (exception)
393            *exception = toRef(exec, exceptionValue);
394        exec->clearException();
395#if ENABLE(REMOTE_INSPECTOR)
396        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
397#endif
398    }
399    return toRef(exec, jsValue);
400}
401
402
403void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception)
404{
405    if (!ctx) {
406        ASSERT_NOT_REACHED();
407        return;
408    }
409    ExecState* exec = toJS(ctx);
410    JSLockHolder locker(exec);
411
412    JSObject* jsObject = toJS(object);
413    JSValue jsValue = toJS(exec, value);
414
415    jsObject->methodTable()->putByIndex(jsObject, exec, propertyIndex, jsValue, false);
416    if (exec->hadException()) {
417        JSValue exceptionValue = exec->exception();
418        if (exception)
419            *exception = toRef(exec, exceptionValue);
420        exec->clearException();
421#if ENABLE(REMOTE_INSPECTOR)
422        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
423#endif
424    }
425}
426
427bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
428{
429    if (!ctx) {
430        ASSERT_NOT_REACHED();
431        return false;
432    }
433    ExecState* exec = toJS(ctx);
434    JSLockHolder locker(exec);
435
436    JSObject* jsObject = toJS(object);
437
438    bool result = jsObject->methodTable()->deleteProperty(jsObject, exec, propertyName->identifier(&exec->vm()));
439    if (exec->hadException()) {
440        JSValue exceptionValue = exec->exception();
441        if (exception)
442            *exception = toRef(exec, exceptionValue);
443        exec->clearException();
444#if ENABLE(REMOTE_INSPECTOR)
445        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
446#endif
447    }
448    return result;
449}
450
451void* JSObjectGetPrivate(JSObjectRef object)
452{
453    JSObject* jsObject = uncheckedToJS(object);
454
455    // Get wrapped object if proxied
456    if (jsObject->inherits(JSProxy::info()))
457        jsObject = jsCast<JSProxy*>(jsObject)->target();
458
459    if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info()))
460        return jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
461    if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info()))
462        return jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivate();
463#if JSC_OBJC_API_ENABLED
464    if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info()))
465        return jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivate();
466#endif
467
468    return 0;
469}
470
471bool JSObjectSetPrivate(JSObjectRef object, void* data)
472{
473    JSObject* jsObject = uncheckedToJS(object);
474
475    // Get wrapped object if proxied
476    if (jsObject->inherits(JSProxy::info()))
477        jsObject = jsCast<JSProxy*>(jsObject)->target();
478
479    if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) {
480        jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
481        return true;
482    }
483    if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) {
484        jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivate(data);
485        return true;
486    }
487#if JSC_OBJC_API_ENABLED
488    if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) {
489        jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivate(data);
490        return true;
491    }
492#endif
493
494    return false;
495}
496
497JSValueRef JSObjectGetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
498{
499    ExecState* exec = toJS(ctx);
500    JSLockHolder locker(exec);
501    JSObject* jsObject = toJS(object);
502    JSValue result;
503    Identifier name(propertyName->identifier(&exec->vm()));
504    if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info()))
505        result = jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivateProperty(name);
506    else if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info()))
507        result = jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->getPrivateProperty(name);
508#if JSC_OBJC_API_ENABLED
509    else if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info()))
510        result = jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->getPrivateProperty(name);
511#endif
512    return toRef(exec, result);
513}
514
515bool JSObjectSetPrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value)
516{
517    ExecState* exec = toJS(ctx);
518    JSLockHolder locker(exec);
519    JSObject* jsObject = toJS(object);
520    JSValue jsValue = value ? toJS(exec, value) : JSValue();
521    Identifier name(propertyName->identifier(&exec->vm()));
522    if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) {
523        jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue);
524        return true;
525    }
526    if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) {
527        jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue);
528        return true;
529    }
530#if JSC_OBJC_API_ENABLED
531    if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) {
532        jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->setPrivateProperty(exec->vm(), name, jsValue);
533        return true;
534    }
535#endif
536    return false;
537}
538
539bool JSObjectDeletePrivateProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
540{
541    ExecState* exec = toJS(ctx);
542    JSLockHolder locker(exec);
543    JSObject* jsObject = toJS(object);
544    Identifier name(propertyName->identifier(&exec->vm()));
545    if (jsObject->inherits(JSCallbackObject<JSGlobalObject>::info())) {
546        jsCast<JSCallbackObject<JSGlobalObject>*>(jsObject)->deletePrivateProperty(name);
547        return true;
548    }
549    if (jsObject->inherits(JSCallbackObject<JSDestructibleObject>::info())) {
550        jsCast<JSCallbackObject<JSDestructibleObject>*>(jsObject)->deletePrivateProperty(name);
551        return true;
552    }
553#if JSC_OBJC_API_ENABLED
554    if (jsObject->inherits(JSCallbackObject<JSAPIWrapperObject>::info())) {
555        jsCast<JSCallbackObject<JSAPIWrapperObject>*>(jsObject)->deletePrivateProperty(name);
556        return true;
557    }
558#endif
559    return false;
560}
561
562bool JSObjectIsFunction(JSContextRef ctx, JSObjectRef object)
563{
564    if (!object)
565        return false;
566    JSLockHolder locker(toJS(ctx));
567    CallData callData;
568    JSCell* cell = toJS(object);
569    return cell->methodTable()->getCallData(cell, callData) != CallTypeNone;
570}
571
572JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
573{
574    ExecState* exec = toJS(ctx);
575    JSLockHolder locker(exec);
576
577    if (!object)
578        return 0;
579
580    JSObject* jsObject = toJS(object);
581    JSObject* jsThisObject = toJS(thisObject);
582
583    if (!jsThisObject)
584        jsThisObject = exec->globalThisValue();
585
586    MarkedArgumentBuffer argList;
587    for (size_t i = 0; i < argumentCount; i++)
588        argList.append(toJS(exec, arguments[i]));
589
590    CallData callData;
591    CallType callType = jsObject->methodTable()->getCallData(jsObject, callData);
592    if (callType == CallTypeNone)
593        return 0;
594
595    JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
596    if (exec->hadException()) {
597        JSValue exceptionValue = exec->exception();
598        if (exception)
599            *exception = toRef(exec, exceptionValue);
600        exec->clearException();
601#if ENABLE(REMOTE_INSPECTOR)
602        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
603#endif
604        result = 0;
605    }
606    return result;
607}
608
609bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
610{
611    if (!object)
612        return false;
613    JSObject* jsObject = toJS(object);
614    ConstructData constructData;
615    return jsObject->methodTable()->getConstructData(jsObject, constructData) != ConstructTypeNone;
616}
617
618JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
619{
620    ExecState* exec = toJS(ctx);
621    JSLockHolder locker(exec);
622
623    if (!object)
624        return 0;
625
626    JSObject* jsObject = toJS(object);
627
628    ConstructData constructData;
629    ConstructType constructType = jsObject->methodTable()->getConstructData(jsObject, constructData);
630    if (constructType == ConstructTypeNone)
631        return 0;
632
633    MarkedArgumentBuffer argList;
634    for (size_t i = 0; i < argumentCount; i++)
635        argList.append(toJS(exec, arguments[i]));
636    JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
637    if (exec->hadException()) {
638        JSValue exceptionValue = exec->exception();
639        if (exception)
640            *exception = toRef(exec, exceptionValue);
641        exec->clearException();
642#if ENABLE(REMOTE_INSPECTOR)
643        exec->vmEntryGlobalObject()->inspectorController().reportAPIException(exec, exceptionValue);
644#endif
645        result = 0;
646    }
647    return result;
648}
649
650struct OpaqueJSPropertyNameArray {
651    WTF_MAKE_FAST_ALLOCATED;
652public:
653    OpaqueJSPropertyNameArray(VM* vm)
654        : refCount(0)
655        , vm(vm)
656    {
657    }
658
659    unsigned refCount;
660    VM* vm;
661    Vector<JSRetainPtr<JSStringRef>> array;
662};
663
664JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
665{
666    if (!ctx) {
667        ASSERT_NOT_REACHED();
668        return 0;
669    }
670    ExecState* exec = toJS(ctx);
671    JSLockHolder locker(exec);
672
673    VM* vm = &exec->vm();
674
675    JSObject* jsObject = toJS(object);
676    JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(vm);
677    PropertyNameArray array(vm);
678    jsObject->methodTable()->getPropertyNames(jsObject, exec, array, ExcludeDontEnumProperties);
679
680    size_t size = array.size();
681    propertyNames->array.reserveInitialCapacity(size);
682    for (size_t i = 0; i < size; ++i)
683        propertyNames->array.uncheckedAppend(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].string()).leakRef()));
684
685    return JSPropertyNameArrayRetain(propertyNames);
686}
687
688JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)
689{
690    ++array->refCount;
691    return array;
692}
693
694void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)
695{
696    if (--array->refCount == 0) {
697        JSLockHolder locker(array->vm);
698        delete array;
699    }
700}
701
702size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
703{
704    return array->array.size();
705}
706
707JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
708{
709    return array->array[static_cast<unsigned>(index)].get();
710}
711
712void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
713{
714    PropertyNameArray* propertyNames = toJS(array);
715    JSLockHolder locker(propertyNames->vm());
716    propertyNames->add(propertyName->identifier(propertyNames->vm()));
717}
718