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
30 #include "APICast.h"
31 #include "DateConstructor.h"
32 #include "ErrorConstructor.h"
33 #include "FunctionConstructor.h"
34 #include "Identifier.h"
35 #include "InitializeThreading.h"
36 #include "JSArray.h"
37 #include "JSCallbackConstructor.h"
38 #include "JSCallbackFunction.h"
39 #include "JSCallbackObject.h"
40 #include "JSClassRef.h"
41 #include "JSFunction.h"
42 #include "JSGlobalObject.h"
43 #include "JSObject.h"
44 #include "JSRetainPtr.h"
45 #include "JSString.h"
46 #include "JSValueRef.h"
47 #include "ObjectPrototype.h"
48 #include "PropertyNameArray.h"
49 #include "RegExpConstructor.h"
50 #include <wtf/Platform.h>
51
52 using namespace JSC;
53
JSClassCreate(const JSClassDefinition * definition)54 JSClassRef JSClassCreate(const JSClassDefinition* definition)
55 {
56 initializeThreading();
57 RefPtr<OpaqueJSClass> jsClass = (definition->attributes & kJSClassAttributeNoAutomaticPrototype)
58 ? OpaqueJSClass::createNoAutomaticPrototype(definition)
59 : OpaqueJSClass::create(definition);
60
61 return jsClass.release().releaseRef();
62 }
63
JSClassRetain(JSClassRef jsClass)64 JSClassRef JSClassRetain(JSClassRef jsClass)
65 {
66 jsClass->ref();
67 return jsClass;
68 }
69
JSClassRelease(JSClassRef jsClass)70 void JSClassRelease(JSClassRef jsClass)
71 {
72 jsClass->deref();
73 }
74
JSObjectMake(JSContextRef ctx,JSClassRef jsClass,void * data)75 JSObjectRef JSObjectMake(JSContextRef ctx, JSClassRef jsClass, void* data)
76 {
77 ExecState* exec = toJS(ctx);
78 exec->globalData().heap.registerThread();
79 JSLock lock(exec);
80
81 if (!jsClass)
82 return toRef(new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure())); // slightly more efficient
83
84 JSCallbackObject<JSObject>* object = new (exec) JSCallbackObject<JSObject>(exec, exec->lexicalGlobalObject()->callbackObjectStructure(), jsClass, data);
85 if (JSObject* prototype = jsClass->prototype(exec))
86 object->setPrototype(prototype);
87
88 return toRef(object);
89 }
90
JSObjectMakeFunctionWithCallback(JSContextRef ctx,JSStringRef name,JSObjectCallAsFunctionCallback callAsFunction)91 JSObjectRef JSObjectMakeFunctionWithCallback(JSContextRef ctx, JSStringRef name, JSObjectCallAsFunctionCallback callAsFunction)
92 {
93 ExecState* exec = toJS(ctx);
94 exec->globalData().heap.registerThread();
95 JSLock lock(exec);
96
97 Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous");
98
99 return toRef(new (exec) JSCallbackFunction(exec, callAsFunction, nameID));
100 }
101
JSObjectMakeConstructor(JSContextRef ctx,JSClassRef jsClass,JSObjectCallAsConstructorCallback callAsConstructor)102 JSObjectRef JSObjectMakeConstructor(JSContextRef ctx, JSClassRef jsClass, JSObjectCallAsConstructorCallback callAsConstructor)
103 {
104 ExecState* exec = toJS(ctx);
105 exec->globalData().heap.registerThread();
106 JSLock lock(exec);
107
108 JSValuePtr jsPrototype = jsClass
109 ? jsClass->prototype(exec)
110 : exec->lexicalGlobalObject()->objectPrototype();
111
112 JSCallbackConstructor* constructor = new (exec) JSCallbackConstructor(exec->lexicalGlobalObject()->callbackConstructorStructure(), jsClass, callAsConstructor);
113 constructor->putDirect(exec->propertyNames().prototype, jsPrototype, DontEnum | DontDelete | ReadOnly);
114 return toRef(constructor);
115 }
116
JSObjectMakeFunction(JSContextRef ctx,JSStringRef name,unsigned parameterCount,const JSStringRef parameterNames[],JSStringRef body,JSStringRef sourceURL,int startingLineNumber,JSValueRef * exception)117 JSObjectRef JSObjectMakeFunction(JSContextRef ctx, JSStringRef name, unsigned parameterCount, const JSStringRef parameterNames[], JSStringRef body, JSStringRef sourceURL, int startingLineNumber, JSValueRef* exception)
118 {
119 ExecState* exec = toJS(ctx);
120 exec->globalData().heap.registerThread();
121 JSLock lock(exec);
122
123 Identifier nameID = name ? name->identifier(&exec->globalData()) : Identifier(exec, "anonymous");
124
125 ArgList args;
126 for (unsigned i = 0; i < parameterCount; i++)
127 args.append(jsString(exec, parameterNames[i]->ustring()));
128 args.append(jsString(exec, body->ustring()));
129
130 JSObject* result = constructFunction(exec, args, nameID, sourceURL->ustring(), startingLineNumber);
131 if (exec->hadException()) {
132 if (exception)
133 *exception = toRef(exec->exception());
134 exec->clearException();
135 result = 0;
136 }
137 return toRef(result);
138 }
139
JSObjectMakeArray(JSContextRef ctx,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)140 JSObjectRef JSObjectMakeArray(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
141 {
142 ExecState* exec = toJS(ctx);
143 exec->globalData().heap.registerThread();
144 JSLock lock(exec);
145
146 JSObject* result;
147 if (argumentCount) {
148 ArgList argList;
149 for (size_t i = 0; i < argumentCount; ++i)
150 argList.append(toJS(arguments[i]));
151
152 result = constructArray(exec, argList);
153 } else
154 result = constructEmptyArray(exec);
155
156 if (exec->hadException()) {
157 if (exception)
158 *exception = toRef(exec->exception());
159 exec->clearException();
160 result = 0;
161 }
162
163 return toRef(result);
164 }
165
JSObjectMakeDate(JSContextRef ctx,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)166 JSObjectRef JSObjectMakeDate(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
167 {
168 ExecState* exec = toJS(ctx);
169 exec->globalData().heap.registerThread();
170 JSLock lock(exec);
171
172 ArgList argList;
173 for (size_t i = 0; i < argumentCount; ++i)
174 argList.append(toJS(arguments[i]));
175
176 JSObject* result = constructDate(exec, argList);
177 if (exec->hadException()) {
178 if (exception)
179 *exception = toRef(exec->exception());
180 exec->clearException();
181 result = 0;
182 }
183
184 return toRef(result);
185 }
186
JSObjectMakeError(JSContextRef ctx,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)187 JSObjectRef JSObjectMakeError(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
188 {
189 ExecState* exec = toJS(ctx);
190 exec->globalData().heap.registerThread();
191 JSLock lock(exec);
192
193 ArgList argList;
194 for (size_t i = 0; i < argumentCount; ++i)
195 argList.append(toJS(arguments[i]));
196
197 JSObject* result = constructError(exec, argList);
198 if (exec->hadException()) {
199 if (exception)
200 *exception = toRef(exec->exception());
201 exec->clearException();
202 result = 0;
203 }
204
205 return toRef(result);
206 }
207
JSObjectMakeRegExp(JSContextRef ctx,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)208 JSObjectRef JSObjectMakeRegExp(JSContextRef ctx, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
209 {
210 ExecState* exec = toJS(ctx);
211 exec->globalData().heap.registerThread();
212 JSLock lock(exec);
213
214 ArgList argList;
215 for (size_t i = 0; i < argumentCount; ++i)
216 argList.append(toJS(arguments[i]));
217
218 JSObject* result = constructRegExp(exec, argList);
219 if (exec->hadException()) {
220 if (exception)
221 *exception = toRef(exec->exception());
222 exec->clearException();
223 result = 0;
224 }
225
226 return toRef(result);
227 }
228
JSObjectGetPrototype(JSContextRef,JSObjectRef object)229 JSValueRef JSObjectGetPrototype(JSContextRef, JSObjectRef object)
230 {
231 JSObject* jsObject = toJS(object);
232 return toRef(jsObject->prototype());
233 }
234
JSObjectSetPrototype(JSContextRef,JSObjectRef object,JSValueRef value)235 void JSObjectSetPrototype(JSContextRef, JSObjectRef object, JSValueRef value)
236 {
237 JSObject* jsObject = toJS(object);
238 JSValuePtr jsValue = toJS(value);
239
240 jsObject->setPrototype(jsValue.isObject() ? jsValue : jsNull());
241 }
242
JSObjectHasProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName)243 bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
244 {
245 ExecState* exec = toJS(ctx);
246 exec->globalData().heap.registerThread();
247 JSLock lock(exec);
248
249 JSObject* jsObject = toJS(object);
250
251 return jsObject->hasProperty(exec, propertyName->identifier(&exec->globalData()));
252 }
253
JSObjectGetProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName,JSValueRef * exception)254 JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
255 {
256 ExecState* exec = toJS(ctx);
257 exec->globalData().heap.registerThread();
258 JSLock lock(exec);
259
260 JSObject* jsObject = toJS(object);
261
262 JSValuePtr jsValue = jsObject->get(exec, propertyName->identifier(&exec->globalData()));
263 if (exec->hadException()) {
264 if (exception)
265 *exception = toRef(exec->exception());
266 exec->clearException();
267 }
268 return toRef(jsValue);
269 }
270
JSObjectSetProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName,JSValueRef value,JSPropertyAttributes attributes,JSValueRef * exception)271 void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
272 {
273 ExecState* exec = toJS(ctx);
274 exec->globalData().heap.registerThread();
275 JSLock lock(exec);
276
277 JSObject* jsObject = toJS(object);
278 Identifier name(propertyName->identifier(&exec->globalData()));
279 JSValuePtr jsValue = toJS(value);
280
281 if (attributes && !jsObject->hasProperty(exec, name))
282 jsObject->putWithAttributes(exec, name, jsValue, attributes);
283 else {
284 PutPropertySlot slot;
285 jsObject->put(exec, name, jsValue, slot);
286 }
287
288 if (exec->hadException()) {
289 if (exception)
290 *exception = toRef(exec->exception());
291 exec->clearException();
292 }
293 }
294
JSObjectGetPropertyAtIndex(JSContextRef ctx,JSObjectRef object,unsigned propertyIndex,JSValueRef * exception)295 JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
296 {
297 ExecState* exec = toJS(ctx);
298 exec->globalData().heap.registerThread();
299 JSLock lock(exec);
300
301 JSObject* jsObject = toJS(object);
302
303 JSValuePtr jsValue = jsObject->get(exec, propertyIndex);
304 if (exec->hadException()) {
305 if (exception)
306 *exception = toRef(exec->exception());
307 exec->clearException();
308 }
309 return toRef(jsValue);
310 }
311
312
JSObjectSetPropertyAtIndex(JSContextRef ctx,JSObjectRef object,unsigned propertyIndex,JSValueRef value,JSValueRef * exception)313 void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception)
314 {
315 ExecState* exec = toJS(ctx);
316 exec->globalData().heap.registerThread();
317 JSLock lock(exec);
318
319 JSObject* jsObject = toJS(object);
320 JSValuePtr jsValue = toJS(value);
321
322 jsObject->put(exec, propertyIndex, jsValue);
323 if (exec->hadException()) {
324 if (exception)
325 *exception = toRef(exec->exception());
326 exec->clearException();
327 }
328 }
329
JSObjectDeleteProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName,JSValueRef * exception)330 bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
331 {
332 ExecState* exec = toJS(ctx);
333 exec->globalData().heap.registerThread();
334 JSLock lock(exec);
335
336 JSObject* jsObject = toJS(object);
337
338 bool result = jsObject->deleteProperty(exec, propertyName->identifier(&exec->globalData()));
339 if (exec->hadException()) {
340 if (exception)
341 *exception = toRef(exec->exception());
342 exec->clearException();
343 }
344 return result;
345 }
346
JSObjectGetPrivate(JSObjectRef object)347 void* JSObjectGetPrivate(JSObjectRef object)
348 {
349 JSObject* jsObject = toJS(object);
350
351 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info))
352 return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
353 else if (jsObject->inherits(&JSCallbackObject<JSObject>::info))
354 return static_cast<JSCallbackObject<JSObject>*>(jsObject)->getPrivate();
355
356 return 0;
357 }
358
JSObjectSetPrivate(JSObjectRef object,void * data)359 bool JSObjectSetPrivate(JSObjectRef object, void* data)
360 {
361 JSObject* jsObject = toJS(object);
362
363 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
364 static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
365 return true;
366 } else if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
367 static_cast<JSCallbackObject<JSObject>*>(jsObject)->setPrivate(data);
368 return true;
369 }
370
371 return false;
372 }
373
JSObjectIsFunction(JSContextRef,JSObjectRef object)374 bool JSObjectIsFunction(JSContextRef, JSObjectRef object)
375 {
376 CallData callData;
377 return toJS(object)->getCallData(callData) != CallTypeNone;
378 }
379
JSObjectCallAsFunction(JSContextRef ctx,JSObjectRef object,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)380 JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
381 {
382 ExecState* exec = toJS(ctx);
383 exec->globalData().heap.registerThread();
384 JSLock lock(exec);
385
386 JSObject* jsObject = toJS(object);
387 JSObject* jsThisObject = toJS(thisObject);
388
389 if (!jsThisObject)
390 jsThisObject = exec->globalThisValue();
391
392 ArgList argList;
393 for (size_t i = 0; i < argumentCount; i++)
394 argList.append(toJS(arguments[i]));
395
396 CallData callData;
397 CallType callType = jsObject->getCallData(callData);
398 if (callType == CallTypeNone)
399 return 0;
400
401 JSValueRef result = toRef(call(exec, jsObject, callType, callData, jsThisObject, argList));
402 if (exec->hadException()) {
403 if (exception)
404 *exception = toRef(exec->exception());
405 exec->clearException();
406 result = 0;
407 }
408 return result;
409 }
410
JSObjectIsConstructor(JSContextRef,JSObjectRef object)411 bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
412 {
413 JSObject* jsObject = toJS(object);
414 ConstructData constructData;
415 return jsObject->getConstructData(constructData) != ConstructTypeNone;
416 }
417
JSObjectCallAsConstructor(JSContextRef ctx,JSObjectRef object,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)418 JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
419 {
420 ExecState* exec = toJS(ctx);
421 exec->globalData().heap.registerThread();
422 JSLock lock(exec);
423
424 JSObject* jsObject = toJS(object);
425
426 ConstructData constructData;
427 ConstructType constructType = jsObject->getConstructData(constructData);
428 if (constructType == ConstructTypeNone)
429 return 0;
430
431 ArgList argList;
432 for (size_t i = 0; i < argumentCount; i++)
433 argList.append(toJS(arguments[i]));
434 JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
435 if (exec->hadException()) {
436 if (exception)
437 *exception = toRef(exec->exception());
438 exec->clearException();
439 result = 0;
440 }
441 return result;
442 }
443
444 struct OpaqueJSPropertyNameArray {
OpaqueJSPropertyNameArrayOpaqueJSPropertyNameArray445 OpaqueJSPropertyNameArray(JSGlobalData* globalData)
446 : refCount(0)
447 , globalData(globalData)
448 {
449 }
450
451 unsigned refCount;
452 JSGlobalData* globalData;
453 Vector<JSRetainPtr<JSStringRef> > array;
454 };
455
JSObjectCopyPropertyNames(JSContextRef ctx,JSObjectRef object)456 JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
457 {
458 JSObject* jsObject = toJS(object);
459 ExecState* exec = toJS(ctx);
460 exec->globalData().heap.registerThread();
461 JSLock lock(exec);
462
463 JSGlobalData* globalData = &exec->globalData();
464
465 JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(globalData);
466 PropertyNameArray array(globalData);
467 jsObject->getPropertyNames(exec, array);
468
469 size_t size = array.size();
470 propertyNames->array.reserveCapacity(size);
471 for (size_t i = 0; i < size; ++i)
472 propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).releaseRef()));
473
474 return JSPropertyNameArrayRetain(propertyNames);
475 }
476
JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)477 JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)
478 {
479 ++array->refCount;
480 return array;
481 }
482
JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)483 void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)
484 {
485 if (--array->refCount == 0) {
486 JSLock lock(array->globalData->isSharedInstance);
487 delete array;
488 }
489 }
490
JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)491 size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
492 {
493 return array->array.size();
494 }
495
JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array,size_t index)496 JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
497 {
498 return array->array[static_cast<unsigned>(index)].get();
499 }
500
JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array,JSStringRef propertyName)501 void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
502 {
503 PropertyNameArray* propertyNames = toJS(array);
504
505 propertyNames->globalData()->heap.registerThread();
506 JSLock lock(propertyNames->globalData()->isSharedInstance);
507
508 propertyNames->add(propertyName->identifier(propertyNames->globalData()));
509 }
510