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 "CodeBlock.h"
33 #include "DateConstructor.h"
34 #include "ErrorConstructor.h"
35 #include "FunctionConstructor.h"
36 #include "Identifier.h"
37 #include "InitializeThreading.h"
39 #include "JSCallbackConstructor.h"
40 #include "JSCallbackFunction.h"
41 #include "JSCallbackObject.h"
42 #include "JSClassRef.h"
43 #include "JSFunction.h"
44 #include "JSGlobalObject.h"
46 #include "JSRetainPtr.h"
48 #include "JSValueRef.h"
49 #include "ObjectPrototype.h"
50 #include "PropertyNameArray.h"
51 #include "RegExpConstructor.h"
55 JSClassRef
JSClassCreate(const JSClassDefinition
* definition
)
57 initializeThreading();
58 RefPtr
<OpaqueJSClass
> jsClass
= (definition
->attributes
& kJSClassAttributeNoAutomaticPrototype
)
59 ? OpaqueJSClass::createNoAutomaticPrototype(definition
)
60 : OpaqueJSClass::create(definition
);
62 return jsClass
.release().leakRef();
65 JSClassRef
JSClassRetain(JSClassRef jsClass
)
71 void JSClassRelease(JSClassRef jsClass
)
76 JSObjectRef
JSObjectMake(JSContextRef ctx
, JSClassRef jsClass
, void* data
)
78 ExecState
* exec
= toJS(ctx
);
79 APIEntryShim
entryShim(exec
);
82 return toRef(constructEmptyObject(exec
));
84 JSCallbackObject
<JSNonFinalObject
>* object
= JSCallbackObject
<JSNonFinalObject
>::create(exec
, exec
->lexicalGlobalObject(), exec
->lexicalGlobalObject()->callbackObjectStructure(), jsClass
, data
);
85 if (JSObject
* prototype
= jsClass
->prototype(exec
))
86 object
->setPrototype(exec
->globalData(), prototype
);
91 JSObjectRef
JSObjectMakeFunctionWithCallback(JSContextRef ctx
, JSStringRef name
, JSObjectCallAsFunctionCallback callAsFunction
)
93 ExecState
* exec
= toJS(ctx
);
94 APIEntryShim
entryShim(exec
);
96 Identifier nameID
= name
? name
->identifier(&exec
->globalData()) : Identifier(exec
, "anonymous");
98 return toRef(JSCallbackFunction::create(exec
, exec
->lexicalGlobalObject(), callAsFunction
, nameID
));
101 JSObjectRef
JSObjectMakeConstructor(JSContextRef ctx
, JSClassRef jsClass
, JSObjectCallAsConstructorCallback callAsConstructor
)
103 ExecState
* exec
= toJS(ctx
);
104 APIEntryShim
entryShim(exec
);
106 JSValue jsPrototype
= jsClass
? jsClass
->prototype(exec
) : 0;
108 jsPrototype
= exec
->lexicalGlobalObject()->objectPrototype();
110 JSCallbackConstructor
* constructor
= JSCallbackConstructor::create(exec
, exec
->lexicalGlobalObject(), exec
->lexicalGlobalObject()->callbackConstructorStructure(), jsClass
, callAsConstructor
);
111 constructor
->putDirect(exec
->globalData(), exec
->propertyNames().prototype
, jsPrototype
, DontEnum
| DontDelete
| ReadOnly
);
112 return toRef(constructor
);
115 JSObjectRef
JSObjectMakeFunction(JSContextRef ctx
, JSStringRef name
, unsigned parameterCount
, const JSStringRef parameterNames
[], JSStringRef body
, JSStringRef sourceURL
, int startingLineNumber
, JSValueRef
* exception
)
117 ExecState
* exec
= toJS(ctx
);
118 APIEntryShim
entryShim(exec
);
120 Identifier nameID
= name
? name
->identifier(&exec
->globalData()) : Identifier(exec
, "anonymous");
122 MarkedArgumentBuffer args
;
123 for (unsigned i
= 0; i
< parameterCount
; i
++)
124 args
.append(jsString(exec
, parameterNames
[i
]->ustring()));
125 args
.append(jsString(exec
, body
->ustring()));
127 JSObject
* result
= constructFunction(exec
, exec
->lexicalGlobalObject(), args
, nameID
, sourceURL
->ustring(), TextPosition(OrdinalNumber::fromOneBasedInt(startingLineNumber
), OrdinalNumber::first()));
128 if (exec
->hadException()) {
130 *exception
= toRef(exec
, exec
->exception());
131 exec
->clearException();
134 return toRef(result
);
137 JSObjectRef
JSObjectMakeArray(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
139 ExecState
* exec
= toJS(ctx
);
140 APIEntryShim
entryShim(exec
);
144 MarkedArgumentBuffer argList
;
145 for (size_t i
= 0; i
< argumentCount
; ++i
)
146 argList
.append(toJS(exec
, arguments
[i
]));
148 result
= constructArray(exec
, argList
);
150 result
= constructEmptyArray(exec
);
152 if (exec
->hadException()) {
154 *exception
= toRef(exec
, exec
->exception());
155 exec
->clearException();
159 return toRef(result
);
162 JSObjectRef
JSObjectMakeDate(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
164 ExecState
* exec
= toJS(ctx
);
165 APIEntryShim
entryShim(exec
);
167 MarkedArgumentBuffer argList
;
168 for (size_t i
= 0; i
< argumentCount
; ++i
)
169 argList
.append(toJS(exec
, arguments
[i
]));
171 JSObject
* result
= constructDate(exec
, exec
->lexicalGlobalObject(), argList
);
172 if (exec
->hadException()) {
174 *exception
= toRef(exec
, exec
->exception());
175 exec
->clearException();
179 return toRef(result
);
182 JSObjectRef
JSObjectMakeError(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
184 ExecState
* exec
= toJS(ctx
);
185 APIEntryShim
entryShim(exec
);
187 JSValue message
= argumentCount
? toJS(exec
, arguments
[0]) : jsUndefined();
188 Structure
* errorStructure
= exec
->lexicalGlobalObject()->errorStructure();
189 JSObject
* result
= ErrorInstance::create(exec
, errorStructure
, message
);
191 if (exec
->hadException()) {
193 *exception
= toRef(exec
, exec
->exception());
194 exec
->clearException();
198 return toRef(result
);
201 JSObjectRef
JSObjectMakeRegExp(JSContextRef ctx
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
203 ExecState
* exec
= toJS(ctx
);
204 APIEntryShim
entryShim(exec
);
206 MarkedArgumentBuffer argList
;
207 for (size_t i
= 0; i
< argumentCount
; ++i
)
208 argList
.append(toJS(exec
, arguments
[i
]));
210 JSObject
* result
= constructRegExp(exec
, exec
->lexicalGlobalObject(), argList
);
211 if (exec
->hadException()) {
213 *exception
= toRef(exec
, exec
->exception());
214 exec
->clearException();
218 return toRef(result
);
221 JSValueRef
JSObjectGetPrototype(JSContextRef ctx
, JSObjectRef object
)
223 ExecState
* exec
= toJS(ctx
);
224 APIEntryShim
entryShim(exec
);
226 JSObject
* jsObject
= toJS(object
);
227 return toRef(exec
, jsObject
->prototype());
230 void JSObjectSetPrototype(JSContextRef ctx
, JSObjectRef object
, JSValueRef value
)
232 ExecState
* exec
= toJS(ctx
);
233 APIEntryShim
entryShim(exec
);
235 JSObject
* jsObject
= toJS(object
);
236 JSValue jsValue
= toJS(exec
, value
);
238 jsObject
->setPrototypeWithCycleCheck(exec
->globalData(), jsValue
.isObject() ? jsValue
: jsNull());
241 bool JSObjectHasProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
)
243 ExecState
* exec
= toJS(ctx
);
244 APIEntryShim
entryShim(exec
);
246 JSObject
* jsObject
= toJS(object
);
248 return jsObject
->hasProperty(exec
, propertyName
->identifier(&exec
->globalData()));
251 JSValueRef
JSObjectGetProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
253 ExecState
* exec
= toJS(ctx
);
254 APIEntryShim
entryShim(exec
);
256 JSObject
* jsObject
= toJS(object
);
258 JSValue jsValue
= jsObject
->get(exec
, propertyName
->identifier(&exec
->globalData()));
259 if (exec
->hadException()) {
261 *exception
= toRef(exec
, exec
->exception());
262 exec
->clearException();
264 return toRef(exec
, jsValue
);
267 void JSObjectSetProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
, JSPropertyAttributes attributes
, JSValueRef
* exception
)
269 ExecState
* exec
= toJS(ctx
);
270 APIEntryShim
entryShim(exec
);
272 JSObject
* jsObject
= toJS(object
);
273 Identifier
name(propertyName
->identifier(&exec
->globalData()));
274 JSValue jsValue
= toJS(exec
, value
);
276 if (attributes
&& !jsObject
->hasProperty(exec
, name
))
277 jsObject
->methodTable()->putDirectVirtual(jsObject
, exec
, name
, jsValue
, attributes
);
279 PutPropertySlot slot
;
280 jsObject
->methodTable()->put(jsObject
, exec
, name
, jsValue
, slot
);
283 if (exec
->hadException()) {
285 *exception
= toRef(exec
, exec
->exception());
286 exec
->clearException();
290 JSValueRef
JSObjectGetPropertyAtIndex(JSContextRef ctx
, JSObjectRef object
, unsigned propertyIndex
, JSValueRef
* exception
)
292 ExecState
* exec
= toJS(ctx
);
293 APIEntryShim
entryShim(exec
);
295 JSObject
* jsObject
= toJS(object
);
297 JSValue jsValue
= jsObject
->get(exec
, propertyIndex
);
298 if (exec
->hadException()) {
300 *exception
= toRef(exec
, exec
->exception());
301 exec
->clearException();
303 return toRef(exec
, jsValue
);
307 void JSObjectSetPropertyAtIndex(JSContextRef ctx
, JSObjectRef object
, unsigned propertyIndex
, JSValueRef value
, JSValueRef
* exception
)
309 ExecState
* exec
= toJS(ctx
);
310 APIEntryShim
entryShim(exec
);
312 JSObject
* jsObject
= toJS(object
);
313 JSValue jsValue
= toJS(exec
, value
);
315 jsObject
->methodTable()->putByIndex(jsObject
, exec
, propertyIndex
, jsValue
, false);
316 if (exec
->hadException()) {
318 *exception
= toRef(exec
, exec
->exception());
319 exec
->clearException();
323 bool JSObjectDeleteProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef
* exception
)
325 ExecState
* exec
= toJS(ctx
);
326 APIEntryShim
entryShim(exec
);
328 JSObject
* jsObject
= toJS(object
);
330 bool result
= jsObject
->methodTable()->deleteProperty(jsObject
, exec
, propertyName
->identifier(&exec
->globalData()));
331 if (exec
->hadException()) {
333 *exception
= toRef(exec
, exec
->exception());
334 exec
->clearException();
339 void* JSObjectGetPrivate(JSObjectRef object
)
341 JSObject
* jsObject
= toJS(object
);
343 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
))
344 return jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->getPrivate();
345 if (jsObject
->inherits(&JSCallbackObject
<JSNonFinalObject
>::s_info
))
346 return jsCast
<JSCallbackObject
<JSNonFinalObject
>*>(jsObject
)->getPrivate();
351 bool JSObjectSetPrivate(JSObjectRef object
, void* data
)
353 JSObject
* jsObject
= toJS(object
);
355 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
)) {
356 jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->setPrivate(data
);
359 if (jsObject
->inherits(&JSCallbackObject
<JSNonFinalObject
>::s_info
)) {
360 jsCast
<JSCallbackObject
<JSNonFinalObject
>*>(jsObject
)->setPrivate(data
);
367 JSValueRef
JSObjectGetPrivateProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
)
369 ExecState
* exec
= toJS(ctx
);
370 APIEntryShim
entryShim(exec
);
371 JSObject
* jsObject
= toJS(object
);
373 Identifier
name(propertyName
->identifier(&exec
->globalData()));
374 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
))
375 result
= jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->getPrivateProperty(name
);
376 else if (jsObject
->inherits(&JSCallbackObject
<JSNonFinalObject
>::s_info
))
377 result
= jsCast
<JSCallbackObject
<JSNonFinalObject
>*>(jsObject
)->getPrivateProperty(name
);
378 return toRef(exec
, result
);
381 bool JSObjectSetPrivateProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
, JSValueRef value
)
383 ExecState
* exec
= toJS(ctx
);
384 APIEntryShim
entryShim(exec
);
385 JSObject
* jsObject
= toJS(object
);
386 JSValue jsValue
= value
? toJS(exec
, value
) : JSValue();
387 Identifier
name(propertyName
->identifier(&exec
->globalData()));
388 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
)) {
389 jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->setPrivateProperty(exec
->globalData(), name
, jsValue
);
392 if (jsObject
->inherits(&JSCallbackObject
<JSNonFinalObject
>::s_info
)) {
393 jsCast
<JSCallbackObject
<JSNonFinalObject
>*>(jsObject
)->setPrivateProperty(exec
->globalData(), name
, jsValue
);
399 bool JSObjectDeletePrivateProperty(JSContextRef ctx
, JSObjectRef object
, JSStringRef propertyName
)
401 ExecState
* exec
= toJS(ctx
);
402 APIEntryShim
entryShim(exec
);
403 JSObject
* jsObject
= toJS(object
);
404 Identifier
name(propertyName
->identifier(&exec
->globalData()));
405 if (jsObject
->inherits(&JSCallbackObject
<JSGlobalObject
>::s_info
)) {
406 jsCast
<JSCallbackObject
<JSGlobalObject
>*>(jsObject
)->deletePrivateProperty(name
);
409 if (jsObject
->inherits(&JSCallbackObject
<JSNonFinalObject
>::s_info
)) {
410 jsCast
<JSCallbackObject
<JSNonFinalObject
>*>(jsObject
)->deletePrivateProperty(name
);
416 bool JSObjectIsFunction(JSContextRef
, JSObjectRef object
)
419 JSCell
* cell
= toJS(object
);
420 return cell
->methodTable()->getCallData(cell
, callData
) != CallTypeNone
;
423 JSValueRef
JSObjectCallAsFunction(JSContextRef ctx
, JSObjectRef object
, JSObjectRef thisObject
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
425 ExecState
* exec
= toJS(ctx
);
426 APIEntryShim
entryShim(exec
);
428 JSObject
* jsObject
= toJS(object
);
429 JSObject
* jsThisObject
= toJS(thisObject
);
432 jsThisObject
= exec
->globalThisValue();
434 MarkedArgumentBuffer argList
;
435 for (size_t i
= 0; i
< argumentCount
; i
++)
436 argList
.append(toJS(exec
, arguments
[i
]));
439 CallType callType
= jsObject
->methodTable()->getCallData(jsObject
, callData
);
440 if (callType
== CallTypeNone
)
443 JSValueRef result
= toRef(exec
, call(exec
, jsObject
, callType
, callData
, jsThisObject
, argList
));
444 if (exec
->hadException()) {
446 *exception
= toRef(exec
, exec
->exception());
447 exec
->clearException();
453 bool JSObjectIsConstructor(JSContextRef
, JSObjectRef object
)
455 JSObject
* jsObject
= toJS(object
);
456 ConstructData constructData
;
457 return jsObject
->methodTable()->getConstructData(jsObject
, constructData
) != ConstructTypeNone
;
460 JSObjectRef
JSObjectCallAsConstructor(JSContextRef ctx
, JSObjectRef object
, size_t argumentCount
, const JSValueRef arguments
[], JSValueRef
* exception
)
462 ExecState
* exec
= toJS(ctx
);
463 APIEntryShim
entryShim(exec
);
465 JSObject
* jsObject
= toJS(object
);
467 ConstructData constructData
;
468 ConstructType constructType
= jsObject
->methodTable()->getConstructData(jsObject
, constructData
);
469 if (constructType
== ConstructTypeNone
)
472 MarkedArgumentBuffer argList
;
473 for (size_t i
= 0; i
< argumentCount
; i
++)
474 argList
.append(toJS(exec
, arguments
[i
]));
475 JSObjectRef result
= toRef(construct(exec
, jsObject
, constructType
, constructData
, argList
));
476 if (exec
->hadException()) {
478 *exception
= toRef(exec
, exec
->exception());
479 exec
->clearException();
485 struct OpaqueJSPropertyNameArray
{
486 WTF_MAKE_FAST_ALLOCATED
;
488 OpaqueJSPropertyNameArray(JSGlobalData
* globalData
)
490 , globalData(globalData
)
495 JSGlobalData
* globalData
;
496 Vector
<JSRetainPtr
<JSStringRef
> > array
;
499 JSPropertyNameArrayRef
JSObjectCopyPropertyNames(JSContextRef ctx
, JSObjectRef object
)
501 JSObject
* jsObject
= toJS(object
);
502 ExecState
* exec
= toJS(ctx
);
503 APIEntryShim
entryShim(exec
);
505 JSGlobalData
* globalData
= &exec
->globalData();
507 JSPropertyNameArrayRef propertyNames
= new OpaqueJSPropertyNameArray(globalData
);
508 PropertyNameArray
array(globalData
);
509 jsObject
->methodTable()->getPropertyNames(jsObject
, exec
, array
, ExcludeDontEnumProperties
);
511 size_t size
= array
.size();
512 propertyNames
->array
.reserveInitialCapacity(size
);
513 for (size_t i
= 0; i
< size
; ++i
)
514 propertyNames
->array
.append(JSRetainPtr
<JSStringRef
>(Adopt
, OpaqueJSString::create(array
[i
].ustring()).leakRef()));
516 return JSPropertyNameArrayRetain(propertyNames
);
519 JSPropertyNameArrayRef
JSPropertyNameArrayRetain(JSPropertyNameArrayRef array
)
525 void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array
)
527 if (--array
->refCount
== 0) {
528 APIEntryShim
entryShim(array
->globalData
, false);
533 size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array
)
535 return array
->array
.size();
538 JSStringRef
JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array
, size_t index
)
540 return array
->array
[static_cast<unsigned>(index
)].get();
543 void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array
, JSStringRef propertyName
)
545 PropertyNameArray
* propertyNames
= toJS(array
);
546 APIEntryShim
entryShim(propertyNames
->globalData());
547 propertyNames
->add(propertyName
->identifier(propertyNames
->globalData()));