2009-02-09 John Grabowski <jrg@chromium.org>
[WebKit-https.git] / JavaScriptGlue / JavaScriptGlue.cpp
1 /*
2  * Copyright (C) 2005 Apple Computer, Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
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  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #include "config.h"
30 #include "JavaScriptGlue.h"
31 #include "JSUtils.h"
32 #include "JSBase.h"
33 #include "JSObject.h"
34 #include "JSRun.h"
35 #include <JavaScriptCore/Completion.h>
36 #include <JavaScriptCore/InitializeThreading.h>
37
38 static CFTypeRef sJSCFNullRef = 0;
39
40 static void CFJSObjectDispose(void *data);
41 static JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName);
42 static void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue);
43 static CFTypeRef CFJSObjectCopyCFValue(void *data);
44 static UInt8 CFJSObjectEqual(void *data1, void *data2);
45 static CFArrayRef CFJSObjectCopyPropertyNames(void *data);
46
47 void *JSCFRetain(CFAllocatorRef allocator, const void *value);
48 void JSCFRelease(CFAllocatorRef allocator, const void *value);
49
50
51 void JSSetCFNull(CFTypeRef nullRef)
52 {
53     ReleaseCFType(sJSCFNullRef);
54     sJSCFNullRef = RetainCFType(nullRef);
55 }
56
57 CFTypeRef JSGetCFNull(void)
58 {
59     return sJSCFNullRef;
60 }
61
62 /*
63     JSRetain
64 */
65 JSTypeRef JSRetain(JSTypeRef ref)
66 {
67     if (ref)
68     {
69         JSBase* ptr = (JSBase*)ref;
70         ptr->Retain();
71     }
72     return ref;
73 }
74
75 /*
76     JSRelease
77 */
78 void JSRelease(JSTypeRef ref)
79 {
80     if (ref)
81     {
82         JSBase* ptr = (JSBase*)ref;
83         ptr->Release();
84     }
85 }
86
87 /*
88     JSCopyDescription
89 */
90 CFStringRef JSCopyDescription(JSTypeRef ref)
91 {
92     CFStringRef result = 0;
93     if (ref)
94     {
95         JSBase* ptr = (JSBase*)ref;
96         ptr->CopyDescription();
97     }
98     return result;
99 }
100
101 /*
102     JSEqual
103 */
104 UInt8 JSEqual(JSTypeRef ref1, JSTypeRef ref2)
105 {
106     UInt8 result = false;
107     if (ref1 && ref2)
108     {
109         JSBase* ptr = (JSBase*)ref1;
110         result = ptr->Equal((JSBase*)ref2);
111     }
112     return result;
113 }
114
115
116 /*
117     JSGetTypeID
118 */
119 JSTypeID JSGetTypeID(JSTypeRef ref)
120 {
121     JSTypeID result = kJSInvalidTypeID;
122     if (ref)
123     {
124         JSBase* ptr = (JSBase*)ref;
125         result = ptr->GetTypeID();
126     }
127     return result;
128 }
129
130
131 /*
132     JSGetRetainCount
133 */
134 CFIndex JSGetRetainCount(JSTypeRef ref)
135 {
136     CFIndex result = -1;
137     if (ref)
138     {
139         JSBase* ptr = (JSBase*)ref;
140         result = ptr->RetainCount();
141     }
142     return result;
143 }
144
145
146
147 /*
148     JSObjectCreate
149 */
150 JSObjectRef JSObjectCreate(void *data, JSObjectCallBacksPtr callBacks)
151 {
152     JSObjectRef result = JSObjectCreateInternal(data, callBacks, 0, kJSUserObjectDataTypeUnknown);
153     return result;
154 }
155
156 /*
157     JSObjectCreateInternal
158 */
159 JSObjectRef JSObjectCreateInternal(void *data, JSObjectCallBacksPtr callBacks, JSObjectMarkProcPtr markProc, int type)
160 {
161     JSObjectRef result = 0;
162     JSUserObject* ptr = new JSUserObject(callBacks, markProc, data, type);
163     result = (JSObjectRef)ptr;
164     return result;
165 }
166
167 /*
168     JSObjectCopyCFValue
169 */
170 CFTypeRef JSObjectCopyCFValue(JSObjectRef ref)
171 {
172     CFTypeRef result = 0;
173     JSUserObject* ptr = (JSUserObject*)ref;
174     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
175     {
176         result = ptr->CopyCFValue();
177     }
178     return result;
179 }
180
181 /*
182     JSObjectGetData
183 */
184 void *JSObjectGetData(JSObjectRef ref)
185 {
186     void *result = 0;
187     JSUserObject* ptr = (JSUserObject*)ref;
188     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
189     {
190         result = ptr->GetData();
191     }
192     return result;
193 }
194
195
196 /*
197     JSObjectCopyProperty
198 */
199 JSObjectRef JSObjectCopyProperty(JSObjectRef ref, CFStringRef propertyName)
200 {
201     JSObjectRef result = 0;
202     JSUserObject* ptr = (JSUserObject*)ref;
203     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
204     {
205         result = (JSObjectRef)ptr->CopyProperty(propertyName);
206     }
207     return result;
208 }
209
210
211 /*
212     JSObjectSetProperty
213 */
214 void JSObjectSetProperty(JSObjectRef ref, CFStringRef propertyName, JSObjectRef value)
215 {
216     JSUserObject* ptr = (JSUserObject*)ref;
217     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
218     {
219         ptr->SetProperty(propertyName, (JSUserObject*)value);
220     }
221 }
222
223
224 /*
225     JSObjectCallFunction
226 */
227 JSObjectRef JSObjectCallFunction(JSObjectRef ref, JSObjectRef thisObj, CFArrayRef args)
228 {
229     JSObjectRef result = 0;
230     JSUserObject* ptr = (JSUserObject*)ref;
231     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
232     {
233         result = (JSObjectRef)ptr->CallFunction((JSUserObject*)thisObj, args);
234     }
235     return result;
236 }
237
238
239 /*
240     JSRunCreate
241 */
242 JSRunRef JSRunCreate(CFStringRef jsSource, JSFlags inFlags)
243 {
244     initializeThreading();
245
246     JSRunRef result = 0;
247     if (jsSource)
248     {
249         JSLock lock(true);
250         result = (JSRunRef) new JSRun(jsSource, inFlags);
251     }
252     return result;
253 }
254
255 /*
256     JSRunCopySource
257 */
258 CFStringRef JSRunCopySource(JSRunRef ref)
259 {
260     CFStringRef result = 0;
261     JSRun* ptr = (JSRun*)ref;
262     if (ptr)
263     {
264         result = UStringToCFString(ptr->GetSource());
265     }
266     return result;
267 }
268
269
270 /*
271     JSRunCopyGlobalObject
272 */
273 JSObjectRef JSRunCopyGlobalObject(JSRunRef ref)
274 {
275     JSObjectRef result = 0;
276     JSRun* ptr = (JSRun*)ref;
277     if (ptr)
278     {
279         JSGlobalObject* globalObject = ptr->GlobalObject();
280         result = (JSObjectRef)KJSValueToJSObject(globalObject, globalObject->globalExec());
281     }
282     return result;
283 }
284
285 /*
286     JSRunEvaluate
287 */
288 JSObjectRef JSRunEvaluate(JSRunRef ref)
289 {
290     JSObjectRef result = 0;
291     JSRun* ptr = (JSRun*)ref;
292     if (ptr)
293     {
294         JSLock lock(true);
295         Completion completion = ptr->Evaluate();
296         if (completion.isValueCompletion())
297         {
298             result = (JSObjectRef)KJSValueToJSObject(completion.value(), ptr->GlobalObject()->globalExec());
299         }
300
301         if (completion.complType() == Throw)
302         {
303             JSFlags flags = ptr->Flags();
304             if (flags & kJSFlagDebug)
305             {
306                 CFTypeRef error = JSObjectCopyCFValue(result);
307                 if (error)
308                 {
309                     CFShow(error);
310                     CFRelease(error);
311                 }
312             }
313         }
314     }
315     return result;
316 }
317
318 /*
319     JSRunCheckSyntax
320     Return true if no syntax error
321 */
322 bool JSRunCheckSyntax(JSRunRef ref)
323 {
324     bool result = false;
325     JSRun* ptr = (JSRun*)ref;
326     if (ptr)
327     {
328             JSLock lock(true);
329             result = ptr->CheckSyntax();
330     }
331     return result;
332 }
333
334 /*
335     JSCollect - trigger garbage collection
336 */
337 void JSCollect()
338 {
339     initializeThreading();
340
341     JSLock lock(true);
342     getThreadGlobalExecState()->heap()->collect();
343 }
344
345 /*
346     JSTypeGetCFArrayCallBacks
347 */
348 void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks)
349 {
350     if (outCallBacks)
351     {
352         outCallBacks->version = 1;
353         outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain;
354         outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease;
355         outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription;
356         outCallBacks->equal = (CFArrayEqualCallBack)JSEqual;
357     }
358 }
359
360
361 /*
362     JSCFRetain
363 */
364 void *JSCFRetain(CFAllocatorRef allocator, const void *value)
365 {
366     JSRetain((JSTypeRef)value);
367     return (void*)value;
368 }
369
370 /*
371     JSCFRelease
372 */
373 void JSCFRelease(CFAllocatorRef allocator, const void *value)
374 {
375     JSRelease((JSTypeRef)value);
376 }
377
378
379 /*
380     JSObjectCreateWithCFType
381 */
382 JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef)
383 {
384     JSObjectCallBacks callBacks;
385     JSObjectRef cfJSObject = nil;
386     if (inRef)
387     {
388         callBacks.dispose = CFJSObjectDispose;
389         callBacks.equal = CFJSObjectEqual;
390         callBacks.copyCFValue = CFJSObjectCopyCFValue;
391         callBacks.copyProperty = CFJSObjectCopyProperty;
392         callBacks.setProperty = CFJSObjectSetProperty;
393         callBacks.callFunction = 0;
394         callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames;
395         cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, 0, kJSUserObjectDataTypeCFType );
396     }
397     return cfJSObject;
398 }
399
400 /*
401     CFJSObjectDispose
402 */
403 void CFJSObjectDispose(void *data)
404 {
405     if (data)
406     {
407         CFRelease((JSTypeRef)data);
408     }
409 }
410
411 CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref)
412 {
413     CFArrayRef result = 0;
414     JSUserObject* ptr = (JSUserObject*)ref;
415     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
416     {
417         result = ptr->CopyPropertyNames();
418     }
419     return result;
420 }
421 /*
422     CFJSObjectCopyProperty
423 */
424 JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName)
425 {
426     JSObjectRef result = 0;
427     if (data && propertyName)
428     {
429         CFTypeRef cfResult = 0;
430         if (CFGetTypeID(data) == CFDictionaryGetTypeID())
431         {
432             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
433             {
434                 int len = CFDictionaryGetCount((CFDictionaryRef)data);
435                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
436             }
437             else
438             {
439                 cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName));
440             }
441         }
442         else if (CFGetTypeID(data) == CFArrayGetTypeID())
443         {
444             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
445             {
446                 int len = CFArrayGetCount((CFArrayRef)data);
447                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
448             }
449             else
450             {
451                 SInt32 index = CFStringGetIntValue(propertyName);
452                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
453                 if (index >= 0 && index < arrayCount)
454                 {
455                     cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index));
456                 }
457             }
458         }
459         else if (CFGetTypeID(data) == CFStringGetTypeID())
460         {
461             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
462             {
463                 int len = CFStringGetLength((CFStringRef)data);
464                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
465             }
466         }
467         if (cfResult)
468         {
469             result = JSObjectCreateWithCFType(cfResult);
470             CFRelease(cfResult);
471         }
472     }
473     return result;
474 }
475
476
477 /*
478     CFJSObjectSetProperty
479 */
480 void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue)
481 {
482     if (data && propertyName)
483     {
484         CFTypeRef cfValue = JSObjectCopyCFValue(jsValue);
485
486         if (cfValue)
487         {
488             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
489             {
490                 CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue);
491             }
492             else if (CFGetTypeID(data) == CFArrayGetTypeID())
493             {
494                 SInt32 index = CFStringGetIntValue(propertyName);
495                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
496                 if (index >= 0)
497                 {
498                     for (; arrayCount < index; arrayCount++)
499                     {
500                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
501                     }
502                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue);
503                 }
504             }
505             CFRelease(cfValue);
506         }
507         else
508         {
509             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
510             {
511                 CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName);
512             }
513             else if (CFGetTypeID(data) == CFArrayGetTypeID())
514             {
515                 SInt32 index = CFStringGetIntValue(propertyName);
516                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
517                 if (index >= 0)
518                 {
519                     for (; arrayCount < index; arrayCount++)
520                     {
521                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
522                     }
523                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull());
524                 }
525             }
526         }
527     }
528 }
529
530
531 /*
532     CFJSObjectCopyCFValue
533 */
534 CFTypeRef CFJSObjectCopyCFValue(void *data)
535 {
536     CFTypeRef result = 0;
537     if (data)
538     {
539         result = (CFTypeRef)CFRetain(data);
540     }
541     return result;
542 }
543
544 /*
545     CFJSObjectCopyCFValue
546 */
547 UInt8 CFJSObjectEqual(void *data1, void *data2)
548 {
549     UInt8 result = false;
550     if (data1 && data2)
551     {
552         CFEqual((CFTypeRef)data1, (CFTypeRef)data2);
553     }
554     return result;
555 }
556
557
558 /*
559     CFJSObjectCopyPropertyNames
560 */
561 CFArrayRef CFJSObjectCopyPropertyNames(void *data)
562 {
563     CFMutableArrayRef result = 0;
564     if (data)
565     {
566         CFTypeID cfType = CFGetTypeID(data);
567         if (cfType == CFDictionaryGetTypeID())
568         {
569             CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data);
570             if (count)
571             {
572                 CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count);
573                 if (keys)
574                 {
575                     int i;
576                     CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, 0);
577                     for (i = 0; i < count; i++)
578                     {
579                         CFStringRef key = (CFStringRef)keys[i];
580                         if (CFGetTypeID(key) != CFStringGetTypeID()) continue;
581
582                         if (!result) result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
583                         if (!result) continue;
584
585                         CFArrayAppendValue(result, key);
586                     }
587                     free(keys);
588                 }
589             }
590         }
591     }
592     return result;
593 }
594
595
596
597
598 CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array)
599 {
600     CFIndex count = array ? CFArrayGetCount(array) : 0;
601     CFMutableArrayRef cfArray = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
602     CFIndex i;
603
604     for (i = 0; cfArray && i <  count; i++)
605     {
606         JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i);
607         CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue);
608         if (cfvalue)
609         {
610             CFArrayAppendValue(cfArray, cfvalue);
611             CFRelease(cfvalue);
612         }
613         else
614         {
615             CFArrayAppendValue(cfArray, GetCFNull());
616         }
617     }
618     return cfArray;
619 }
620
621 CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array)
622 {
623     initializeThreading();
624
625     CFIndex count = array ? CFArrayGetCount(array) : 0;
626     CFArrayCallBacks arrayCallbacks;
627     CFMutableArrayRef jsArray;
628     CFIndex i;
629
630     JSTypeGetCFArrayCallBacks(&arrayCallbacks);
631     jsArray = CFArrayCreateMutable(0, 0, &arrayCallbacks);
632
633     for (i = 0; array && i <  count; i++)
634     {
635         CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i);
636         JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue);
637
638         if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull());
639         if (jsValue)
640         {
641             CFArrayAppendValue(jsArray, jsValue);
642             JSRelease(jsValue);
643         }
644     }
645     return jsArray;
646 }
647
648
649 void JSLockInterpreter()
650 {
651     initializeThreading();
652     JSLock::lock(true);
653 }
654
655
656 void JSUnlockInterpreter()
657 {
658     JSLock::unlock(true);
659 }