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 JSValue jsPrototype = jsClass ? jsClass->prototype(exec) : 0;
109 if (!jsPrototype)
110 jsPrototype = 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 MarkedArgumentBuffer 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, 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 MarkedArgumentBuffer argList;
149 for (size_t i = 0; i < argumentCount; ++i)
150 argList.append(toJS(exec, 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, 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 MarkedArgumentBuffer argList;
173 for (size_t i = 0; i < argumentCount; ++i)
174 argList.append(toJS(exec, arguments[i]));
175
176 JSObject* result = constructDate(exec, argList);
177 if (exec->hadException()) {
178 if (exception)
179 *exception = toRef(exec, 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 MarkedArgumentBuffer argList;
194 for (size_t i = 0; i < argumentCount; ++i)
195 argList.append(toJS(exec, arguments[i]));
196
197 JSObject* result = constructError(exec, 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
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 MarkedArgumentBuffer argList;
215 for (size_t i = 0; i < argumentCount; ++i)
216 argList.append(toJS(exec, arguments[i]));
217
218 JSObject* result = constructRegExp(exec, argList);
219 if (exec->hadException()) {
220 if (exception)
221 *exception = toRef(exec, exec->exception());
222 exec->clearException();
223 result = 0;
224 }
225
226 return toRef(result);
227 }
228
JSObjectGetPrototype(JSContextRef ctx,JSObjectRef object)229 JSValueRef JSObjectGetPrototype(JSContextRef ctx, JSObjectRef object)
230 {
231 ExecState* exec = toJS(ctx);
232 exec->globalData().heap.registerThread();
233 JSLock lock(exec);
234
235 JSObject* jsObject = toJS(object);
236 return toRef(exec, jsObject->prototype());
237 }
238
JSObjectSetPrototype(JSContextRef ctx,JSObjectRef object,JSValueRef value)239 void JSObjectSetPrototype(JSContextRef ctx, JSObjectRef object, JSValueRef value)
240 {
241 ExecState* exec = toJS(ctx);
242 exec->globalData().heap.registerThread();
243 JSLock lock(exec);
244
245 JSObject* jsObject = toJS(object);
246 JSValue jsValue = toJS(exec, value);
247
248 jsObject->setPrototype(jsValue.isObject() ? jsValue : jsNull());
249 }
250
JSObjectHasProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName)251 bool JSObjectHasProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName)
252 {
253 ExecState* exec = toJS(ctx);
254 exec->globalData().heap.registerThread();
255 JSLock lock(exec);
256
257 JSObject* jsObject = toJS(object);
258
259 return jsObject->hasProperty(exec, propertyName->identifier(&exec->globalData()));
260 }
261
JSObjectGetProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName,JSValueRef * exception)262 JSValueRef JSObjectGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
263 {
264 ExecState* exec = toJS(ctx);
265 exec->globalData().heap.registerThread();
266 JSLock lock(exec);
267
268 JSObject* jsObject = toJS(object);
269
270 JSValue jsValue = jsObject->get(exec, propertyName->identifier(&exec->globalData()));
271 if (exec->hadException()) {
272 if (exception)
273 *exception = toRef(exec, exec->exception());
274 exec->clearException();
275 }
276 return toRef(exec, jsValue);
277 }
278
JSObjectSetProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName,JSValueRef value,JSPropertyAttributes attributes,JSValueRef * exception)279 void JSObjectSetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSPropertyAttributes attributes, JSValueRef* exception)
280 {
281 ExecState* exec = toJS(ctx);
282 exec->globalData().heap.registerThread();
283 JSLock lock(exec);
284
285 JSObject* jsObject = toJS(object);
286 Identifier name(propertyName->identifier(&exec->globalData()));
287 JSValue jsValue = toJS(exec, value);
288
289 if (attributes && !jsObject->hasProperty(exec, name))
290 jsObject->putWithAttributes(exec, name, jsValue, attributes);
291 else {
292 PutPropertySlot slot;
293 jsObject->put(exec, name, jsValue, slot);
294 }
295
296 if (exec->hadException()) {
297 if (exception)
298 *exception = toRef(exec, exec->exception());
299 exec->clearException();
300 }
301 }
302
JSObjectGetPropertyAtIndex(JSContextRef ctx,JSObjectRef object,unsigned propertyIndex,JSValueRef * exception)303 JSValueRef JSObjectGetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef* exception)
304 {
305 ExecState* exec = toJS(ctx);
306 exec->globalData().heap.registerThread();
307 JSLock lock(exec);
308
309 JSObject* jsObject = toJS(object);
310
311 JSValue jsValue = jsObject->get(exec, propertyIndex);
312 if (exec->hadException()) {
313 if (exception)
314 *exception = toRef(exec, exec->exception());
315 exec->clearException();
316 }
317 return toRef(exec, jsValue);
318 }
319
320
JSObjectSetPropertyAtIndex(JSContextRef ctx,JSObjectRef object,unsigned propertyIndex,JSValueRef value,JSValueRef * exception)321 void JSObjectSetPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned propertyIndex, JSValueRef value, JSValueRef* exception)
322 {
323 ExecState* exec = toJS(ctx);
324 exec->globalData().heap.registerThread();
325 JSLock lock(exec);
326
327 JSObject* jsObject = toJS(object);
328 JSValue jsValue = toJS(exec, value);
329
330 jsObject->put(exec, propertyIndex, jsValue);
331 if (exec->hadException()) {
332 if (exception)
333 *exception = toRef(exec, exec->exception());
334 exec->clearException();
335 }
336 }
337
JSObjectDeleteProperty(JSContextRef ctx,JSObjectRef object,JSStringRef propertyName,JSValueRef * exception)338 bool JSObjectDeleteProperty(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception)
339 {
340 ExecState* exec = toJS(ctx);
341 exec->globalData().heap.registerThread();
342 JSLock lock(exec);
343
344 JSObject* jsObject = toJS(object);
345
346 bool result = jsObject->deleteProperty(exec, propertyName->identifier(&exec->globalData()));
347 if (exec->hadException()) {
348 if (exception)
349 *exception = toRef(exec, exec->exception());
350 exec->clearException();
351 }
352 return result;
353 }
354
JSObjectGetPrivate(JSObjectRef object)355 void* JSObjectGetPrivate(JSObjectRef object)
356 {
357 JSObject* jsObject = toJS(object);
358
359 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info))
360 return static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->getPrivate();
361 else if (jsObject->inherits(&JSCallbackObject<JSObject>::info))
362 return static_cast<JSCallbackObject<JSObject>*>(jsObject)->getPrivate();
363
364 return 0;
365 }
366
JSObjectSetPrivate(JSObjectRef object,void * data)367 bool JSObjectSetPrivate(JSObjectRef object, void* data)
368 {
369 JSObject* jsObject = toJS(object);
370
371 if (jsObject->inherits(&JSCallbackObject<JSGlobalObject>::info)) {
372 static_cast<JSCallbackObject<JSGlobalObject>*>(jsObject)->setPrivate(data);
373 return true;
374 } else if (jsObject->inherits(&JSCallbackObject<JSObject>::info)) {
375 static_cast<JSCallbackObject<JSObject>*>(jsObject)->setPrivate(data);
376 return true;
377 }
378
379 return false;
380 }
381
JSObjectIsFunction(JSContextRef,JSObjectRef object)382 bool JSObjectIsFunction(JSContextRef, JSObjectRef object)
383 {
384 CallData callData;
385 return toJS(object)->getCallData(callData) != CallTypeNone;
386 }
387
JSObjectCallAsFunction(JSContextRef ctx,JSObjectRef object,JSObjectRef thisObject,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)388 JSValueRef JSObjectCallAsFunction(JSContextRef ctx, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
389 {
390 ExecState* exec = toJS(ctx);
391 exec->globalData().heap.registerThread();
392 JSLock lock(exec);
393
394 JSObject* jsObject = toJS(object);
395 JSObject* jsThisObject = toJS(thisObject);
396
397 if (!jsThisObject)
398 jsThisObject = exec->globalThisValue();
399
400 MarkedArgumentBuffer argList;
401 for (size_t i = 0; i < argumentCount; i++)
402 argList.append(toJS(exec, arguments[i]));
403
404 CallData callData;
405 CallType callType = jsObject->getCallData(callData);
406 if (callType == CallTypeNone)
407 return 0;
408
409 JSValueRef result = toRef(exec, call(exec, jsObject, callType, callData, jsThisObject, argList));
410 if (exec->hadException()) {
411 if (exception)
412 *exception = toRef(exec, exec->exception());
413 exec->clearException();
414 result = 0;
415 }
416 return result;
417 }
418
JSObjectIsConstructor(JSContextRef,JSObjectRef object)419 bool JSObjectIsConstructor(JSContextRef, JSObjectRef object)
420 {
421 JSObject* jsObject = toJS(object);
422 ConstructData constructData;
423 return jsObject->getConstructData(constructData) != ConstructTypeNone;
424 }
425
JSObjectCallAsConstructor(JSContextRef ctx,JSObjectRef object,size_t argumentCount,const JSValueRef arguments[],JSValueRef * exception)426 JSObjectRef JSObjectCallAsConstructor(JSContextRef ctx, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
427 {
428 ExecState* exec = toJS(ctx);
429 exec->globalData().heap.registerThread();
430 JSLock lock(exec);
431
432 JSObject* jsObject = toJS(object);
433
434 ConstructData constructData;
435 ConstructType constructType = jsObject->getConstructData(constructData);
436 if (constructType == ConstructTypeNone)
437 return 0;
438
439 MarkedArgumentBuffer argList;
440 for (size_t i = 0; i < argumentCount; i++)
441 argList.append(toJS(exec, arguments[i]));
442 JSObjectRef result = toRef(construct(exec, jsObject, constructType, constructData, argList));
443 if (exec->hadException()) {
444 if (exception)
445 *exception = toRef(exec, exec->exception());
446 exec->clearException();
447 result = 0;
448 }
449 return result;
450 }
451
452 struct OpaqueJSPropertyNameArray : FastAllocBase {
OpaqueJSPropertyNameArrayOpaqueJSPropertyNameArray453 OpaqueJSPropertyNameArray(JSGlobalData* globalData)
454 : refCount(0)
455 , globalData(globalData)
456 {
457 }
458
459 unsigned refCount;
460 JSGlobalData* globalData;
461 Vector<JSRetainPtr<JSStringRef> > array;
462 };
463
JSObjectCopyPropertyNames(JSContextRef ctx,JSObjectRef object)464 JSPropertyNameArrayRef JSObjectCopyPropertyNames(JSContextRef ctx, JSObjectRef object)
465 {
466 JSObject* jsObject = toJS(object);
467 ExecState* exec = toJS(ctx);
468 exec->globalData().heap.registerThread();
469 JSLock lock(exec);
470
471 JSGlobalData* globalData = &exec->globalData();
472
473 JSPropertyNameArrayRef propertyNames = new OpaqueJSPropertyNameArray(globalData);
474 PropertyNameArray array(globalData);
475 jsObject->getPropertyNames(exec, array);
476
477 size_t size = array.size();
478 propertyNames->array.reserveInitialCapacity(size);
479 for (size_t i = 0; i < size; ++i)
480 propertyNames->array.append(JSRetainPtr<JSStringRef>(Adopt, OpaqueJSString::create(array[i].ustring()).releaseRef()));
481
482 return JSPropertyNameArrayRetain(propertyNames);
483 }
484
JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)485 JSPropertyNameArrayRef JSPropertyNameArrayRetain(JSPropertyNameArrayRef array)
486 {
487 ++array->refCount;
488 return array;
489 }
490
JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)491 void JSPropertyNameArrayRelease(JSPropertyNameArrayRef array)
492 {
493 if (--array->refCount == 0) {
494 JSLock lock(array->globalData->isSharedInstance ? LockForReal : SilenceAssertionsOnly);
495 delete array;
496 }
497 }
498
JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)499 size_t JSPropertyNameArrayGetCount(JSPropertyNameArrayRef array)
500 {
501 return array->array.size();
502 }
503
JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array,size_t index)504 JSStringRef JSPropertyNameArrayGetNameAtIndex(JSPropertyNameArrayRef array, size_t index)
505 {
506 return array->array[static_cast<unsigned>(index)].get();
507 }
508
JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array,JSStringRef propertyName)509 void JSPropertyNameAccumulatorAddName(JSPropertyNameAccumulatorRef array, JSStringRef propertyName)
510 {
511 PropertyNameArray* propertyNames = toJS(array);
512
513 propertyNames->globalData()->heap.registerThread();
514 JSLock lock(propertyNames->globalData()->isSharedInstance ? LockForReal : SilenceAssertionsOnly);
515
516 propertyNames->add(propertyName->identifier(propertyNames->globalData()));
517 }
518