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