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