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 JSGlueAPIEntry entry;
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 JSGlueAPIEntry entry;
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 JSGlueAPIEntry entry;
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 JSGlueAPIEntry entry;
342 Heap* heap = getThreadGlobalExecState()->heap();
343 if (!heap->isBusy())
344 heap->collectAllGarbage();
345 }
346
347 /*
348 JSTypeGetCFArrayCallBacks
349 */
JSTypeGetCFArrayCallBacks(CFArrayCallBacks * outCallBacks)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 */
JSCFRetain(CFAllocatorRef allocator,const void * value)366 void *JSCFRetain(CFAllocatorRef allocator, const void *value)
367 {
368 JSRetain((JSTypeRef)value);
369 return (void*)value;
370 }
371
372 /*
373 JSCFRelease
374 */
JSCFRelease(CFAllocatorRef allocator,const void * value)375 void JSCFRelease(CFAllocatorRef allocator, const void *value)
376 {
377 JSRelease((JSTypeRef)value);
378 }
379
380
381 /*
382 JSObjectCreateWithCFType
383 */
JSObjectCreateWithCFType(CFTypeRef inRef)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 */
CFJSObjectDispose(void * data)405 void CFJSObjectDispose(void *data)
406 {
407 if (data)
408 {
409 CFRelease((JSTypeRef)data);
410 }
411 }
412
JSObjectCopyPropertyNames(JSObjectRef ref)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 */
CFJSObjectCopyProperty(void * data,CFStringRef propertyName)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 */
CFJSObjectSetProperty(void * data,CFStringRef propertyName,JSObjectRef jsValue)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 */
CFJSObjectCopyCFValue(void * data)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 */
CFJSObjectEqual(void * data1,void * data2)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 */
CFJSObjectCopyPropertyNames(void * data)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
JSCreateCFArrayFromJSArray(CFArrayRef array)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
JSCreateJSArrayFromCFArray(CFArrayRef array)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
JSLockInterpreter()651 void JSLockInterpreter()
652 {
653 initializeThreading();
654 JSLock::lock(LockForReal);
655 }
656
657
JSUnlockInterpreter()658 void JSUnlockInterpreter()
659 {
660 JSLock::unlock(LockForReal);
661 }
662