• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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