Versioning.
[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(LockForReal);
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(LockForReal);
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(LockForReal);
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(LockForReal);
342     Heap* heap = getThreadGlobalExecState()->heap();
343     if (!heap->isBusy())
344         heap->collectAllGarbage();
345 }
346
347 /*
348     JSTypeGetCFArrayCallBacks
349 */
350 void JSTypeGetCFArrayCallBacks(CFArrayCallBacks* outCallBacks)
351 {
352     if (outCallBacks)
353     {
354         outCallBacks->version = 1;
355         outCallBacks->retain = (CFArrayRetainCallBack)JSCFRetain;
356         outCallBacks->release = (CFArrayReleaseCallBack)JSCFRelease;
357         outCallBacks->copyDescription = (CFArrayCopyDescriptionCallBack)JSCopyDescription;
358         outCallBacks->equal = (CFArrayEqualCallBack)JSEqual;
359     }
360 }
361
362
363 /*
364     JSCFRetain
365 */
366 void *JSCFRetain(CFAllocatorRef allocator, const void *value)
367 {
368     JSRetain((JSTypeRef)value);
369     return (void*)value;
370 }
371
372 /*
373     JSCFRelease
374 */
375 void JSCFRelease(CFAllocatorRef allocator, const void *value)
376 {
377     JSRelease((JSTypeRef)value);
378 }
379
380
381 /*
382     JSObjectCreateWithCFType
383 */
384 JSObjectRef JSObjectCreateWithCFType(CFTypeRef inRef)
385 {
386     JSObjectCallBacks callBacks;
387     JSObjectRef cfJSObject = nil;
388     if (inRef)
389     {
390         callBacks.dispose = CFJSObjectDispose;
391         callBacks.equal = CFJSObjectEqual;
392         callBacks.copyCFValue = CFJSObjectCopyCFValue;
393         callBacks.copyProperty = CFJSObjectCopyProperty;
394         callBacks.setProperty = CFJSObjectSetProperty;
395         callBacks.callFunction = 0;
396         callBacks.copyPropertyNames = CFJSObjectCopyPropertyNames;
397         cfJSObject = JSObjectCreateInternal((void*)CFRetain(inRef), &callBacks, 0, kJSUserObjectDataTypeCFType );
398     }
399     return cfJSObject;
400 }
401
402 /*
403     CFJSObjectDispose
404 */
405 void CFJSObjectDispose(void *data)
406 {
407     if (data)
408     {
409         CFRelease((JSTypeRef)data);
410     }
411 }
412
413 CFArrayRef JSObjectCopyPropertyNames(JSObjectRef ref)
414 {
415     CFArrayRef result = 0;
416     JSUserObject* ptr = (JSUserObject*)ref;
417     if (ptr && (ptr->GetTypeID() == kJSObjectTypeID))
418     {
419         result = ptr->CopyPropertyNames();
420     }
421     return result;
422 }
423 /*
424     CFJSObjectCopyProperty
425 */
426 JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName)
427 {
428     JSObjectRef result = 0;
429     if (data && propertyName)
430     {
431         CFTypeRef cfResult = 0;
432         if (CFGetTypeID(data) == CFDictionaryGetTypeID())
433         {
434             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
435             {
436                 int len = CFDictionaryGetCount((CFDictionaryRef)data);
437                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
438             }
439             else
440             {
441                 cfResult = RetainCFType(CFDictionaryGetValue((CFDictionaryRef)data, propertyName));
442             }
443         }
444         else if (CFGetTypeID(data) == CFArrayGetTypeID())
445         {
446             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
447             {
448                 int len = CFArrayGetCount((CFArrayRef)data);
449                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
450             }
451             else
452             {
453                 SInt32 index = CFStringGetIntValue(propertyName);
454                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
455                 if (index >= 0 && index < arrayCount)
456                 {
457                     cfResult = RetainCFType(CFArrayGetValueAtIndex((CFArrayRef)data, index));
458                 }
459             }
460         }
461         else if (CFGetTypeID(data) == CFStringGetTypeID())
462         {
463             if (CFStringCompare(propertyName, CFSTR("length"), 0) == kCFCompareEqualTo)
464             {
465                 int len = CFStringGetLength((CFStringRef)data);
466                 cfResult = CFNumberCreate(0, kCFNumberIntType, &len);
467             }
468         }
469         if (cfResult)
470         {
471             result = JSObjectCreateWithCFType(cfResult);
472             CFRelease(cfResult);
473         }
474     }
475     return result;
476 }
477
478
479 /*
480     CFJSObjectSetProperty
481 */
482 void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue)
483 {
484     if (data && propertyName)
485     {
486         CFTypeRef cfValue = JSObjectCopyCFValue(jsValue);
487
488         if (cfValue)
489         {
490             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
491             {
492                 CFDictionarySetValue((CFMutableDictionaryRef)data, propertyName, cfValue);
493             }
494             else if (CFGetTypeID(data) == CFArrayGetTypeID())
495             {
496                 SInt32 index = CFStringGetIntValue(propertyName);
497                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
498                 if (index >= 0)
499                 {
500                     for (; arrayCount < index; arrayCount++)
501                     {
502                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
503                     }
504                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, cfValue);
505                 }
506             }
507             CFRelease(cfValue);
508         }
509         else
510         {
511             if (CFGetTypeID(data) == CFDictionaryGetTypeID())
512             {
513                 CFDictionaryRemoveValue((CFMutableDictionaryRef)data, propertyName);
514             }
515             else if (CFGetTypeID(data) == CFArrayGetTypeID())
516             {
517                 SInt32 index = CFStringGetIntValue(propertyName);
518                 CFIndex arrayCount = CFArrayGetCount((CFArrayRef)data);
519                 if (index >= 0)
520                 {
521                     for (; arrayCount < index; arrayCount++)
522                     {
523                         CFArrayAppendValue((CFMutableArrayRef)data, GetCFNull());
524                     }
525                     CFArraySetValueAtIndex((CFMutableArrayRef)data, index, GetCFNull());
526                 }
527             }
528         }
529     }
530 }
531
532
533 /*
534     CFJSObjectCopyCFValue
535 */
536 CFTypeRef CFJSObjectCopyCFValue(void *data)
537 {
538     CFTypeRef result = 0;
539     if (data)
540     {
541         result = (CFTypeRef)CFRetain(data);
542     }
543     return result;
544 }
545
546 /*
547     CFJSObjectCopyCFValue
548 */
549 UInt8 CFJSObjectEqual(void *data1, void *data2)
550 {
551     UInt8 result = false;
552     if (data1 && data2)
553     {
554         CFEqual((CFTypeRef)data1, (CFTypeRef)data2);
555     }
556     return result;
557 }
558
559
560 /*
561     CFJSObjectCopyPropertyNames
562 */
563 CFArrayRef CFJSObjectCopyPropertyNames(void *data)
564 {
565     CFMutableArrayRef result = 0;
566     if (data)
567     {
568         CFTypeID cfType = CFGetTypeID(data);
569         if (cfType == CFDictionaryGetTypeID())
570         {
571             CFIndex count = CFDictionaryGetCount((CFDictionaryRef)data);
572             if (count)
573             {
574                 CFTypeRef* keys = (CFTypeRef*)malloc(sizeof(CFTypeRef)*count);
575                 if (keys)
576                 {
577                     int i;
578                     CFDictionaryGetKeysAndValues((CFDictionaryRef)data, (const void **)keys, 0);
579                     for (i = 0; i < count; i++)
580                     {
581                         CFStringRef key = (CFStringRef)keys[i];
582                         if (CFGetTypeID(key) != CFStringGetTypeID()) continue;
583
584                         if (!result) result = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
585                         if (!result) continue;
586
587                         CFArrayAppendValue(result, key);
588                     }
589                     free(keys);
590                 }
591             }
592         }
593     }
594     return result;
595 }
596
597
598
599
600 CFMutableArrayRef JSCreateCFArrayFromJSArray(CFArrayRef array)
601 {
602     CFIndex count = array ? CFArrayGetCount(array) : 0;
603     CFMutableArrayRef cfArray = CFArrayCreateMutable(0, 0, &kCFTypeArrayCallBacks);
604     CFIndex i;
605
606     for (i = 0; cfArray && i <  count; i++)
607     {
608         JSObjectRef jsValue = (JSObjectRef)CFArrayGetValueAtIndex(array, i);
609         CFTypeRef cfvalue = JSObjectCopyCFValue(jsValue);
610         if (cfvalue)
611         {
612             CFArrayAppendValue(cfArray, cfvalue);
613             CFRelease(cfvalue);
614         }
615         else
616         {
617             CFArrayAppendValue(cfArray, GetCFNull());
618         }
619     }
620     return cfArray;
621 }
622
623 CFMutableArrayRef JSCreateJSArrayFromCFArray(CFArrayRef array)
624 {
625     initializeThreading();
626
627     CFIndex count = array ? CFArrayGetCount(array) : 0;
628     CFArrayCallBacks arrayCallbacks;
629     CFMutableArrayRef jsArray;
630     CFIndex i;
631
632     JSTypeGetCFArrayCallBacks(&arrayCallbacks);
633     jsArray = CFArrayCreateMutable(0, 0, &arrayCallbacks);
634
635     for (i = 0; array && i <  count; i++)
636     {
637         CFTypeRef cfValue = (CFTypeRef)CFArrayGetValueAtIndex(array, i);
638         JSObjectRef jsValue = JSObjectCreateWithCFType(cfValue);
639
640         if (!jsValue) jsValue = JSObjectCreateWithCFType(GetCFNull());
641         if (jsValue)
642         {
643             CFArrayAppendValue(jsArray, jsValue);
644             JSRelease(jsValue);
645         }
646     }
647     return jsArray;
648 }
649
650
651 void JSLockInterpreter()
652 {
653     initializeThreading();
654     JSLock::lock(LockForReal);
655 }
656
657
658 void JSUnlockInterpreter()
659 {
660     JSLock::unlock(LockForReal);
661 }