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
JSSetCFNull(CFTypeRef nullRef)51 void JSSetCFNull(CFTypeRef nullRef)
52 {
53 ReleaseCFType(sJSCFNullRef);
54 sJSCFNullRef = RetainCFType(nullRef);
55 }
56
JSGetCFNull(void)57 CFTypeRef JSGetCFNull(void)
58 {
59 return sJSCFNullRef;
60 }
61
62 /*
63 JSRetain
64 */
JSRetain(JSTypeRef ref)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 */
JSRelease(JSTypeRef ref)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 */
JSCopyDescription(JSTypeRef ref)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 */
JSEqual(JSTypeRef ref1,JSTypeRef ref2)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 */
JSGetTypeID(JSTypeRef ref)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 */
JSGetRetainCount(JSTypeRef ref)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 */
JSObjectCreate(void * data,JSObjectCallBacksPtr callBacks)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 */
JSObjectCreateInternal(void * data,JSObjectCallBacksPtr callBacks,JSObjectMarkProcPtr markProc,int type)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 */
JSObjectCopyCFValue(JSObjectRef ref)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 */
JSObjectGetData(JSObjectRef ref)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 */
JSObjectCopyProperty(JSObjectRef ref,CFStringRef propertyName)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 */
JSObjectSetProperty(JSObjectRef ref,CFStringRef propertyName,JSObjectRef value)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 */
JSObjectCallFunction(JSObjectRef ref,JSObjectRef thisObj,CFArrayRef args)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 */
JSRunCreate(CFStringRef jsSource,JSFlags inFlags)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 */
JSRunCopySource(JSRunRef ref)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 */
JSRunCopyGlobalObject(JSRunRef ref)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 */
JSRunEvaluate(JSRunRef ref)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 */
JSRunCheckSyntax(JSRunRef ref)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 */
JSCollect()337 void JSCollect()
338 {
339 initializeThreading();
340
341 JSLock lock(true);
342 getThreadGlobalExecState()->heap()->collect();
343 }
344
345 /*
346 JSTypeGetCFArrayCallBacks
347 */
JSTypeGetCFArrayCallBacks(CFArrayCallBacks * outCallBacks)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 */
JSCFRetain(CFAllocatorRef allocator,const void * value)364 void *JSCFRetain(CFAllocatorRef allocator, const void *value)
365 {
366 JSRetain((JSTypeRef)value);
367 return (void*)value;
368 }
369
370 /*
371 JSCFRelease
372 */
JSCFRelease(CFAllocatorRef allocator,const void * value)373 void JSCFRelease(CFAllocatorRef allocator, const void *value)
374 {
375 JSRelease((JSTypeRef)value);
376 }
377
378
379 /*
380 JSObjectCreateWithCFType
381 */
JSObjectCreateWithCFType(CFTypeRef inRef)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 */
CFJSObjectDispose(void * data)403 void CFJSObjectDispose(void *data)
404 {
405 if (data)
406 {
407 CFRelease((JSTypeRef)data);
408 }
409 }
410
JSObjectCopyPropertyNames(JSObjectRef ref)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 */
CFJSObjectCopyProperty(void * data,CFStringRef propertyName)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 */
CFJSObjectSetProperty(void * data,CFStringRef propertyName,JSObjectRef jsValue)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 */
CFJSObjectCopyCFValue(void * data)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 */
CFJSObjectEqual(void * data1,void * data2)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 */
CFJSObjectCopyPropertyNames(void * data)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
JSCreateCFArrayFromJSArray(CFArrayRef array)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
JSCreateJSArrayFromCFArray(CFArrayRef array)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
JSLockInterpreter()649 void JSLockInterpreter()
650 {
651 initializeThreading();
652 JSLock::lock(true);
653 }
654
655
JSUnlockInterpreter()656 void JSUnlockInterpreter()
657 {
658 JSLock::unlock(true);
659 }
660