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 JSGlueAPIEntry entry; 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 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 */ 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 */ 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 */ 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 } 662