2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Kelvin W Sherlock (ksherlock@gmail.com)
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "JSObjectRef.h"
29 #include "JSObjectRefPrivate.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"
42 #include "JSCallbackConstructor.h"
43 #include "JSCallbackFunction.h"
44 #include "JSCallbackObject.h"
45 #include "JSClassRef.h"
46 #include "JSFunction.h"
47 #include "JSGlobalObject.h"
49 #include "JSRetainPtr.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"
60 JSClassRef
JSClassCreate(const JSClassDefinition
* definition
)
62 initializeThreading();
63 RefPtr
<OpaqueJSClass
> jsClass
= (definition
->attributes
& kJSClassAttributeNoAutomaticPrototype
)
64 ? OpaqueJSClass::createNoAutomaticPrototype(definition
)
65 : OpaqueJSClass::create(definition
);
67 return jsClass
.release().leakRef();
70 JSClassRef
JSClassRetain(JSClassRef jsClass
)
76 void JSClassRelease(JSClassRef jsClass
)
81 JSObjectRef
JSObjectMake(JSContextRef ctx
, JSClassRef jsClass
, void* data
)
87 ExecState
* exec
= toJS(ctx
);
88 APIEntryShim
entryShim(exec
);
91 return toRef(constructEmptyObject(exec
));
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
);
100 JSObjectRef
JSObjectMakeFunctionWithCallback(JSContextRef ctx
, JSStringRef name
, JSObjectCallAsFunctionCallback callAsFunction
)
103 ASSERT_NOT_REACHED();
106 ExecState
* exec
= toJS(ctx
);
107 APIEntryShim
entryShim(exec
);
108 return toRef(JSCallbackFunction::create(exec
, exec
->lexicalGlobalObject(), callAsFunction
, name
? name
->string() : ASCIILiteral("anonymous")));
111 JSObjectRef
JSObjectMakeConstructor(JSContextRef ctx
, JSClassRef jsClass
, JSObjectCallAsConstructorCallback callAsConstructor
)
114 ASSERT_NOT_REACHED();
117 ExecState
* exec
= toJS(ctx
);
118 APIEntryShim
entryShim(exec
);
120 JSValue jsPrototype
= jsClass
? jsClass
->prototype(exec
) : 0;
122 jsPrototype
= exec
->lexicalGlobalObject()->objectPrototype();
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
);
129 JSObjectRef
JSObjectMakeFunction(JSContextRef ctx
, JSStringRef name
, unsigned parameterCount
, const JSStringRef parameterNames
[], JSStringRef body
, JSStringRef sourceURL
, int startingLineNumber
, JSValueRef
* exception
)
132 ASSERT_NOT_REACHED();
135 ExecState
* exec
= toJS(ctx
);
136 APIEntryShim
entryShim(exec
);
138 Identifier nameID
= name
? name
->identifier(&exec
->vm()) : Identifier(exec
, "anonymous");
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()));
145 JSObject
* result
= constructFunction(exec
, exec
->lexicalGlobalObject(), args
, nameID
, sourceURL
->string(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber
), OrdinalNumber::first()));
146 if (exec
->hadException()) {
148 *exception
= toRef(exec
, exec
->exception());
149 exec
->clearException();
152 return toRef(result
);
155 JSObjectRef
JSObjectMakeArray(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
158 ASSERT_NOT_REACHED();
161 ExecState
* exec
= toJS(ctx
);
162 APIEntryShim
entryShim(exec
);
166 MarkedArgumentBuffer argList
;
167 for (size_t i
= 0; i
< argumentCount
; ++i
)
168 argList
.append(toJS(exec
, arguments
[i
]));
170 result
= constructArray(exec
, static_cast<ArrayAllocationProfile
*>(0), argList
);
172 result
= constructEmptyArray(exec
, 0);
174 if (exec
->hadException()) {
176 *exception
= toRef(exec
, exec
->exception());
177 exec
->clearException();
181 return toRef(result
);
184 JSObjectRef
JSObjectMakeDate(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
187 ASSERT_NOT_REACHED();
190 ExecState
* exec
= toJS(ctx
);
191 APIEntryShim
entryShim(exec
);
193 MarkedArgumentBuffer argList
;
194 for (size_t i
= 0; i
< argumentCount
; ++i
)
195 argList
.append(toJS(exec
, arguments
[i
]));
197 JSObject
* result
= constructDate(exec
, exec
->lexicalGlobalObject(), argList
);
198 if (exec
->hadException()) {
200 *exception
= toRef(exec
, exec
->exception());
201 exec
->clearException();
205 return toRef(result
);
208 JSObjectRef
JSObjectMakeError(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
211 ASSERT_NOT_REACHED();
214 ExecState
* exec
= toJS(ctx
);
215 APIEntryShim
entryShim(exec
);
217 JSValue message
= argumentCount
? toJS(exec
, arguments
[0]) : jsUndefined();
218 Structure
* errorStructure
= exec
->lexicalGlobalObject()->errorStructure();
219 JSObject
* result
= ErrorInstance::create(exec
, errorStructure
, message
);
221 if (exec
->hadException()) {
223 *exception
= toRef(exec
, exec
->exception());
224 exec
->clearException();
228 return toRef(result
);
231 JSObjectRef
JSObjectMakeRegExp(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
234 ASSERT_NOT_REACHED();
237 ExecState
* exec
= toJS(ctx
);
238 APIEntryShim
entryShim(exec
);
240 MarkedArgumentBuffer argList
;
241 for (size_t i
= 0; i
< argumentCount
; ++i
)
242 argList
.append(toJS(exec
, arguments
[i
]));
244 JSObject
* result
= constructRegExp(exec
, exec
->lexicalGlobalObject(), argList
);
245 if (exec
->hadException()) {
247 *exception
= toRef(exec
, exec
->exception());
248 exec
->clearException();
252 return toRef(result
);
255 JSValueRef
JSObjectGetPrototype(JSContextRef ctx
, JSObjectRef object
)
258 ASSERT_NOT_REACHED();
261 ExecState
* exec
= toJS(ctx
);
262 APIEntryShim
entryShim(exec
);
264 JSObject
* jsObject
= toJS(object
);
265 return toRef(exec
, jsObject
->prototype());
268 void JSObjectSetPrototype(JSContextRef ctx
, JSObjectRef object
, JSValueRef value
)
271 ASSERT_NOT_REACHED();
274 ExecState
* exec
= toJS(ctx
);
275 APIEntryShim
entryShim(exec
);
277 JSObject
* jsObject
= toJS(object
);
278 JSValue jsValue
= toJS(exec
, value
);
280 jsObject
->setPrototypeWithCycleCheck(exec
->vm(), jsValue
.isObject() ? jsValue
: jsNull());
283 bool JSObjectHasProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
)
286 ASSERT_NOT_REACHED();
289 ExecState
* exec
= toJS(ctx
);
290 APIEntryShim
entryShim(exec
);
292 JSObject
* jsObject
= toJS(object
);
294 return jsObject
->hasProperty(exec
, propertyName
->identifier(&exec
->vm()));
297 JSValueRef
JSObjectGetProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
300 ASSERT_NOT_REACHED();
303 ExecState
* exec
= toJS(ctx
);
304 APIEntryShim
entryShim(exec
);
306 JSObject
* jsObject
= toJS(object
);
308 JSValue jsValue
= jsObject
->get(exec
, propertyName
->identifier(&exec
->vm()));
309 if (exec
->hadException()) {
311 *exception
= toRef(exec
, exec
->exception());
312 exec
->clearException();
314 return toRef(exec
, jsValue
);
317 void JSObjectSetProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSPropertyAttributes attributes
, JSValueRef
* exception
)
320 ASSERT_NOT_REACHED();
323 ExecState
* exec
= toJS(ctx
);
324 APIEntryShim
entryShim(exec
);
326 JSObject
* jsObject
= toJS(object
);
327 Identifier
name(propertyName
->identifier(&exec
->vm()));
328 JSValue jsValue
= toJS(exec
, value
);
330 if (attributes
&& !jsObject
->hasProperty(exec
, name
))
331 jsObject
->methodTable()->putDirectVirtual(jsObject
, exec
, name
, jsValue
, attributes
);
333 PutPropertySlot slot
;
334 jsObject
->methodTable()->put(jsObject
, exec
, name
, jsValue
, slot
);
337 if (exec
->hadException()) {
339 *exception
= toRef(exec
, exec
->exception());
340 exec
->clearException();
344 JSValueRef
JSObjectGetPropertyAtIndex(JSContextRef ctx
, JSObjectRef object
, unsigned propertyIndex
, JSValueRef
* exception
)
347 ASSERT_NOT_REACHED();
350 ExecState
* exec
= toJS(ctx
);
351 APIEntryShim
entryShim(exec
);
353 JSObject
* jsObject
= toJS(object
);
355 JSValue jsValue
= jsObject
->get(exec
, propertyIndex
);
356 if (exec
->hadException()) {
358 *exception
= toRef(exec
, exec
->exception());
359 exec
->clearException();
361 return toRef(exec
, jsValue
);
365 void JSObjectSetPropertyAtIndex(JSContextRef ctx
, JSObjectRef object
, unsigned propertyIndex
, JSValueRef value
, JSValueRef
* exception
)
368 ASSERT_NOT_REACHED();
371 ExecState
* exec
= toJS(ctx
);
372 APIEntryShim
entryShim(exec
);
374 JSObject
* jsObject
= toJS(object
);
375 JSValue jsValue
= toJS(exec
, value
);
377 jsObject
->methodTable()->putByIndex(jsObject
, exec
, propertyIndex
, jsValue
, false);
378 if (exec
->hadException()) {
380 *exception
= toRef(exec
, exec
->exception());
381 exec
->clearException();
385 bool JSObjectDeleteProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
388 ASSERT_NOT_REACHED();
391 ExecState
* exec
= toJS(ctx
);
392 APIEntryShim
entryShim(exec
);
394 JSObject
* jsObject
= toJS(object
);
396 bool result
= jsObject
->methodTable()->deleteProperty(jsObject
, exec
, propertyName
->identifier(&exec
->vm()));
397 if (exec
->hadException()) {
399 *exception
= toRef(exec
, exec
->exception());
400 exec
->clearException();
405 void* JSObjectGetPrivate(JSObjectRef object
)
407 JSObject
* jsObject
= uncheckedToJS(object
);
409 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
))
410 return jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->getPrivate();
411 if (jsObject
->inherits(&JSCallbackObject
<JSDestructibleObject
>::s_info
))
412 return jsCast
<JSCallbackObject
<JSDestructibleObject
>*>(jsObject
)->getPrivate();
413 #if JSC_OBJC_API_ENABLED
414 if (jsObject
->inherits(&JSCallbackObject
<JSAPIWrapperObject
>::s_info
))
415 return jsCast
<JSCallbackObject
<JSAPIWrapperObject
>*>(jsObject
)->getPrivate();
421 bool JSObjectSetPrivate(JSObjectRef object
, void* data
)
423 JSObject
* jsObject
= uncheckedToJS(object
);
425 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
)) {
426 jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->setPrivate(data
);
429 if (jsObject
->inherits(&JSCallbackObject
<JSDestructibleObject
>::s_info
)) {
430 jsCast
<JSCallbackObject
<JSDestructibleObject
>*>(jsObject
)->setPrivate(data
);
433 #if JSC_OBJC_API_ENABLED
434 if (jsObject
->inherits(&JSCallbackObject
<JSAPIWrapperObject
>::s_info
)) {
435 jsCast
<JSCallbackObject
<JSAPIWrapperObject
>*>(jsObject
)->setPrivate(data
);
443 JSValueRef
JSObjectGetPrivateProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
)
445 ExecState
* exec
= toJS(ctx
);
446 APIEntryShim
entryShim(exec
);
447 JSObject
* jsObject
= toJS(object
);
449 Identifier
name(propertyName
->identifier(&exec
->vm()));
450 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
))
451 result
= jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->getPrivateProperty(name
);
452 else if (jsObject
->inherits(&JSCallbackObject
<JSDestructibleObject
>::s_info
))
453 result
= jsCast
<JSCallbackObject
<JSDestructibleObject
>*>(jsObject
)->getPrivateProperty(name
);
454 #if JSC_OBJC_API_ENABLED
455 else if (jsObject
->inherits(&JSCallbackObject
<JSAPIWrapperObject
>::s_info
))
456 result
= jsCast
<JSCallbackObject
<JSAPIWrapperObject
>*>(jsObject
)->getPrivateProperty(name
);
458 return toRef(exec
, result
);
461 bool JSObjectSetPrivateProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
)
463 ExecState
* exec
= toJS(ctx
);
464 APIEntryShim
entryShim(exec
);
465 JSObject
* jsObject
= toJS(object
);
466 JSValue jsValue
= value
? toJS(exec
, value
) : JSValue();
467 Identifier
name(propertyName
->identifier(&exec
->vm()));
468 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
)) {
469 jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->setPrivateProperty(exec
->vm(), name
, jsValue
);
472 if (jsObject
->inherits(&JSCallbackObject
<JSDestructibleObject
>::s_info
)) {
473 jsCast
<JSCallbackObject
<JSDestructibleObject
>*>(jsObject
)->setPrivateProperty(exec
->vm(), name
, jsValue
);
476 #if JSC_OBJC_API_ENABLED
477 if (jsObject
->inherits(&JSCallbackObject
<JSAPIWrapperObject
>::s_info
)) {
478 jsCast
<JSCallbackObject
<JSAPIWrapperObject
>*>(jsObject
)->setPrivateProperty(exec
->vm(), name
, jsValue
);
485 bool JSObjectDeletePrivateProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
)
487 ExecState
* exec
= toJS(ctx
);
488 APIEntryShim
entryShim(exec
);
489 JSObject
* jsObject
= toJS(object
);
490 Identifier
name(propertyName
->identifier(&exec
->vm()));
491 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
)) {
492 jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->deletePrivateProperty(name
);
495 if (jsObject
->inherits(&JSCallbackObject
<JSDestructibleObject
>::s_info
)) {
496 jsCast
<JSCallbackObject
<JSDestructibleObject
>*>(jsObject
)->deletePrivateProperty(name
);
499 #if JSC_OBJC_API_ENABLED
500 if (jsObject
->inherits(&JSCallbackObject
<JSAPIWrapperObject
>::s_info
)) {
501 jsCast
<JSCallbackObject
<JSAPIWrapperObject
>*>(jsObject
)->deletePrivateProperty(name
);
508 bool JSObjectIsFunction(JSContextRef
, JSObjectRef object
)
513 JSCell
* cell
= toJS(object
);
514 return cell
->methodTable()->getCallData(cell
, callData
) != CallTypeNone
;
517 JSValueRef
JSObjectCallAsFunction(JSContextRef ctx
, JSObjectRef object
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
519 ExecState
* exec
= toJS(ctx
);
520 APIEntryShim
entryShim(exec
);
525 JSObject
* jsObject
= toJS(object
);
526 JSObject
* jsThisObject
= toJS(thisObject
);
529 jsThisObject
= exec
->globalThisValue();
531 jsThisObject
= jsThisObject
->methodTable()->toThisObject(jsThisObject
, exec
);
533 MarkedArgumentBuffer argList
;
534 for (size_t i
= 0; i
< argumentCount
; i
++)
535 argList
.append(toJS(exec
, arguments
[i
]));
538 CallType callType
= jsObject
->methodTable()->getCallData(jsObject
, callData
);
539 if (callType
== CallTypeNone
)
542 JSValueRef result
= toRef(exec
, call(exec
, jsObject
, callType
, callData
, jsThisObject
, argList
));
543 if (exec
->hadException()) {
545 *exception
= toRef(exec
, exec
->exception());
546 exec
->clearException();
552 bool JSObjectIsConstructor(JSContextRef
, JSObjectRef object
)
556 JSObject
* jsObject
= toJS(object
);
557 ConstructData constructData
;
558 return jsObject
->methodTable()->getConstructData(jsObject
, constructData
) != ConstructTypeNone
;
561 JSObjectRef
JSObjectCallAsConstructor(JSContextRef ctx
, JSObjectRef object
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
563 ExecState
* exec
= toJS(ctx
);
564 APIEntryShim
entryShim(exec
);
569 JSObject
* jsObject
= toJS(object
);
571 ConstructData constructData
;
572 ConstructType constructType
= jsObject
->methodTable()->getConstructData(jsObject
, constructData
);
573 if (constructType
== ConstructTypeNone
)
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()) {
582 *exception
= toRef(exec
, exec
->exception());
583 exec
->clearException();
589 struct OpaqueJSPropertyNameArray
{
590 WTF_MAKE_FAST_ALLOCATED
;
592 OpaqueJSPropertyNameArray(VM
* vm
)
600 Vector
<JSRetainPtr
<JSStringRef
> > array
;
603 JSPropertyNameArrayRef
JSObjectCopyPropertyNames(JSContextRef ctx
, JSObjectRef object
)
606 ASSERT_NOT_REACHED();
609 JSObject
* jsObject
= toJS(object
);
610 ExecState
* exec
= toJS(ctx
);
611 APIEntryShim
entryShim(exec
);
613 VM
* vm
= &exec
->vm();
615 JSPropertyNameArrayRef propertyNames
= new OpaqueJSPropertyNameArray(vm
);
616 PropertyNameArray
array(vm
);
617 jsObject
->methodTable()->getPropertyNames(jsObject
, exec
, array
, ExcludeDontEnumProperties
);
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()));
624 return JSPropertyNameArrayRetain(propertyNames
);
627 JSPropertyNameArrayRef
JSPropertyNameArrayRetain(JSPropertyNameArrayRef array
)
633 void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array
)
635 if (--array
->refCount
== 0) {
636 APIEntryShim
entryShim(array
->vm
, false);
641 size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array
)
643 return array
->array
.size();
646 JSStringRef
JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array
, size_t index
)
648 return array
->array
[static_cast<unsigned>(index
)].get();
651 void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array
, JSStringRef propertyName
)
653 PropertyNameArray
* propertyNames
= toJS(array
);
654 APIEntryShim
entryShim(propertyNames
->vm());
655 propertyNames
->add(propertyName
->identifier(propertyNames
->vm()));