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 38static CFTypeRef sJSCFNullRef = 0; 39 40static void CFJSObjectDispose(void *data); 41static JSObjectRef CFJSObjectCopyProperty(void *data, CFStringRef propertyName); 42static void CFJSObjectSetProperty(void *data, CFStringRef propertyName, JSObjectRef jsValue); 43static CFTypeRef CFJSObjectCopyCFValue(void *data); 44static UInt8 CFJSObjectEqual(void *data1, void *data2); 45static CFArrayRef CFJSObjectCopyPropertyNames(void *data); 46 47void *JSCFRetain(CFAllocatorRef allocator, const void *value); 48void JSCFRelease(CFAllocatorRef allocator, const void *value); 49 50 51void JSSetCFNull(CFTypeRef nullRef) 52{ 53 ReleaseCFType(sJSCFNullRef); 54 sJSCFNullRef = RetainCFType(nullRef); 55} 56 57CFTypeRef JSGetCFNull(void) 58{ 59 return sJSCFNullRef; 60} 61 62/* 63 JSRetain 64*/ 65JSTypeRef 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*/ 78void JSRelease(JSTypeRef ref) 79{ 80 if (ref) 81 { 82 JSBase* ptr = (JSBase*)ref; 83 ptr->Release(); 84 } 85} 86 87/* 88 JSCopyDescription 89*/ 90CFStringRef 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*/ 104UInt8 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*/ 119JSTypeID 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*/ 134CFIndex 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*/ 150JSObjectRef JSObjectCreate(void *data, JSObjectCallBacksPtr callBacks) 151{ 152 JSObjectRef result = JSObjectCreateInternal(data, callBacks, 0, kJSUserObjectDataTypeUnknown); 153 return result; 154} 155 156/* 157 JSObjectCreateInternal 158*/ 159JSObjectRef 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*/ 170CFTypeRef 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*/ 184void *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*/ 199JSObjectRef 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*/ 214void 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*/ 227JSObjectRef 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*/ 242JSRunRef 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*/ 258CFStringRef 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*/ 273JSObjectRef 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*/ 288JSObjectRef 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*/ 322bool 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*/ 337void 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*/ 350void 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*/ 366void *JSCFRetain(CFAllocatorRef allocator, const void *value) 367{ 368 JSRetain((JSTypeRef)value); 369 return (void*)value; 370} 371 372/* 373 JSCFRelease 374*/ 375void JSCFRelease(CFAllocatorRef allocator, const void *value) 376{ 377 JSRelease((JSTypeRef)value); 378} 379 380 381/* 382 JSObjectCreateWithCFType 383*/ 384JSObjectRef 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*/ 405void CFJSObjectDispose(void *data) 406{ 407 if (data) 408 { 409 CFRelease((JSTypeRef)data); 410 } 411} 412 413CFArrayRef 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*/ 426JSObjectRef 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*/ 482void 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*/ 536CFTypeRef 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*/ 549UInt8 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*/ 563CFArrayRef 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 600CFMutableArrayRef 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 623CFMutableArrayRef 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 651void JSLockInterpreter() 652{ 653 initializeThreading(); 654 JSLock::lock(LockForReal); 655} 656 657 658void JSUnlockInterpreter() 659{ 660 JSLock::unlock(LockForReal); 661} 662