testapi.c
1 /* 2 * Copyright (C) 2006-2020 Apple 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 * 1. Redistributions of source code must retain the above copyright 8 * notice, this list of conditions and the following disclaimer. 9 * 2. Redistributions in binary form must reproduce the above copyright 10 * notice, this list of conditions and the following disclaimer in the 11 * documentation and/or other materials provided with the distribution. 12 * 13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY 14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #define ASSERT_ENABLED 1 27 #include "config.h" 28 29 #if USE(CF) 30 #include "JavaScriptCore.h" 31 #else 32 #include "JavaScript.h" 33 #endif 34 35 #include "JSBasePrivate.h" 36 #include "JSHeapFinalizerPrivate.h" 37 #include "JSMarkingConstraintPrivate.h" 38 #include "JSObjectRefPrivate.h" 39 #include "JSScriptRefPrivate.h" 40 #include "JSStringRefPrivate.h" 41 #include "JSWeakPrivate.h" 42 #if !OS(WINDOWS) 43 #include <libgen.h> 44 #endif 45 #include <limits.h> 46 #include <math.h> 47 #include <stdio.h> 48 #include <stdlib.h> 49 #include <string.h> 50 #include <time.h> 51 #if !OS(WINDOWS) 52 #include <unistd.h> 53 #endif 54 #include <wtf/Assertions.h> 55 56 #if OS(WINDOWS) 57 #include <windows.h> 58 #endif 59 60 #include "CompareAndSwapTest.h" 61 #include "CustomGlobalObjectClassTest.h" 62 #include "ExecutionTimeLimitTest.h" 63 #include "FunctionOverridesTest.h" 64 #include "GlobalContextWithFinalizerTest.h" 65 #include "JSONParseTest.h" 66 #include "JSObjectGetProxyTargetTest.h" 67 #include "MultithreadedMultiVMExecutionTest.h" 68 #include "PingPongStackOverflowTest.h" 69 #include "TypedArrayCTest.h" 70 71 #if COMPILER(MSVC) 72 #pragma warning(disable:4204) 73 #endif 74 75 #if JSC_OBJC_API_ENABLED 76 void testObjectiveCAPI(const char*); 77 #endif 78 79 void configureJSCForTesting(void); 80 int testCAPIViaCpp(const char* filter); 81 82 bool assertTrue(bool value, const char* message); 83 84 static JSGlobalContextRef context; 85 int failed; 86 static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue) 87 { 88 if (JSValueToBoolean(context, value) != expectedValue) { 89 fprintf(stderr, "assertEqualsAsBoolean failed: %p, %d\n", value, expectedValue); 90 failed = 1; 91 } 92 } 93 94 static void assertEqualsAsNumber(JSValueRef value, double expectedValue) 95 { 96 double number = JSValueToNumber(context, value, NULL); 97 98 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function, 99 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team. 100 // After that's resolved, we can remove these casts 101 if (number != expectedValue && !(isnan((float)number) && isnan((float)expectedValue))) { 102 fprintf(stderr, "assertEqualsAsNumber failed: %p, %lf\n", value, expectedValue); 103 failed = 1; 104 } 105 } 106 107 static void assertEqualsAsUTF8String(JSValueRef value, const char* expectedValue) 108 { 109 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); 110 111 size_t jsSize = JSStringGetMaximumUTF8CStringSize(valueAsString); 112 char* jsBuffer = (char*)malloc(jsSize); 113 JSStringGetUTF8CString(valueAsString, jsBuffer, jsSize); 114 115 unsigned i; 116 for (i = 0; jsBuffer[i]; i++) { 117 if (jsBuffer[i] != expectedValue[i]) { 118 fprintf(stderr, "assertEqualsAsUTF8String failed at character %d: %c(%d) != %c(%d)\n", i, jsBuffer[i], jsBuffer[i], expectedValue[i], expectedValue[i]); 119 fprintf(stderr, "value: %s\n", jsBuffer); 120 fprintf(stderr, "expectedValue: %s\n", expectedValue); 121 failed = 1; 122 } 123 } 124 125 if (jsSize < strlen(jsBuffer) + 1) { 126 fprintf(stderr, "assertEqualsAsUTF8String failed: jsSize was too small\n"); 127 failed = 1; 128 } 129 130 free(jsBuffer); 131 JSStringRelease(valueAsString); 132 } 133 134 static void assertEqualsAsCharactersPtr(JSValueRef value, const char* expectedValue) 135 { 136 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); 137 138 #if USE(CF) 139 size_t jsLength = JSStringGetLength(valueAsString); 140 const JSChar* jsBuffer = JSStringGetCharactersPtr(valueAsString); 141 142 CFStringRef expectedValueAsCFString = CFStringCreateWithCString(kCFAllocatorDefault, 143 expectedValue, 144 kCFStringEncodingUTF8); 145 CFIndex cfLength = CFStringGetLength(expectedValueAsCFString); 146 UniChar* cfBuffer = (UniChar*)malloc(cfLength * sizeof(UniChar)); 147 CFStringGetCharacters(expectedValueAsCFString, CFRangeMake(0, cfLength), cfBuffer); 148 CFRelease(expectedValueAsCFString); 149 150 if (memcmp(jsBuffer, cfBuffer, cfLength * sizeof(UniChar)) != 0) { 151 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n"); 152 failed = 1; 153 } 154 155 if (jsLength != (size_t)cfLength) { 156 #if OS(WINDOWS) 157 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%Iu) != cfLength(%Iu)\n", jsLength, (size_t)cfLength); 158 #else 159 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsLength(%zu) != cfLength(%zu)\n", jsLength, (size_t)cfLength); 160 #endif 161 failed = 1; 162 } 163 164 free(cfBuffer); 165 #else 166 size_t bufferSize = JSStringGetMaximumUTF8CStringSize(valueAsString); 167 char* buffer = (char*)malloc(bufferSize); 168 JSStringGetUTF8CString(valueAsString, buffer, bufferSize); 169 170 if (strcmp(buffer, expectedValue)) { 171 fprintf(stderr, "assertEqualsAsCharactersPtr failed: jsBuffer != cfBuffer\n"); 172 failed = 1; 173 } 174 175 free(buffer); 176 #endif 177 JSStringRelease(valueAsString); 178 } 179 180 static bool timeZoneIsPST() 181 { 182 char timeZoneName[70]; 183 struct tm gtm; 184 memset(>m, 0, sizeof(gtm)); 185 strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); 186 187 return 0 == strcmp("PST", timeZoneName); 188 } 189 190 static JSValueRef jsGlobalValue; // non-stack value for testing JSValueProtect() 191 192 /* MyObject pseudo-class */ 193 194 static bool MyObject_hasProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName) 195 { 196 UNUSED_PARAM(context); 197 UNUSED_PARAM(object); 198 199 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne") 200 || JSStringIsEqualToUTF8CString(propertyName, "cantFind") 201 || JSStringIsEqualToUTF8CString(propertyName, "throwOnGet") 202 || JSStringIsEqualToUTF8CString(propertyName, "myPropertyName") 203 || JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie") 204 || JSStringIsEqualToUTF8CString(propertyName, "0")) { 205 return true; 206 } 207 208 return false; 209 } 210 211 static JSValueRef throwException(JSContextRef context, JSObjectRef object, JSValueRef* exception) 212 { 213 JSStringRef script = JSStringCreateWithUTF8CString("throw 'an exception'"); 214 JSStringRef sourceURL = JSStringCreateWithUTF8CString("test script"); 215 JSValueRef result = JSEvaluateScript(context, script, object, sourceURL, 1, exception); 216 JSStringRelease(script); 217 JSStringRelease(sourceURL); 218 return result; 219 } 220 221 static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 222 { 223 UNUSED_PARAM(context); 224 UNUSED_PARAM(object); 225 226 if (JSStringIsEqualToUTF8CString(propertyName, "alwaysOne")) { 227 return JSValueMakeNumber(context, 1); 228 } 229 230 if (JSStringIsEqualToUTF8CString(propertyName, "myPropertyName")) { 231 return JSValueMakeNumber(context, 1); 232 } 233 234 if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) { 235 return JSValueMakeUndefined(context); 236 } 237 238 if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) { 239 return 0; 240 } 241 242 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) { 243 return throwException(context, object, exception); 244 } 245 246 if (JSStringIsEqualToUTF8CString(propertyName, "0")) { 247 *exception = JSValueMakeNumber(context, 1); 248 return JSValueMakeNumber(context, 1); 249 } 250 251 return JSValueMakeNull(context); 252 } 253 254 static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 255 { 256 UNUSED_PARAM(context); 257 UNUSED_PARAM(object); 258 UNUSED_PARAM(value); 259 UNUSED_PARAM(exception); 260 261 if (JSStringIsEqualToUTF8CString(propertyName, "cantSet")) 262 return true; // pretend we set the property in order to swallow it 263 264 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnSet")) { 265 throwException(context, object, exception); 266 } 267 268 return false; 269 } 270 271 static bool MyObject_deleteProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 272 { 273 UNUSED_PARAM(context); 274 UNUSED_PARAM(object); 275 276 if (JSStringIsEqualToUTF8CString(propertyName, "cantDelete")) 277 return true; 278 279 if (JSStringIsEqualToUTF8CString(propertyName, "throwOnDelete")) { 280 throwException(context, object, exception); 281 return false; 282 } 283 284 return false; 285 } 286 287 static void MyObject_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) 288 { 289 UNUSED_PARAM(context); 290 UNUSED_PARAM(object); 291 292 JSStringRef propertyName; 293 294 propertyName = JSStringCreateWithUTF8CString("alwaysOne"); 295 JSPropertyNameAccumulatorAddName(propertyNames, propertyName); 296 JSStringRelease(propertyName); 297 298 propertyName = JSStringCreateWithUTF8CString("myPropertyName"); 299 JSPropertyNameAccumulatorAddName(propertyNames, propertyName); 300 JSStringRelease(propertyName); 301 } 302 303 static bool isValueEqualToString(JSContextRef context, JSValueRef value, const char* string) 304 { 305 if (!JSValueIsString(context, value)) 306 return false; 307 JSStringRef valueString = JSValueToStringCopy(context, value, NULL); 308 if (!valueString) 309 return false; 310 bool isEqual = JSStringIsEqualToUTF8CString(valueString, string); 311 JSStringRelease(valueString); 312 return isEqual; 313 } 314 315 static JSValueRef MyObject_callAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 316 { 317 UNUSED_PARAM(context); 318 UNUSED_PARAM(object); 319 UNUSED_PARAM(thisObject); 320 UNUSED_PARAM(exception); 321 322 if (argumentCount > 0 && isValueEqualToString(context, arguments[0], "throwOnCall")) { 323 throwException(context, object, exception); 324 return JSValueMakeUndefined(context); 325 } 326 327 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0))) 328 return JSValueMakeNumber(context, 1); 329 330 return JSValueMakeUndefined(context); 331 } 332 333 static JSObjectRef MyObject_callAsConstructor(JSContextRef context, JSObjectRef object, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 334 { 335 UNUSED_PARAM(context); 336 UNUSED_PARAM(object); 337 338 if (argumentCount > 0 && isValueEqualToString(context, arguments[0], "throwOnConstruct")) { 339 throwException(context, object, exception); 340 return object; 341 } 342 343 if (argumentCount > 0 && JSValueIsStrictEqual(context, arguments[0], JSValueMakeNumber(context, 0))) 344 return JSValueToObject(context, JSValueMakeNumber(context, 1), exception); 345 346 return JSValueToObject(context, JSValueMakeNumber(context, 0), exception); 347 } 348 349 static bool MyObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) 350 { 351 UNUSED_PARAM(context); 352 UNUSED_PARAM(constructor); 353 354 if (isValueEqualToString(context, possibleValue, "throwOnHasInstance")) { 355 throwException(context, constructor, exception); 356 return false; 357 } 358 359 JSStringRef numberString = JSStringCreateWithUTF8CString("Number"); 360 JSObjectRef numberConstructor = JSValueToObject(context, JSObjectGetProperty(context, JSContextGetGlobalObject(context), numberString, exception), exception); 361 JSStringRelease(numberString); 362 363 return JSValueIsInstanceOfConstructor(context, possibleValue, numberConstructor, exception); 364 } 365 366 static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) 367 { 368 UNUSED_PARAM(object); 369 UNUSED_PARAM(exception); 370 371 switch (type) { 372 case kJSTypeNumber: 373 return JSValueMakeNumber(context, 1); 374 case kJSTypeString: 375 { 376 JSStringRef string = JSStringCreateWithUTF8CString("MyObjectAsString"); 377 JSValueRef result = JSValueMakeString(context, string); 378 JSStringRelease(string); 379 return result; 380 } 381 default: 382 break; 383 } 384 385 // string conversion -- forward to default object class 386 return JSValueMakeNull(context); 387 } 388 389 static JSValueRef MyObject_convertToTypeWrapper(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) 390 { 391 UNUSED_PARAM(context); 392 UNUSED_PARAM(object); 393 UNUSED_PARAM(type); 394 UNUSED_PARAM(exception); 395 // Forward to default object class 396 return 0; 397 } 398 399 static bool MyObject_set_nullGetForwardSet(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 400 { 401 UNUSED_PARAM(ctx); 402 UNUSED_PARAM(object); 403 UNUSED_PARAM(propertyName); 404 UNUSED_PARAM(value); 405 UNUSED_PARAM(exception); 406 return false; // Forward to parent class. 407 } 408 409 static JSStaticValue evilStaticValues[] = { 410 { "nullGetSet", 0, 0, kJSPropertyAttributeNone }, 411 { "nullGetForwardSet", 0, MyObject_set_nullGetForwardSet, kJSPropertyAttributeNone }, 412 { 0, 0, 0, 0 } 413 }; 414 415 static JSStaticFunction evilStaticFunctions[] = { 416 { "nullCall", 0, kJSPropertyAttributeNone }, 417 { 0, 0, 0 } 418 }; 419 420 JSClassDefinition MyObject_definition = { 421 0, 422 kJSClassAttributeNone, 423 424 "MyObject", 425 NULL, 426 427 evilStaticValues, 428 evilStaticFunctions, 429 430 NULL, 431 NULL, 432 MyObject_hasProperty, 433 MyObject_getProperty, 434 MyObject_setProperty, 435 MyObject_deleteProperty, 436 MyObject_getPropertyNames, 437 MyObject_callAsFunction, 438 MyObject_callAsConstructor, 439 MyObject_hasInstance, 440 MyObject_convertToType, 441 }; 442 443 JSClassDefinition MyObject_convertToTypeWrapperDefinition = { 444 0, 445 kJSClassAttributeNone, 446 447 "MyObject", 448 NULL, 449 450 NULL, 451 NULL, 452 453 NULL, 454 NULL, 455 NULL, 456 NULL, 457 NULL, 458 NULL, 459 NULL, 460 NULL, 461 NULL, 462 NULL, 463 MyObject_convertToTypeWrapper, 464 }; 465 466 JSClassDefinition MyObject_nullWrapperDefinition = { 467 0, 468 kJSClassAttributeNone, 469 470 "MyObject", 471 NULL, 472 473 NULL, 474 NULL, 475 476 NULL, 477 NULL, 478 NULL, 479 NULL, 480 NULL, 481 NULL, 482 NULL, 483 NULL, 484 NULL, 485 NULL, 486 NULL, 487 }; 488 489 static JSClassRef MyObject_class(JSContextRef context) 490 { 491 UNUSED_PARAM(context); 492 493 static JSClassRef jsClass; 494 if (!jsClass) { 495 JSClassRef baseClass = JSClassCreate(&MyObject_definition); 496 MyObject_convertToTypeWrapperDefinition.parentClass = baseClass; 497 JSClassRef wrapperClass = JSClassCreate(&MyObject_convertToTypeWrapperDefinition); 498 MyObject_nullWrapperDefinition.parentClass = wrapperClass; 499 jsClass = JSClassCreate(&MyObject_nullWrapperDefinition); 500 } 501 502 return jsClass; 503 } 504 505 static JSValueRef PropertyCatchalls_getProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 506 { 507 UNUSED_PARAM(context); 508 UNUSED_PARAM(object); 509 UNUSED_PARAM(propertyName); 510 UNUSED_PARAM(exception); 511 512 if (JSStringIsEqualToUTF8CString(propertyName, "x")) { 513 static size_t count; 514 if (count++ < 5) 515 return NULL; 516 517 // Swallow all .x gets after 5, returning null. 518 return JSValueMakeNull(context); 519 } 520 521 if (JSStringIsEqualToUTF8CString(propertyName, "y")) { 522 static size_t count; 523 if (count++ < 5) 524 return NULL; 525 526 // Swallow all .y gets after 5, returning null. 527 return JSValueMakeNull(context); 528 } 529 530 if (JSStringIsEqualToUTF8CString(propertyName, "z")) { 531 static size_t count; 532 if (count++ < 5) 533 return NULL; 534 535 // Swallow all .y gets after 5, returning null. 536 return JSValueMakeNull(context); 537 } 538 539 return NULL; 540 } 541 542 static bool PropertyCatchalls_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 543 { 544 UNUSED_PARAM(context); 545 UNUSED_PARAM(object); 546 UNUSED_PARAM(propertyName); 547 UNUSED_PARAM(value); 548 UNUSED_PARAM(exception); 549 550 if (JSStringIsEqualToUTF8CString(propertyName, "x")) { 551 static size_t count; 552 if (count++ < 5) 553 return false; 554 555 // Swallow all .x sets after 4. 556 return true; 557 } 558 559 if (JSStringIsEqualToUTF8CString(propertyName, "make_throw") || JSStringIsEqualToUTF8CString(propertyName, "0")) { 560 *exception = JSValueMakeNumber(context, 5); 561 return true; 562 } 563 564 return false; 565 } 566 567 static void PropertyCatchalls_getPropertyNames(JSContextRef context, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) 568 { 569 UNUSED_PARAM(context); 570 UNUSED_PARAM(object); 571 572 static size_t count; 573 static const char* numbers[] = { "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" }; 574 575 // Provide a property of a different name every time. 576 JSStringRef propertyName = JSStringCreateWithUTF8CString(numbers[count++ % 10]); 577 JSPropertyNameAccumulatorAddName(propertyNames, propertyName); 578 JSStringRelease(propertyName); 579 } 580 581 JSClassDefinition PropertyCatchalls_definition = { 582 0, 583 kJSClassAttributeNone, 584 585 "PropertyCatchalls", 586 NULL, 587 588 NULL, 589 NULL, 590 591 NULL, 592 NULL, 593 NULL, 594 PropertyCatchalls_getProperty, 595 PropertyCatchalls_setProperty, 596 NULL, 597 PropertyCatchalls_getPropertyNames, 598 NULL, 599 NULL, 600 NULL, 601 NULL, 602 }; 603 604 static JSClassRef PropertyCatchalls_class(JSContextRef context) 605 { 606 UNUSED_PARAM(context); 607 608 static JSClassRef jsClass; 609 if (!jsClass) 610 jsClass = JSClassCreate(&PropertyCatchalls_definition); 611 612 return jsClass; 613 } 614 615 static bool EvilExceptionObject_hasInstance(JSContextRef context, JSObjectRef constructor, JSValueRef possibleValue, JSValueRef* exception) 616 { 617 UNUSED_PARAM(context); 618 UNUSED_PARAM(constructor); 619 620 JSStringRef hasInstanceName = JSStringCreateWithUTF8CString("hasInstance"); 621 JSValueRef hasInstance = JSObjectGetProperty(context, constructor, hasInstanceName, exception); 622 JSStringRelease(hasInstanceName); 623 if (!hasInstance) 624 return false; 625 JSObjectRef function = JSValueToObject(context, hasInstance, exception); 626 JSValueRef result = JSObjectCallAsFunction(context, function, constructor, 1, &possibleValue, exception); 627 return result && JSValueToBoolean(context, result); 628 } 629 630 static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObjectRef object, JSType type, JSValueRef* exception) 631 { 632 UNUSED_PARAM(object); 633 UNUSED_PARAM(exception); 634 JSStringRef funcName; 635 switch (type) { 636 case kJSTypeNumber: 637 funcName = JSStringCreateWithUTF8CString("toNumber"); 638 break; 639 case kJSTypeString: 640 funcName = JSStringCreateWithUTF8CString("toStringExplicit"); 641 break; 642 default: 643 return JSValueMakeNull(context); 644 } 645 646 JSValueRef func = JSObjectGetProperty(context, object, funcName, exception); 647 JSStringRelease(funcName); 648 JSObjectRef function = JSValueToObject(context, func, exception); 649 if (!function) 650 return JSValueMakeNull(context); 651 JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception); 652 if (!value) { 653 JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed"); 654 JSValueRef errorStringRef = JSValueMakeString(context, errorString); 655 JSStringRelease(errorString); 656 return errorStringRef; 657 } 658 return value; 659 } 660 661 JSClassDefinition EvilExceptionObject_definition = { 662 0, 663 kJSClassAttributeNone, 664 665 "EvilExceptionObject", 666 NULL, 667 668 NULL, 669 NULL, 670 671 NULL, 672 NULL, 673 NULL, 674 NULL, 675 NULL, 676 NULL, 677 NULL, 678 NULL, 679 NULL, 680 EvilExceptionObject_hasInstance, 681 EvilExceptionObject_convertToType, 682 }; 683 684 static JSClassRef EvilExceptionObject_class(JSContextRef context) 685 { 686 UNUSED_PARAM(context); 687 688 static JSClassRef jsClass; 689 if (!jsClass) 690 jsClass = JSClassCreate(&EvilExceptionObject_definition); 691 692 return jsClass; 693 } 694 695 JSClassDefinition EmptyObject_definition = { 696 0, 697 kJSClassAttributeNone, 698 699 NULL, 700 NULL, 701 702 NULL, 703 NULL, 704 705 NULL, 706 NULL, 707 NULL, 708 NULL, 709 NULL, 710 NULL, 711 NULL, 712 NULL, 713 NULL, 714 NULL, 715 NULL, 716 }; 717 718 static JSClassRef EmptyObject_class(JSContextRef context) 719 { 720 UNUSED_PARAM(context); 721 722 static JSClassRef jsClass; 723 if (!jsClass) 724 jsClass = JSClassCreate(&EmptyObject_definition); 725 726 return jsClass; 727 } 728 729 730 static JSValueRef Base_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 731 { 732 UNUSED_PARAM(object); 733 UNUSED_PARAM(propertyName); 734 UNUSED_PARAM(exception); 735 736 return JSValueMakeNumber(ctx, 1); // distinguish base get form derived get 737 } 738 739 static bool Base_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 740 { 741 UNUSED_PARAM(object); 742 UNUSED_PARAM(propertyName); 743 UNUSED_PARAM(value); 744 745 *exception = JSValueMakeNumber(ctx, 1); // distinguish base set from derived set 746 return true; 747 } 748 749 static JSValueRef Base_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 750 { 751 UNUSED_PARAM(function); 752 UNUSED_PARAM(thisObject); 753 UNUSED_PARAM(argumentCount); 754 UNUSED_PARAM(arguments); 755 UNUSED_PARAM(exception); 756 757 return JSValueMakeNumber(ctx, 1); // distinguish base call from derived call 758 } 759 760 static JSValueRef Base_returnHardNull(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 761 { 762 UNUSED_PARAM(ctx); 763 UNUSED_PARAM(function); 764 UNUSED_PARAM(thisObject); 765 UNUSED_PARAM(argumentCount); 766 UNUSED_PARAM(arguments); 767 UNUSED_PARAM(exception); 768 769 return 0; // should convert to undefined! 770 } 771 772 static JSStaticFunction Base_staticFunctions[] = { 773 { "baseProtoDup", NULL, kJSPropertyAttributeNone }, 774 { "baseProto", Base_callAsFunction, kJSPropertyAttributeNone }, 775 { "baseHardNull", Base_returnHardNull, kJSPropertyAttributeNone }, 776 { 0, 0, 0 } 777 }; 778 779 static JSStaticValue Base_staticValues[] = { 780 { "baseDup", Base_get, Base_set, kJSPropertyAttributeNone }, 781 { "baseOnly", Base_get, Base_set, kJSPropertyAttributeNone }, 782 { 0, 0, 0, 0 } 783 }; 784 785 static bool TestInitializeFinalize; 786 static void Base_initialize(JSContextRef context, JSObjectRef object) 787 { 788 UNUSED_PARAM(context); 789 790 if (TestInitializeFinalize) { 791 ASSERT((void*)1 == JSObjectGetPrivate(object)); 792 JSObjectSetPrivate(object, (void*)2); 793 } 794 } 795 796 static unsigned Base_didFinalize; 797 static void Base_finalize(JSObjectRef object) 798 { 799 UNUSED_PARAM(object); 800 if (TestInitializeFinalize) { 801 ASSERT((void*)4 == JSObjectGetPrivate(object)); 802 Base_didFinalize = true; 803 } 804 } 805 806 static JSClassRef Base_class(JSContextRef context) 807 { 808 UNUSED_PARAM(context); 809 810 static JSClassRef jsClass; 811 if (!jsClass) { 812 JSClassDefinition definition = kJSClassDefinitionEmpty; 813 definition.staticValues = Base_staticValues; 814 definition.staticFunctions = Base_staticFunctions; 815 definition.initialize = Base_initialize; 816 definition.finalize = Base_finalize; 817 jsClass = JSClassCreate(&definition); 818 } 819 return jsClass; 820 } 821 822 static JSValueRef Derived_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 823 { 824 UNUSED_PARAM(object); 825 UNUSED_PARAM(propertyName); 826 UNUSED_PARAM(exception); 827 828 return JSValueMakeNumber(ctx, 2); // distinguish base get form derived get 829 } 830 831 static bool Derived_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 832 { 833 UNUSED_PARAM(ctx); 834 UNUSED_PARAM(object); 835 UNUSED_PARAM(propertyName); 836 UNUSED_PARAM(value); 837 838 *exception = JSValueMakeNumber(ctx, 2); // distinguish base set from derived set 839 return true; 840 } 841 842 static JSValueRef Derived_callAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 843 { 844 UNUSED_PARAM(function); 845 UNUSED_PARAM(thisObject); 846 UNUSED_PARAM(argumentCount); 847 UNUSED_PARAM(arguments); 848 UNUSED_PARAM(exception); 849 850 return JSValueMakeNumber(ctx, 2); // distinguish base call from derived call 851 } 852 853 static JSStaticFunction Derived_staticFunctions[] = { 854 { "protoOnly", Derived_callAsFunction, kJSPropertyAttributeNone }, 855 { "protoDup", NULL, kJSPropertyAttributeNone }, 856 { "baseProtoDup", Derived_callAsFunction, kJSPropertyAttributeNone }, 857 { 0, 0, 0 } 858 }; 859 860 static JSStaticValue Derived_staticValues[] = { 861 { "derivedOnly", Derived_get, Derived_set, kJSPropertyAttributeNone }, 862 { "protoDup", Derived_get, Derived_set, kJSPropertyAttributeNone }, 863 { "baseDup", Derived_get, Derived_set, kJSPropertyAttributeNone }, 864 { 0, 0, 0, 0 } 865 }; 866 867 static void Derived_initialize(JSContextRef context, JSObjectRef object) 868 { 869 UNUSED_PARAM(context); 870 871 if (TestInitializeFinalize) { 872 ASSERT((void*)2 == JSObjectGetPrivate(object)); 873 JSObjectSetPrivate(object, (void*)3); 874 } 875 } 876 877 static void Derived_finalize(JSObjectRef object) 878 { 879 if (TestInitializeFinalize) { 880 ASSERT((void*)3 == JSObjectGetPrivate(object)); 881 JSObjectSetPrivate(object, (void*)4); 882 } 883 } 884 885 static JSClassRef Derived_class(JSContextRef context) 886 { 887 static JSClassRef jsClass; 888 if (!jsClass) { 889 JSClassDefinition definition = kJSClassDefinitionEmpty; 890 definition.parentClass = Base_class(context); 891 definition.staticValues = Derived_staticValues; 892 definition.staticFunctions = Derived_staticFunctions; 893 definition.initialize = Derived_initialize; 894 definition.finalize = Derived_finalize; 895 jsClass = JSClassCreate(&definition); 896 } 897 return jsClass; 898 } 899 900 static JSClassRef Derived2_class(JSContextRef context) 901 { 902 static JSClassRef jsClass; 903 if (!jsClass) { 904 JSClassDefinition definition = kJSClassDefinitionEmpty; 905 definition.parentClass = Derived_class(context); 906 jsClass = JSClassCreate(&definition); 907 } 908 return jsClass; 909 } 910 911 static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 912 { 913 UNUSED_PARAM(functionObject); 914 UNUSED_PARAM(thisObject); 915 UNUSED_PARAM(exception); 916 917 ASSERT(JSContextGetGlobalContext(ctx) == context); 918 919 if (argumentCount > 0) { 920 JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL); 921 size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string); 922 char* stringUTF8 = (char*)malloc(sizeUTF8); 923 JSStringGetUTF8CString(string, stringUTF8, sizeUTF8); 924 printf("%s\n", stringUTF8); 925 free(stringUTF8); 926 JSStringRelease(string); 927 } 928 929 return JSValueMakeUndefined(ctx); 930 } 931 932 static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 933 { 934 UNUSED_PARAM(constructorObject); 935 UNUSED_PARAM(exception); 936 937 JSObjectRef result = JSObjectMake(context, NULL, NULL); 938 if (argumentCount > 0) { 939 JSStringRef value = JSStringCreateWithUTF8CString("value"); 940 JSObjectSetProperty(context, result, value, arguments[0], kJSPropertyAttributeNone, NULL); 941 JSStringRelease(value); 942 } 943 944 return result; 945 } 946 947 static JSObjectRef myBadConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 948 { 949 UNUSED_PARAM(context); 950 UNUSED_PARAM(constructorObject); 951 UNUSED_PARAM(argumentCount); 952 UNUSED_PARAM(arguments); 953 UNUSED_PARAM(exception); 954 955 return 0; 956 } 957 958 959 static void globalObject_initialize(JSContextRef context, JSObjectRef object) 960 { 961 UNUSED_PARAM(object); 962 // Ensure that an execution context is passed in 963 ASSERT(context); 964 965 JSObjectRef globalObject = JSContextGetGlobalObject(context); 966 ASSERT(globalObject); 967 968 // Ensure that the standard global properties have been set on the global object 969 JSStringRef array = JSStringCreateWithUTF8CString("Array"); 970 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL); 971 JSStringRelease(array); 972 973 UNUSED_PARAM(arrayConstructor); 974 ASSERT(arrayConstructor); 975 } 976 977 static JSValueRef globalObject_get(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef* exception) 978 { 979 UNUSED_PARAM(object); 980 UNUSED_PARAM(propertyName); 981 UNUSED_PARAM(exception); 982 983 return JSValueMakeNumber(ctx, 3); 984 } 985 986 static bool globalObject_set(JSContextRef ctx, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) 987 { 988 UNUSED_PARAM(object); 989 UNUSED_PARAM(propertyName); 990 UNUSED_PARAM(value); 991 992 *exception = JSValueMakeNumber(ctx, 3); 993 return true; 994 } 995 996 static JSValueRef globalObject_call(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 997 { 998 UNUSED_PARAM(function); 999 UNUSED_PARAM(thisObject); 1000 UNUSED_PARAM(argumentCount); 1001 UNUSED_PARAM(arguments); 1002 UNUSED_PARAM(exception); 1003 1004 return JSValueMakeNumber(ctx, 3); 1005 } 1006 1007 static JSValueRef functionGC(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 1008 { 1009 UNUSED_PARAM(function); 1010 UNUSED_PARAM(thisObject); 1011 UNUSED_PARAM(argumentCount); 1012 UNUSED_PARAM(arguments); 1013 UNUSED_PARAM(exception); 1014 JSGarbageCollect(context); 1015 return JSValueMakeUndefined(context); 1016 } 1017 1018 static JSStaticValue globalObject_staticValues[] = { 1019 { "globalStaticValue", globalObject_get, globalObject_set, kJSPropertyAttributeNone }, 1020 { "globalStaticValue2", globalObject_get, 0, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum }, 1021 { 0, 0, 0, 0 } 1022 }; 1023 1024 static JSStaticFunction globalObject_staticFunctions[] = { 1025 { "globalStaticFunction", globalObject_call, kJSPropertyAttributeNone }, 1026 { "globalStaticFunction2", globalObject_call, kJSPropertyAttributeNone }, 1027 { "globalStaticFunction3", globalObject_call, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum }, 1028 { "gc", functionGC, kJSPropertyAttributeNone }, 1029 { 0, 0, 0 } 1030 }; 1031 1032 static char* createStringWithContentsOfFile(const char* fileName); 1033 1034 static void testInitializeFinalize() 1035 { 1036 JSObjectRef o = JSObjectMake(context, Derived_class(context), (void*)1); 1037 UNUSED_PARAM(o); 1038 ASSERT(JSObjectGetPrivate(o) == (void*)3); 1039 } 1040 1041 static JSValueRef jsNumberValue = NULL; 1042 1043 static JSObjectRef aHeapRef = NULL; 1044 1045 static void makeGlobalNumberValue(JSContextRef context) { 1046 JSValueRef v = JSValueMakeNumber(context, 420); 1047 JSValueProtect(context, v); 1048 jsNumberValue = v; 1049 v = NULL; 1050 } 1051 1052 bool assertTrue(bool value, const char* message) 1053 { 1054 if (!value) { 1055 if (message) 1056 fprintf(stderr, "assertTrue failed: '%s'\n", message); 1057 else 1058 fprintf(stderr, "assertTrue failed.\n"); 1059 failed = 1; 1060 } 1061 return value; 1062 } 1063 1064 static bool checkForCycleInPrototypeChain() 1065 { 1066 bool result = true; 1067 JSGlobalContextRef context = JSGlobalContextCreate(0); 1068 JSObjectRef object1 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); 1069 JSObjectRef object2 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); 1070 JSObjectRef object3 = JSObjectMake(context, /* jsClass */ 0, /* data */ 0); 1071 1072 JSObjectSetPrototype(context, object1, JSValueMakeNull(context)); 1073 ASSERT(JSValueIsNull(context, JSObjectGetPrototype(context, object1))); 1074 1075 // object1 -> object1 1076 JSObjectSetPrototype(context, object1, object1); 1077 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to assign self as a prototype"); 1078 1079 // object1 -> object2 -> object1 1080 JSObjectSetPrototype(context, object2, object1); 1081 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object1)); 1082 JSObjectSetPrototype(context, object1, object2); 1083 result &= assertTrue(JSValueIsNull(context, JSObjectGetPrototype(context, object1)), "It is possible to close a prototype chain cycle"); 1084 1085 // object1 -> object2 -> object3 -> object1 1086 JSObjectSetPrototype(context, object2, object3); 1087 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object2), object3)); 1088 JSObjectSetPrototype(context, object1, object2); 1089 ASSERT(JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object1), object2)); 1090 JSObjectSetPrototype(context, object3, object1); 1091 result &= assertTrue(!JSValueIsStrictEqual(context, JSObjectGetPrototype(context, object3), object1), "It is possible to close a prototype chain cycle"); 1092 1093 JSValueRef exception; 1094 JSStringRef code = JSStringCreateWithUTF8CString("o = { }; p = { }; o.__proto__ = p; p.__proto__ = o"); 1095 JSStringRef file = JSStringCreateWithUTF8CString(""); 1096 result &= assertTrue(!JSEvaluateScript(context, code, /* thisObject*/ 0, file, 1, &exception) 1097 , "An exception should be thrown"); 1098 1099 JSStringRelease(code); 1100 JSStringRelease(file); 1101 JSGlobalContextRelease(context); 1102 return result; 1103 } 1104 1105 static JSValueRef valueToObjectExceptionCallAsFunction(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) 1106 { 1107 UNUSED_PARAM(function); 1108 UNUSED_PARAM(thisObject); 1109 UNUSED_PARAM(argumentCount); 1110 UNUSED_PARAM(arguments); 1111 JSValueRef jsUndefined = JSValueMakeUndefined(JSContextGetGlobalContext(ctx)); 1112 JSValueToObject(JSContextGetGlobalContext(ctx), jsUndefined, exception); 1113 1114 return JSValueMakeUndefined(ctx); 1115 } 1116 static bool valueToObjectExceptionTest() 1117 { 1118 JSGlobalContextRef testContext; 1119 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; 1120 globalObjectClassDefinition.initialize = globalObject_initialize; 1121 globalObjectClassDefinition.staticValues = globalObject_staticValues; 1122 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; 1123 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; 1124 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); 1125 testContext = JSGlobalContextCreateInGroup(NULL, globalObjectClass); 1126 JSObjectRef globalObject = JSContextGetGlobalObject(testContext); 1127 1128 JSStringRef valueToObject = JSStringCreateWithUTF8CString("valueToObject"); 1129 JSObjectRef valueToObjectFunction = JSObjectMakeFunctionWithCallback(testContext, valueToObject, valueToObjectExceptionCallAsFunction); 1130 JSObjectSetProperty(testContext, globalObject, valueToObject, valueToObjectFunction, kJSPropertyAttributeNone, NULL); 1131 JSStringRelease(valueToObject); 1132 1133 JSStringRef test = JSStringCreateWithUTF8CString("valueToObject();"); 1134 JSEvaluateScript(testContext, test, NULL, NULL, 1, NULL); 1135 1136 JSStringRelease(test); 1137 JSClassRelease(globalObjectClass); 1138 JSGlobalContextRelease(testContext); 1139 1140 return true; 1141 } 1142 1143 static bool globalContextNameTest() 1144 { 1145 bool result = true; 1146 JSGlobalContextRef context = JSGlobalContextCreate(0); 1147 1148 JSStringRef str = JSGlobalContextCopyName(context); 1149 result &= assertTrue(!str, "Default context name is NULL"); 1150 1151 JSStringRef name1 = JSStringCreateWithUTF8CString("name1"); 1152 JSStringRef name2 = JSStringCreateWithUTF8CString("name2"); 1153 1154 JSGlobalContextSetName(context, name1); 1155 JSStringRef fetchName1 = JSGlobalContextCopyName(context); 1156 JSGlobalContextSetName(context, name2); 1157 JSStringRef fetchName2 = JSGlobalContextCopyName(context); 1158 JSGlobalContextSetName(context, NULL); 1159 JSStringRef fetchName3 = JSGlobalContextCopyName(context); 1160 1161 result &= assertTrue(JSStringIsEqual(name1, fetchName1), "Unexpected Context name"); 1162 result &= assertTrue(JSStringIsEqual(name2, fetchName2), "Unexpected Context name"); 1163 result &= assertTrue(!JSStringIsEqual(fetchName1, fetchName2), "Unexpected Context name"); 1164 result &= assertTrue(!fetchName3, "Unexpected Context name"); 1165 1166 JSStringRelease(name1); 1167 JSStringRelease(name2); 1168 JSStringRelease(fetchName1); 1169 JSStringRelease(fetchName2); 1170 1171 JSGlobalContextRelease(context); 1172 1173 return result; 1174 } 1175 1176 IGNORE_GCC_WARNINGS_BEGIN("unused-but-set-variable") 1177 static void checkConstnessInJSObjectNames() 1178 { 1179 JSStaticFunction fun; 1180 fun.name = "something"; 1181 JSStaticValue val; 1182 val.name = "something"; 1183 } 1184 IGNORE_GCC_WARNINGS_END 1185 1186 #ifdef __cplusplus 1187 extern "C" { 1188 #endif 1189 void JSSynchronousGarbageCollectForDebugging(JSContextRef); 1190 #ifdef __cplusplus 1191 } 1192 #endif 1193 1194 static const unsigned numWeakRefs = 10000; 1195 1196 static void markingConstraint(JSMarkerRef marker, void *userData) 1197 { 1198 JSWeakRef *weakRefs; 1199 unsigned i; 1200 1201 weakRefs = (JSWeakRef*)userData; 1202 1203 for (i = 0; i < numWeakRefs; i += 2) { 1204 JSWeakRef weakRef = weakRefs[i]; 1205 if (weakRef) { 1206 JSObjectRef object = JSWeakGetObject(weakRefs[i]); 1207 marker->Mark(marker, object); 1208 assertTrue(marker->IsMarked(marker, object), "A marked object is marked"); 1209 } 1210 } 1211 } 1212 1213 static bool didRunHeapFinalizer; 1214 static JSContextGroupRef expectedContextGroup; 1215 1216 static void heapFinalizer(JSContextGroupRef group, void *userData) 1217 { 1218 assertTrue((uintptr_t)userData == (uintptr_t)42, "Correct userData was passed"); 1219 assertTrue(group == expectedContextGroup, "Correct context group"); 1220 1221 didRunHeapFinalizer = true; 1222 } 1223 1224 static void testMarkingConstraintsAndHeapFinalizers(void) 1225 { 1226 JSContextGroupRef group; 1227 JSWeakRef *weakRefs; 1228 unsigned i; 1229 unsigned deadCount; 1230 1231 printf("Testing Marking Constraints.\n"); 1232 1233 group = JSContextGroupCreate(); 1234 expectedContextGroup = group; 1235 1236 JSGlobalContextRef context = JSGlobalContextCreateInGroup(group, NULL); 1237 1238 weakRefs = (JSWeakRef*)calloc(numWeakRefs, sizeof(JSWeakRef)); 1239 1240 JSContextGroupAddMarkingConstraint(group, markingConstraint, (void*)weakRefs); 1241 JSContextGroupAddHeapFinalizer(group, heapFinalizer, (void*)(uintptr_t)42); 1242 1243 for (i = numWeakRefs; i--;) 1244 weakRefs[i] = JSWeakCreate(group, JSObjectMakeArray(context, 0, NULL, NULL)); 1245 1246 JSSynchronousGarbageCollectForDebugging(context); 1247 assertTrue(didRunHeapFinalizer, "Did run heap finalizer"); 1248 1249 deadCount = 0; 1250 for (i = 0; i < numWeakRefs; i += 2) { 1251 assertTrue((bool)JSWeakGetObject(weakRefs[i]), "Marked objects stayed alive"); 1252 if (!JSWeakGetObject(weakRefs[i + 1])) 1253 deadCount++; 1254 } 1255 1256 assertTrue(deadCount != 0, "At least some objects died"); 1257 1258 for (i = numWeakRefs; i--;) { 1259 JSWeakRef weakRef = weakRefs[i]; 1260 weakRefs[i] = NULL; 1261 JSWeakRelease(group, weakRef); 1262 } 1263 1264 didRunHeapFinalizer = false; 1265 JSSynchronousGarbageCollectForDebugging(context); 1266 assertTrue(didRunHeapFinalizer, "Did run heap finalizer"); 1267 1268 JSContextGroupRemoveHeapFinalizer(group, heapFinalizer, (void*)(uintptr_t)42); 1269 1270 didRunHeapFinalizer = false; 1271 JSSynchronousGarbageCollectForDebugging(context); 1272 assertTrue(!didRunHeapFinalizer, "Did not run heap finalizer"); 1273 1274 JSGlobalContextRelease(context); 1275 JSContextGroupRelease(group); 1276 1277 printf("PASS: Marking Constraints and Heap Finalizers.\n"); 1278 } 1279 1280 #if USE(CF) 1281 static void testCFStrings(void) 1282 { 1283 /* The assertion utility functions we use below expects to get the JSGlobalContextRef 1284 from the global context variable. */ 1285 JSGlobalContextRef oldContext = context; 1286 context = JSGlobalContextCreate(0); 1287 1288 UniChar singleUniChar = 65; // Capital A 1289 CFMutableStringRef cfString = CFStringCreateMutableWithExternalCharactersNoCopy(kCFAllocatorDefault, &singleUniChar, 1, 1, kCFAllocatorNull); 1290 1291 JSStringRef jsCFIString = JSStringCreateWithCFString(cfString); 1292 JSValueRef jsCFString = JSValueMakeString(context, jsCFIString); 1293 1294 CFStringRef cfEmptyString = CFStringCreateWithCString(kCFAllocatorDefault, "", kCFStringEncodingUTF8); 1295 1296 JSStringRef jsCFEmptyIString = JSStringCreateWithCFString(cfEmptyString); 1297 JSValueRef jsCFEmptyString = JSValueMakeString(context, jsCFEmptyIString); 1298 1299 CFIndex cfStringLength = CFStringGetLength(cfString); 1300 UniChar* buffer = (UniChar*)malloc(cfStringLength * sizeof(UniChar)); 1301 CFStringGetCharacters(cfString, CFRangeMake(0, cfStringLength), buffer); 1302 JSStringRef jsCFIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, cfStringLength); 1303 JSValueRef jsCFStringWithCharacters = JSValueMakeString(context, jsCFIStringWithCharacters); 1304 1305 JSStringRef jsCFEmptyIStringWithCharacters = JSStringCreateWithCharacters((JSChar*)buffer, CFStringGetLength(cfEmptyString)); 1306 free(buffer); 1307 JSValueRef jsCFEmptyStringWithCharacters = JSValueMakeString(context, jsCFEmptyIStringWithCharacters); 1308 1309 ASSERT(JSValueGetType(context, jsCFString) == kJSTypeString); 1310 ASSERT(JSValueGetType(context, jsCFStringWithCharacters) == kJSTypeString); 1311 ASSERT(JSValueGetType(context, jsCFEmptyString) == kJSTypeString); 1312 ASSERT(JSValueGetType(context, jsCFEmptyStringWithCharacters) == kJSTypeString); 1313 1314 JSStringRef emptyString = JSStringCreateWithCFString(CFSTR("")); 1315 const JSChar* characters = JSStringGetCharactersPtr(emptyString); 1316 if (!characters) { 1317 printf("FAIL: Returned null when accessing character pointer of an empty String.\n"); 1318 failed = 1; 1319 } else 1320 printf("PASS: returned empty when accessing character pointer of an empty String.\n"); 1321 1322 size_t length = JSStringGetLength(emptyString); 1323 if (length) { 1324 printf("FAIL: Didn't return 0 length for empty String.\n"); 1325 failed = 1; 1326 } else 1327 printf("PASS: returned 0 length for empty String.\n"); 1328 JSStringRelease(emptyString); 1329 1330 assertEqualsAsBoolean(jsCFString, true); 1331 assertEqualsAsBoolean(jsCFStringWithCharacters, true); 1332 assertEqualsAsBoolean(jsCFEmptyString, false); 1333 assertEqualsAsBoolean(jsCFEmptyStringWithCharacters, false); 1334 1335 assertEqualsAsNumber(jsCFString, nan("")); 1336 assertEqualsAsNumber(jsCFStringWithCharacters, nan("")); 1337 assertEqualsAsNumber(jsCFEmptyString, 0); 1338 assertEqualsAsNumber(jsCFEmptyStringWithCharacters, 0); 1339 ASSERT(sizeof(JSChar) == sizeof(UniChar)); 1340 1341 assertEqualsAsCharactersPtr(jsCFString, "A"); 1342 assertEqualsAsCharactersPtr(jsCFStringWithCharacters, "A"); 1343 assertEqualsAsCharactersPtr(jsCFEmptyString, ""); 1344 assertEqualsAsCharactersPtr(jsCFEmptyStringWithCharacters, ""); 1345 1346 assertEqualsAsUTF8String(jsCFString, "A"); 1347 assertEqualsAsUTF8String(jsCFStringWithCharacters, "A"); 1348 assertEqualsAsUTF8String(jsCFEmptyString, ""); 1349 assertEqualsAsUTF8String(jsCFEmptyStringWithCharacters, ""); 1350 1351 CFStringRef cfJSString = JSStringCopyCFString(kCFAllocatorDefault, jsCFIString); 1352 CFStringRef cfJSEmptyString = JSStringCopyCFString(kCFAllocatorDefault, jsCFEmptyIString); 1353 ASSERT(CFEqual(cfJSString, cfString)); 1354 ASSERT(CFEqual(cfJSEmptyString, cfEmptyString)); 1355 CFRelease(cfJSString); 1356 CFRelease(cfJSEmptyString); 1357 1358 JSObjectRef o = JSObjectMake(context, NULL, NULL); 1359 JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1"); 1360 JSObjectSetProperty(context, o, jsOneIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeNone, NULL); 1361 JSObjectSetProperty(context, o, jsCFIString, JSValueMakeNumber(context, 1), kJSPropertyAttributeDontEnum, NULL); 1362 JSPropertyNameArrayRef nameArray = JSObjectCopyPropertyNames(context, o); 1363 size_t expectedCount = JSPropertyNameArrayGetCount(nameArray); 1364 size_t count; 1365 for (count = 0; count < expectedCount; ++count) 1366 JSPropertyNameArrayGetNameAtIndex(nameArray, count); 1367 JSPropertyNameArrayRelease(nameArray); 1368 ASSERT(count == 1); // jsCFString should not be enumerated 1369 1370 JSStringRelease(jsOneIString); 1371 JSStringRelease(jsCFIString); 1372 JSStringRelease(jsCFEmptyIString); 1373 JSStringRelease(jsCFIStringWithCharacters); 1374 JSStringRelease(jsCFEmptyIStringWithCharacters); 1375 CFRelease(cfString); 1376 CFRelease(cfEmptyString); 1377 1378 JSGlobalContextRelease(context); 1379 context = oldContext; 1380 } 1381 #endif 1382 1383 int main(int argc, char* argv[]) 1384 { 1385 #if OS(WINDOWS) 1386 // Cygwin calls SetErrorMode(SEM_FAILCRITICALERRORS), which we will inherit. This is bad for 1387 // testing/debugging, as it causes the post-mortem debugger not to be invoked. We reset the 1388 // error mode here to work around Cygwin's behavior. See <http://webkit.org/b/55222>. 1389 SetErrorMode(0); 1390 #endif 1391 1392 configureJSCForTesting(); 1393 1394 #if !OS(WINDOWS) 1395 char resolvedPath[PATH_MAX]; 1396 if (!realpath(argv[0], resolvedPath)) 1397 fprintf(stdout, "Could not get the absolute pathname for: %s\n", argv[0]); 1398 char* newCWD = dirname(resolvedPath); 1399 if (chdir(newCWD)) 1400 fprintf(stdout, "Could not chdir to: %s\n", newCWD); 1401 #endif 1402 1403 const char* filter = argc > 1 ? argv[1] : NULL; 1404 #if JSC_OBJC_API_ENABLED 1405 testObjectiveCAPI(filter); 1406 #endif 1407 1408 RELEASE_ASSERT(!testCAPIViaCpp(filter)); 1409 if (filter) 1410 return 0; 1411 1412 testCompareAndSwap(); 1413 startMultithreadedMultiVMExecutionTest(); 1414 1415 // Test garbage collection with a fresh context 1416 context = JSGlobalContextCreateInGroup(NULL, NULL); 1417 TestInitializeFinalize = true; 1418 testInitializeFinalize(); 1419 JSGlobalContextRelease(context); 1420 TestInitializeFinalize = false; 1421 1422 ASSERT(Base_didFinalize); 1423 1424 testMarkingConstraintsAndHeapFinalizers(); 1425 1426 #if USE(CF) 1427 testCFStrings(); 1428 #endif 1429 1430 JSClassDefinition globalObjectClassDefinition = kJSClassDefinitionEmpty; 1431 globalObjectClassDefinition.initialize = globalObject_initialize; 1432 globalObjectClassDefinition.staticValues = globalObject_staticValues; 1433 globalObjectClassDefinition.staticFunctions = globalObject_staticFunctions; 1434 globalObjectClassDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; 1435 JSClassRef globalObjectClass = JSClassCreate(&globalObjectClassDefinition); 1436 context = JSGlobalContextCreateInGroup(NULL, globalObjectClass); 1437 1438 JSContextGroupRef contextGroup = JSContextGetGroup(context); 1439 1440 JSGlobalContextRetain(context); 1441 JSGlobalContextRelease(context); 1442 ASSERT(JSContextGetGlobalContext(context) == context); 1443 1444 JSReportExtraMemoryCost(context, 0); 1445 JSReportExtraMemoryCost(context, 1); 1446 JSReportExtraMemoryCost(context, 1024); 1447 1448 JSObjectRef globalObject = JSContextGetGlobalObject(context); 1449 ASSERT(JSValueIsObject(context, globalObject)); 1450 1451 JSValueRef jsUndefined = JSValueMakeUndefined(context); 1452 JSValueRef jsNull = JSValueMakeNull(context); 1453 JSValueRef jsTrue = JSValueMakeBoolean(context, true); 1454 JSValueRef jsFalse = JSValueMakeBoolean(context, false); 1455 JSValueRef jsZero = JSValueMakeNumber(context, 0); 1456 JSValueRef jsOne = JSValueMakeNumber(context, 1); 1457 JSValueRef jsOneThird = JSValueMakeNumber(context, 1.0 / 3.0); 1458 JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, NULL); 1459 JSObjectSetPrototype(context, jsObjectNoProto, JSValueMakeNull(context)); 1460 1461 JSObjectSetPrivate(globalObject, (void*)123); 1462 if (JSObjectGetPrivate(globalObject) != (void*)123) { 1463 printf("FAIL: Didn't return private data when set by JSObjectSetPrivate().\n"); 1464 failed = 1; 1465 } else 1466 printf("PASS: returned private data when set by JSObjectSetPrivate().\n"); 1467 1468 // FIXME: test funny utf8 characters 1469 JSStringRef jsEmptyIString = JSStringCreateWithUTF8CString(""); 1470 JSValueRef jsEmptyString = JSValueMakeString(context, jsEmptyIString); 1471 1472 JSStringRef jsOneIString = JSStringCreateWithUTF8CString("1"); 1473 JSValueRef jsOneString = JSValueMakeString(context, jsOneIString); 1474 1475 JSChar constantString[] = { 'H', 'e', 'l', 'l', 'o', }; 1476 JSStringRef constantStringRef = JSStringCreateWithCharactersNoCopy(constantString, sizeof(constantString) / sizeof(constantString[0])); 1477 ASSERT(JSStringGetCharactersPtr(constantStringRef) == constantString); 1478 JSStringRelease(constantStringRef); 1479 1480 ASSERT(JSValueGetType(context, NULL) == kJSTypeNull); 1481 ASSERT(JSValueGetType(context, jsUndefined) == kJSTypeUndefined); 1482 ASSERT(JSValueGetType(context, jsNull) == kJSTypeNull); 1483 ASSERT(JSValueGetType(context, jsTrue) == kJSTypeBoolean); 1484 ASSERT(JSValueGetType(context, jsFalse) == kJSTypeBoolean); 1485 ASSERT(JSValueGetType(context, jsZero) == kJSTypeNumber); 1486 ASSERT(JSValueGetType(context, jsOne) == kJSTypeNumber); 1487 ASSERT(JSValueGetType(context, jsOneThird) == kJSTypeNumber); 1488 ASSERT(JSValueGetType(context, jsEmptyString) == kJSTypeString); 1489 ASSERT(JSValueGetType(context, jsOneString) == kJSTypeString); 1490 1491 ASSERT(!JSValueIsBoolean(context, NULL)); 1492 ASSERT(!JSValueIsObject(context, NULL)); 1493 ASSERT(!JSValueIsArray(context, NULL)); 1494 ASSERT(!JSValueIsDate(context, NULL)); 1495 ASSERT(!JSValueIsString(context, NULL)); 1496 ASSERT(!JSValueIsNumber(context, NULL)); 1497 ASSERT(!JSValueIsUndefined(context, NULL)); 1498 ASSERT(JSValueIsNull(context, NULL)); 1499 ASSERT(!JSObjectCallAsFunction(context, NULL, NULL, 0, NULL, NULL)); 1500 ASSERT(!JSObjectCallAsConstructor(context, NULL, 0, NULL, NULL)); 1501 ASSERT(!JSObjectIsConstructor(context, NULL)); 1502 ASSERT(!JSObjectIsFunction(context, NULL)); 1503 1504 JSStringRef nullString = JSStringCreateWithUTF8CString(0); 1505 const JSChar* characters = JSStringGetCharactersPtr(nullString); 1506 if (characters) { 1507 printf("FAIL: Didn't return null when accessing character pointer of a null String.\n"); 1508 failed = 1; 1509 } else 1510 printf("PASS: returned null when accessing character pointer of a null String.\n"); 1511 1512 size_t length = JSStringGetLength(nullString); 1513 if (length) { 1514 printf("FAIL: Didn't return 0 length for null String.\n"); 1515 failed = 1; 1516 } else 1517 printf("PASS: returned 0 length for null String.\n"); 1518 JSStringRelease(nullString); 1519 1520 JSObjectRef propertyCatchalls = JSObjectMake(context, PropertyCatchalls_class(context), NULL); 1521 JSStringRef propertyCatchallsString = JSStringCreateWithUTF8CString("PropertyCatchalls"); 1522 JSObjectSetProperty(context, globalObject, propertyCatchallsString, propertyCatchalls, kJSPropertyAttributeNone, NULL); 1523 JSStringRelease(propertyCatchallsString); 1524 1525 JSObjectRef myObject = JSObjectMake(context, MyObject_class(context), NULL); 1526 JSStringRef myObjectIString = JSStringCreateWithUTF8CString("MyObject"); 1527 JSObjectSetProperty(context, globalObject, myObjectIString, myObject, kJSPropertyAttributeNone, NULL); 1528 JSStringRelease(myObjectIString); 1529 1530 JSObjectRef EvilExceptionObject = JSObjectMake(context, EvilExceptionObject_class(context), NULL); 1531 JSStringRef EvilExceptionObjectIString = JSStringCreateWithUTF8CString("EvilExceptionObject"); 1532 JSObjectSetProperty(context, globalObject, EvilExceptionObjectIString, EvilExceptionObject, kJSPropertyAttributeNone, NULL); 1533 JSStringRelease(EvilExceptionObjectIString); 1534 1535 JSObjectRef EmptyObject = JSObjectMake(context, EmptyObject_class(context), NULL); 1536 JSStringRef EmptyObjectIString = JSStringCreateWithUTF8CString("EmptyObject"); 1537 JSObjectSetProperty(context, globalObject, EmptyObjectIString, EmptyObject, kJSPropertyAttributeNone, NULL); 1538 JSStringRelease(EmptyObjectIString); 1539 1540 JSStringRef lengthStr = JSStringCreateWithUTF8CString("length"); 1541 JSObjectRef aStackRef = JSObjectMakeArray(context, 0, 0, 0); 1542 aHeapRef = aStackRef; 1543 JSObjectSetProperty(context, aHeapRef, lengthStr, JSValueMakeNumber(context, 10), 0, 0); 1544 JSStringRef privatePropertyName = JSStringCreateWithUTF8CString("privateProperty"); 1545 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, aHeapRef)) { 1546 printf("FAIL: Could not set private property.\n"); 1547 failed = 1; 1548 } else 1549 printf("PASS: Set private property.\n"); 1550 aStackRef = 0; 1551 if (JSObjectSetPrivateProperty(context, aHeapRef, privatePropertyName, aHeapRef)) { 1552 printf("FAIL: JSObjectSetPrivateProperty should fail on non-API objects.\n"); 1553 failed = 1; 1554 } else 1555 printf("PASS: Did not allow JSObjectSetPrivateProperty on a non-API object.\n"); 1556 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName) != aHeapRef) { 1557 printf("FAIL: Could not retrieve private property.\n"); 1558 failed = 1; 1559 } else 1560 printf("PASS: Retrieved private property.\n"); 1561 if (JSObjectGetPrivateProperty(context, aHeapRef, privatePropertyName)) { 1562 printf("FAIL: JSObjectGetPrivateProperty should return NULL when called on a non-API object.\n"); 1563 failed = 1; 1564 } else 1565 printf("PASS: JSObjectGetPrivateProperty return NULL.\n"); 1566 1567 if (JSObjectGetProperty(context, myObject, privatePropertyName, 0) == aHeapRef) { 1568 printf("FAIL: Accessed private property through ordinary property lookup.\n"); 1569 failed = 1; 1570 } else 1571 printf("PASS: Cannot access private property through ordinary property lookup.\n"); 1572 1573 JSGarbageCollect(context); 1574 1575 int i; 1576 for (i = 0; i < 10000; i++) 1577 JSObjectMake(context, 0, 0); 1578 1579 aHeapRef = JSValueToObject(context, JSObjectGetPrivateProperty(context, myObject, privatePropertyName), 0); 1580 if (JSValueToNumber(context, JSObjectGetProperty(context, aHeapRef, lengthStr, 0), 0) != 10) { 1581 printf("FAIL: Private property has been collected.\n"); 1582 failed = 1; 1583 } else 1584 printf("PASS: Private property does not appear to have been collected.\n"); 1585 JSStringRelease(lengthStr); 1586 1587 if (!JSObjectSetPrivateProperty(context, myObject, privatePropertyName, 0)) { 1588 printf("FAIL: Could not set private property to NULL.\n"); 1589 failed = 1; 1590 } else 1591 printf("PASS: Set private property to NULL.\n"); 1592 if (JSObjectGetPrivateProperty(context, myObject, privatePropertyName)) { 1593 printf("FAIL: Could not retrieve private property.\n"); 1594 failed = 1; 1595 } else 1596 printf("PASS: Retrieved private property.\n"); 1597 1598 JSStringRef nullJSON = JSStringCreateWithUTF8CString(0); 1599 JSValueRef nullJSONObject = JSValueMakeFromJSONString(context, nullJSON); 1600 if (nullJSONObject) { 1601 printf("FAIL: Did not parse null String as JSON correctly\n"); 1602 failed = 1; 1603 } else 1604 printf("PASS: Parsed null String as JSON correctly.\n"); 1605 JSStringRelease(nullJSON); 1606 1607 JSStringRef validJSON = JSStringCreateWithUTF8CString("{\"aProperty\":true}"); 1608 JSValueRef jsonObject = JSValueMakeFromJSONString(context, validJSON); 1609 JSStringRelease(validJSON); 1610 if (!JSValueIsObject(context, jsonObject)) { 1611 printf("FAIL: Did not parse valid JSON correctly\n"); 1612 failed = 1; 1613 } else 1614 printf("PASS: Parsed valid JSON string.\n"); 1615 JSStringRef propertyName = JSStringCreateWithUTF8CString("aProperty"); 1616 assertEqualsAsBoolean(JSObjectGetProperty(context, JSValueToObject(context, jsonObject, 0), propertyName, 0), true); 1617 JSStringRelease(propertyName); 1618 JSStringRef invalidJSON = JSStringCreateWithUTF8CString("fail!"); 1619 if (JSValueMakeFromJSONString(context, invalidJSON)) { 1620 printf("FAIL: Should return null for invalid JSON data\n"); 1621 failed = 1; 1622 } else 1623 printf("PASS: Correctly returned null for invalid JSON data.\n"); 1624 JSValueRef exception; 1625 JSStringRef str = JSValueCreateJSONString(context, jsonObject, 0, 0); 1626 if (!JSStringIsEqualToUTF8CString(str, "{\"aProperty\":true}")) { 1627 printf("FAIL: Did not correctly serialise with indent of 0.\n"); 1628 failed = 1; 1629 } else 1630 printf("PASS: Correctly serialised with indent of 0.\n"); 1631 JSStringRelease(str); 1632 1633 str = JSValueCreateJSONString(context, jsonObject, 4, 0); 1634 if (!JSStringIsEqualToUTF8CString(str, "{\n \"aProperty\": true\n}")) { 1635 printf("FAIL: Did not correctly serialise with indent of 4.\n"); 1636 failed = 1; 1637 } else 1638 printf("PASS: Correctly serialised with indent of 4.\n"); 1639 JSStringRelease(str); 1640 1641 str = JSStringCreateWithUTF8CString("({get a(){ throw '';}})"); 1642 JSValueRef unstringifiableObj = JSEvaluateScript(context, str, NULL, NULL, 1, NULL); 1643 JSStringRelease(str); 1644 1645 str = JSValueCreateJSONString(context, unstringifiableObj, 4, 0); 1646 if (str) { 1647 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n"); 1648 JSStringRelease(str); 1649 failed = 1; 1650 } else 1651 printf("PASS: returned null when attempting to serialize unserializable value.\n"); 1652 1653 str = JSValueCreateJSONString(context, unstringifiableObj, 4, &exception); 1654 if (str) { 1655 printf("FAIL: Didn't return null when attempting to serialize unserializable value.\n"); 1656 JSStringRelease(str); 1657 failed = 1; 1658 } else 1659 printf("PASS: returned null when attempting to serialize unserializable value.\n"); 1660 if (!exception) { 1661 printf("FAIL: Did not set exception on serialisation error\n"); 1662 failed = 1; 1663 } else 1664 printf("PASS: set exception on serialisation error\n"); 1665 // Conversions that throw exceptions 1666 exception = NULL; 1667 ASSERT(NULL == JSValueToObject(context, jsNull, &exception)); 1668 ASSERT(exception); 1669 1670 exception = NULL; 1671 // FIXME <rdar://4668451> - On i386 the isnan(double) macro tries to map to the isnan(float) function, 1672 // causing a build break with -Wshorten-64-to-32 enabled. The issue is known by the appropriate team. 1673 // After that's resolved, we can remove these casts 1674 ASSERT(isnan((float)JSValueToNumber(context, jsObjectNoProto, &exception))); 1675 ASSERT(exception); 1676 1677 exception = NULL; 1678 ASSERT(!JSValueToStringCopy(context, jsObjectNoProto, &exception)); 1679 ASSERT(exception); 1680 1681 ASSERT(JSValueToBoolean(context, myObject)); 1682 1683 exception = NULL; 1684 ASSERT(!JSValueIsEqual(context, jsObjectNoProto, JSValueMakeNumber(context, 1), &exception)); 1685 ASSERT(exception); 1686 1687 exception = NULL; 1688 JSObjectGetPropertyAtIndex(context, myObject, 0, &exception); 1689 ASSERT(1 == JSValueToNumber(context, exception, NULL)); 1690 1691 assertEqualsAsBoolean(jsUndefined, false); 1692 assertEqualsAsBoolean(jsNull, false); 1693 assertEqualsAsBoolean(jsTrue, true); 1694 assertEqualsAsBoolean(jsFalse, false); 1695 assertEqualsAsBoolean(jsZero, false); 1696 assertEqualsAsBoolean(jsOne, true); 1697 assertEqualsAsBoolean(jsOneThird, true); 1698 assertEqualsAsBoolean(jsEmptyString, false); 1699 assertEqualsAsBoolean(jsOneString, true); 1700 1701 assertEqualsAsNumber(jsUndefined, nan("")); 1702 assertEqualsAsNumber(jsNull, 0); 1703 assertEqualsAsNumber(jsTrue, 1); 1704 assertEqualsAsNumber(jsFalse, 0); 1705 assertEqualsAsNumber(jsZero, 0); 1706 assertEqualsAsNumber(jsOne, 1); 1707 assertEqualsAsNumber(jsOneThird, 1.0 / 3.0); 1708 assertEqualsAsNumber(jsEmptyString, 0); 1709 assertEqualsAsNumber(jsOneString, 1); 1710 1711 assertEqualsAsCharactersPtr(jsUndefined, "undefined"); 1712 assertEqualsAsCharactersPtr(jsNull, "null"); 1713 assertEqualsAsCharactersPtr(jsTrue, "true"); 1714 assertEqualsAsCharactersPtr(jsFalse, "false"); 1715 assertEqualsAsCharactersPtr(jsZero, "0"); 1716 assertEqualsAsCharactersPtr(jsOne, "1"); 1717 assertEqualsAsCharactersPtr(jsOneThird, "0.3333333333333333"); 1718 assertEqualsAsCharactersPtr(jsEmptyString, ""); 1719 assertEqualsAsCharactersPtr(jsOneString, "1"); 1720 1721 assertEqualsAsUTF8String(jsUndefined, "undefined"); 1722 assertEqualsAsUTF8String(jsNull, "null"); 1723 assertEqualsAsUTF8String(jsTrue, "true"); 1724 assertEqualsAsUTF8String(jsFalse, "false"); 1725 assertEqualsAsUTF8String(jsZero, "0"); 1726 assertEqualsAsUTF8String(jsOne, "1"); 1727 assertEqualsAsUTF8String(jsOneThird, "0.3333333333333333"); 1728 assertEqualsAsUTF8String(jsEmptyString, ""); 1729 assertEqualsAsUTF8String(jsOneString, "1"); 1730 1731 checkConstnessInJSObjectNames(); 1732 1733 ASSERT(JSValueIsStrictEqual(context, jsTrue, jsTrue)); 1734 ASSERT(!JSValueIsStrictEqual(context, jsOne, jsOneString)); 1735 1736 ASSERT(JSValueIsEqual(context, jsOne, jsOneString, NULL)); 1737 ASSERT(!JSValueIsEqual(context, jsTrue, jsFalse, NULL)); 1738 1739 jsGlobalValue = JSObjectMake(context, NULL, NULL); 1740 makeGlobalNumberValue(context); 1741 JSValueProtect(context, jsGlobalValue); 1742 JSGarbageCollect(context); 1743 ASSERT(JSValueIsObject(context, jsGlobalValue)); 1744 JSValueUnprotect(context, jsGlobalValue); 1745 JSValueUnprotect(context, jsNumberValue); 1746 1747 JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;"); 1748 const char* badSyntaxConstant = "x := 1;"; 1749 JSStringRef badSyntax = JSStringCreateWithUTF8CString(badSyntaxConstant); 1750 ASSERT(JSCheckScriptSyntax(context, goodSyntax, NULL, 0, NULL)); 1751 ASSERT(!JSCheckScriptSyntax(context, badSyntax, NULL, 0, NULL)); 1752 ASSERT(!JSScriptCreateFromString(contextGroup, 0, 0, badSyntax, 0, 0)); 1753 ASSERT(!JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, badSyntaxConstant, strlen(badSyntaxConstant), 0, 0)); 1754 1755 JSValueRef result; 1756 JSValueRef v; 1757 JSObjectRef o; 1758 JSStringRef string; 1759 1760 result = JSEvaluateScript(context, goodSyntax, NULL, NULL, 1, NULL); 1761 ASSERT(result); 1762 ASSERT(JSValueIsEqual(context, result, jsOne, NULL)); 1763 1764 exception = NULL; 1765 result = JSEvaluateScript(context, badSyntax, NULL, NULL, 1, &exception); 1766 ASSERT(!result); 1767 ASSERT(JSValueIsObject(context, exception)); 1768 1769 JSStringRef array = JSStringCreateWithUTF8CString("Array"); 1770 JSObjectRef arrayConstructor = JSValueToObject(context, JSObjectGetProperty(context, globalObject, array, NULL), NULL); 1771 JSStringRelease(array); 1772 result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL); 1773 ASSERT(result); 1774 ASSERT(JSValueIsObject(context, result)); 1775 ASSERT(JSValueIsInstanceOfConstructor(context, result, arrayConstructor, NULL)); 1776 ASSERT(!JSValueIsInstanceOfConstructor(context, JSValueMakeNull(context), arrayConstructor, NULL)); 1777 1778 o = JSValueToObject(context, result, NULL); 1779 exception = NULL; 1780 ASSERT(JSValueIsUndefined(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception))); 1781 ASSERT(!exception); 1782 1783 JSObjectSetPropertyAtIndex(context, o, 0, JSValueMakeNumber(context, 1), &exception); 1784 ASSERT(!exception); 1785 1786 exception = NULL; 1787 ASSERT(1 == JSValueToNumber(context, JSObjectGetPropertyAtIndex(context, o, 0, &exception), &exception)); 1788 ASSERT(!exception); 1789 1790 JSStringRef functionBody; 1791 JSObjectRef function; 1792 1793 exception = NULL; 1794 functionBody = JSStringCreateWithUTF8CString("rreturn Array;"); 1795 JSStringRef line = JSStringCreateWithUTF8CString("line"); 1796 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); 1797 ASSERT(JSValueIsObject(context, exception)); 1798 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); 1799 assertEqualsAsNumber(v, 2); 1800 JSStringRelease(functionBody); 1801 JSStringRelease(line); 1802 1803 exception = NULL; 1804 functionBody = JSStringCreateWithUTF8CString("rreturn Array;"); 1805 line = JSStringCreateWithUTF8CString("line"); 1806 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, -42, &exception)); 1807 ASSERT(JSValueIsObject(context, exception)); 1808 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); 1809 assertEqualsAsNumber(v, 2); 1810 JSStringRelease(functionBody); 1811 JSStringRelease(line); 1812 1813 exception = NULL; 1814 functionBody = JSStringCreateWithUTF8CString("// Line one.\nrreturn Array;"); 1815 line = JSStringCreateWithUTF8CString("line"); 1816 ASSERT(!JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception)); 1817 ASSERT(JSValueIsObject(context, exception)); 1818 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), line, NULL); 1819 assertEqualsAsNumber(v, 3); 1820 JSStringRelease(functionBody); 1821 JSStringRelease(line); 1822 1823 exception = NULL; 1824 functionBody = JSStringCreateWithUTF8CString("return Array;"); 1825 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, &exception); 1826 JSStringRelease(functionBody); 1827 ASSERT(!exception); 1828 ASSERT(JSObjectIsFunction(context, function)); 1829 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); 1830 ASSERT(v); 1831 ASSERT(JSValueIsEqual(context, v, arrayConstructor, NULL)); 1832 1833 exception = NULL; 1834 function = JSObjectMakeFunction(context, NULL, 0, NULL, jsEmptyIString, NULL, 0, &exception); 1835 ASSERT(!exception); 1836 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, &exception); 1837 ASSERT(v && !exception); 1838 ASSERT(JSValueIsUndefined(context, v)); 1839 1840 exception = NULL; 1841 v = NULL; 1842 JSStringRef foo = JSStringCreateWithUTF8CString("foo"); 1843 JSStringRef argumentNames[] = { foo }; 1844 functionBody = JSStringCreateWithUTF8CString("return foo;"); 1845 function = JSObjectMakeFunction(context, foo, 1, argumentNames, functionBody, NULL, 1, &exception); 1846 ASSERT(function && !exception); 1847 JSValueRef arguments[] = { JSValueMakeNumber(context, 2) }; 1848 JSObjectCallAsFunction(context, function, NULL, 1, arguments, &exception); 1849 JSStringRelease(foo); 1850 JSStringRelease(functionBody); 1851 1852 string = JSValueToStringCopy(context, function, NULL); 1853 assertEqualsAsUTF8String(JSValueMakeString(context, string), "function foo(foo) {\nreturn foo;\n}"); 1854 JSStringRelease(string); 1855 1856 JSStringRef print = JSStringCreateWithUTF8CString("print"); 1857 JSObjectRef printFunction = JSObjectMakeFunctionWithCallback(context, print, print_callAsFunction); 1858 JSObjectSetProperty(context, globalObject, print, printFunction, kJSPropertyAttributeNone, NULL); 1859 JSStringRelease(print); 1860 1861 ASSERT(!JSObjectSetPrivate(printFunction, (void*)1)); 1862 ASSERT(!JSObjectGetPrivate(printFunction)); 1863 1864 JSStringRef myConstructorIString = JSStringCreateWithUTF8CString("MyConstructor"); 1865 JSObjectRef myConstructor = JSObjectMakeConstructor(context, NULL, myConstructor_callAsConstructor); 1866 JSObjectSetProperty(context, globalObject, myConstructorIString, myConstructor, kJSPropertyAttributeNone, NULL); 1867 JSStringRelease(myConstructorIString); 1868 1869 JSStringRef myBadConstructorIString = JSStringCreateWithUTF8CString("MyBadConstructor"); 1870 JSObjectRef myBadConstructor = JSObjectMakeConstructor(context, NULL, myBadConstructor_callAsConstructor); 1871 JSObjectSetProperty(context, globalObject, myBadConstructorIString, myBadConstructor, kJSPropertyAttributeNone, NULL); 1872 JSStringRelease(myBadConstructorIString); 1873 1874 ASSERT(!JSObjectSetPrivate(myConstructor, (void*)1)); 1875 ASSERT(!JSObjectGetPrivate(myConstructor)); 1876 1877 string = JSStringCreateWithUTF8CString("Base"); 1878 JSObjectRef baseConstructor = JSObjectMakeConstructor(context, Base_class(context), NULL); 1879 JSObjectSetProperty(context, globalObject, string, baseConstructor, kJSPropertyAttributeNone, NULL); 1880 JSStringRelease(string); 1881 1882 string = JSStringCreateWithUTF8CString("Derived"); 1883 JSObjectRef derivedConstructor = JSObjectMakeConstructor(context, Derived_class(context), NULL); 1884 JSObjectSetProperty(context, globalObject, string, derivedConstructor, kJSPropertyAttributeNone, NULL); 1885 JSStringRelease(string); 1886 1887 string = JSStringCreateWithUTF8CString("Derived2"); 1888 JSObjectRef derived2Constructor = JSObjectMakeConstructor(context, Derived2_class(context), NULL); 1889 JSObjectSetProperty(context, globalObject, string, derived2Constructor, kJSPropertyAttributeNone, NULL); 1890 JSStringRelease(string); 1891 1892 JSValueRef argumentsArrayValues[] = { JSValueMakeNumber(context, 10), JSValueMakeNumber(context, 20) }; 1893 o = JSObjectMakeArray(context, sizeof(argumentsArrayValues) / sizeof(JSValueRef), argumentsArrayValues, NULL); 1894 string = JSStringCreateWithUTF8CString("length"); 1895 v = JSObjectGetProperty(context, o, string, NULL); 1896 assertEqualsAsNumber(v, 2); 1897 v = JSObjectGetPropertyAtIndex(context, o, 0, NULL); 1898 assertEqualsAsNumber(v, 10); 1899 v = JSObjectGetPropertyAtIndex(context, o, 1, NULL); 1900 assertEqualsAsNumber(v, 20); 1901 1902 o = JSObjectMakeArray(context, 0, NULL, NULL); 1903 v = JSObjectGetProperty(context, o, string, NULL); 1904 assertEqualsAsNumber(v, 0); 1905 JSStringRelease(string); 1906 1907 JSValueRef argumentsDateValues[] = { JSValueMakeNumber(context, 0) }; 1908 o = JSObjectMakeDate(context, 1, argumentsDateValues, NULL); 1909 if (timeZoneIsPST()) 1910 assertEqualsAsUTF8String(o, "Wed Dec 31 1969 16:00:00 GMT-0800 (PST)"); 1911 1912 string = JSStringCreateWithUTF8CString("an error message"); 1913 JSValueRef argumentsErrorValues[] = { JSValueMakeString(context, string) }; 1914 o = JSObjectMakeError(context, 1, argumentsErrorValues, NULL); 1915 assertEqualsAsUTF8String(o, "Error: an error message"); 1916 JSStringRelease(string); 1917 1918 string = JSStringCreateWithUTF8CString("foo"); 1919 JSStringRef string2 = JSStringCreateWithUTF8CString("gi"); 1920 JSValueRef argumentsRegExpValues[] = { JSValueMakeString(context, string), JSValueMakeString(context, string2) }; 1921 o = JSObjectMakeRegExp(context, 2, argumentsRegExpValues, NULL); 1922 assertEqualsAsUTF8String(o, "/foo/gi"); 1923 JSStringRelease(string); 1924 JSStringRelease(string2); 1925 1926 JSClassDefinition nullDefinition = kJSClassDefinitionEmpty; 1927 nullDefinition.attributes = kJSClassAttributeNoAutomaticPrototype; 1928 JSClassRef nullClass = JSClassCreate(&nullDefinition); 1929 JSClassRelease(nullClass); 1930 1931 nullDefinition = kJSClassDefinitionEmpty; 1932 nullClass = JSClassCreate(&nullDefinition); 1933 JSClassRelease(nullClass); 1934 1935 functionBody = JSStringCreateWithUTF8CString("return this;"); 1936 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL); 1937 JSStringRelease(functionBody); 1938 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); 1939 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1940 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL); 1941 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1942 1943 functionBody = JSStringCreateWithUTF8CString("return eval(\"this\");"); 1944 function = JSObjectMakeFunction(context, NULL, 0, NULL, functionBody, NULL, 1, NULL); 1945 JSStringRelease(functionBody); 1946 v = JSObjectCallAsFunction(context, function, NULL, 0, NULL, NULL); 1947 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1948 v = JSObjectCallAsFunction(context, function, o, 0, NULL, NULL); 1949 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1950 1951 const char* thisScript = "this;"; 1952 JSStringRef script = JSStringCreateWithUTF8CString(thisScript); 1953 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); 1954 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1955 v = JSEvaluateScript(context, script, o, NULL, 1, NULL); 1956 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1957 JSStringRelease(script); 1958 1959 JSScriptRef scriptObject = JSScriptCreateReferencingImmortalASCIIText(contextGroup, 0, 0, thisScript, strlen(thisScript), 0, 0); 1960 v = JSScriptEvaluate(context, scriptObject, NULL, NULL); 1961 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1962 v = JSScriptEvaluate(context, scriptObject, o, NULL); 1963 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1964 JSScriptRelease(scriptObject); 1965 1966 script = JSStringCreateWithUTF8CString("eval(this);"); 1967 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); 1968 ASSERT(JSValueIsEqual(context, v, globalObject, NULL)); 1969 v = JSEvaluateScript(context, script, o, NULL, 1, NULL); 1970 ASSERT(JSValueIsEqual(context, v, o, NULL)); 1971 JSStringRelease(script); 1972 1973 script = JSStringCreateWithUTF8CString("[ ]"); 1974 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); 1975 ASSERT(JSValueIsArray(context, v)); 1976 JSStringRelease(script); 1977 1978 script = JSStringCreateWithUTF8CString("new Date"); 1979 v = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); 1980 ASSERT(JSValueIsDate(context, v)); 1981 JSStringRelease(script); 1982 1983 exception = NULL; 1984 script = JSStringCreateWithUTF8CString("rreturn Array;"); 1985 JSStringRef sourceURL = JSStringCreateWithUTF8CString("file:///foo/bar.js"); 1986 JSStringRef sourceURLKey = JSStringCreateWithUTF8CString("sourceURL"); 1987 JSEvaluateScript(context, script, NULL, sourceURL, 1, &exception); 1988 ASSERT(exception); 1989 v = JSObjectGetProperty(context, JSValueToObject(context, exception, NULL), sourceURLKey, NULL); 1990 assertEqualsAsUTF8String(v, "file:///foo/bar.js"); 1991 JSStringRelease(script); 1992 JSStringRelease(sourceURL); 1993 JSStringRelease(sourceURLKey); 1994 1995 // Verify that creating a constructor for a class with no static functions does not trigger 1996 // an assert inside putDirect or lead to a crash during GC. <https://bugs.webkit.org/show_bug.cgi?id=25785> 1997 nullDefinition = kJSClassDefinitionEmpty; 1998 nullClass = JSClassCreate(&nullDefinition); 1999 JSObjectMakeConstructor(context, nullClass, 0); 2000 JSClassRelease(nullClass); 2001 2002 const char* scriptPath = "./testapiScripts/testapi.js"; 2003 char* scriptUTF8 = createStringWithContentsOfFile(scriptPath); 2004 if (!scriptUTF8) { 2005 printf("FAIL: Test script could not be loaded.\n"); 2006 failed = 1; 2007 } else { 2008 JSStringRef url = JSStringCreateWithUTF8CString(scriptPath); 2009 JSStringRef script = JSStringCreateWithUTF8CString(scriptUTF8); 2010 JSStringRef errorMessage = 0; 2011 int errorLine = 0; 2012 JSScriptRef scriptObject = JSScriptCreateFromString(contextGroup, url, 1, script, &errorMessage, &errorLine); 2013 ASSERT((!scriptObject) != (!errorMessage)); 2014 if (!scriptObject) { 2015 printf("FAIL: Test script did not parse\n\t%s:%d\n\t", scriptPath, errorLine); 2016 #if USE(CF) 2017 CFStringRef errorCF = JSStringCopyCFString(kCFAllocatorDefault, errorMessage); 2018 CFShow(errorCF); 2019 CFRelease(errorCF); 2020 #endif 2021 JSStringRelease(errorMessage); 2022 failed = 1; 2023 } 2024 2025 JSStringRelease(script); 2026 exception = NULL; 2027 result = scriptObject ? JSScriptEvaluate(context, scriptObject, 0, &exception) : 0; 2028 if (result && JSValueIsUndefined(context, result)) 2029 printf("PASS: Test script executed successfully.\n"); 2030 else { 2031 printf("FAIL: Test script returned unexpected value:\n"); 2032 JSStringRef exceptionIString = JSValueToStringCopy(context, exception, NULL); 2033 #if USE(CF) 2034 CFStringRef exceptionCF = JSStringCopyCFString(kCFAllocatorDefault, exceptionIString); 2035 CFShow(exceptionCF); 2036 CFRelease(exceptionCF); 2037 #endif 2038 JSStringRelease(exceptionIString); 2039 failed = 1; 2040 } 2041 JSScriptRelease(scriptObject); 2042 free(scriptUTF8); 2043 } 2044 2045 // Check Promise is not exposed. 2046 { 2047 JSObjectRef globalObject = JSContextGetGlobalObject(context); 2048 { 2049 JSStringRef promiseProperty = JSStringCreateWithUTF8CString("Promise"); 2050 ASSERT(JSObjectHasProperty(context, globalObject, promiseProperty)); 2051 JSStringRelease(promiseProperty); 2052 } 2053 { 2054 JSStringRef script = JSStringCreateWithUTF8CString("typeof Promise"); 2055 JSStringRef function = JSStringCreateWithUTF8CString("function"); 2056 JSValueRef value = JSEvaluateScript(context, script, NULL, NULL, 1, NULL); 2057 ASSERT(JSValueIsString(context, value)); 2058 JSStringRef valueAsString = JSValueToStringCopy(context, value, NULL); 2059 ASSERT(JSStringIsEqual(valueAsString, function)); 2060 JSStringRelease(valueAsString); 2061 JSStringRelease(function); 2062 JSStringRelease(script); 2063 } 2064 printf("PASS: Promise is exposed under JSContext API.\n"); 2065 } 2066 2067 // Check microtasks. 2068 { 2069 JSGlobalContextRef context = JSGlobalContextCreateInGroup(NULL, NULL); 2070 { 2071 JSObjectRef globalObject = JSContextGetGlobalObject(context); 2072 JSValueRef exception; 2073 JSStringRef code = JSStringCreateWithUTF8CString("result = 0; Promise.resolve(42).then(function (value) { result = value; });"); 2074 JSStringRef file = JSStringCreateWithUTF8CString(""); 2075 assertTrue((bool)JSEvaluateScript(context, code, globalObject, file, 1, &exception), "An exception should not be thrown"); 2076 JSStringRelease(code); 2077 JSStringRelease(file); 2078 2079 JSStringRef resultProperty = JSStringCreateWithUTF8CString("result"); 2080 ASSERT(JSObjectHasProperty(context, globalObject, resultProperty)); 2081 2082 JSValueRef resultValue = JSObjectGetProperty(context, globalObject, resultProperty, &exception); 2083 assertEqualsAsNumber(resultValue, 42); 2084 JSStringRelease(resultProperty); 2085 } 2086 JSGlobalContextRelease(context); 2087 } 2088 2089 // Check JSObjectGetGlobalContext 2090 { 2091 JSGlobalContextRef context = JSGlobalContextCreateInGroup(NULL, NULL); 2092 { 2093 JSObjectRef globalObject = JSContextGetGlobalObject(context); 2094 assertTrue(JSObjectGetGlobalContext(globalObject) == context, "global object context is correct"); 2095 JSObjectRef object = JSObjectMake(context, NULL, NULL); 2096 assertTrue(JSObjectGetGlobalContext(object) == context, "regular object context is correct"); 2097 JSStringRef returnFunctionSource = JSStringCreateWithUTF8CString("return this;"); 2098 JSObjectRef theFunction = JSObjectMakeFunction(context, NULL, 0, NULL, returnFunctionSource, NULL, 1, NULL); 2099 assertTrue(JSObjectGetGlobalContext(theFunction) == context, "function object context is correct"); 2100 assertTrue(JSObjectGetGlobalContext(NULL) == NULL, "NULL object context is NULL"); 2101 JSStringRelease(returnFunctionSource); 2102 } 2103 JSGlobalContextRelease(context); 2104 } 2105 failed |= testTypedArrayCAPI(); 2106 failed |= testFunctionOverrides(); 2107 failed |= testGlobalContextWithFinalizer(); 2108 failed |= testPingPongStackOverflow(); 2109 failed |= testJSONParse(); 2110 failed |= testJSObjectGetProxyTarget(); 2111 2112 // Clear out local variables pointing at JSObjectRefs to allow their values to be collected 2113 function = NULL; 2114 v = NULL; 2115 o = NULL; 2116 globalObject = NULL; 2117 myConstructor = NULL; 2118 2119 JSStringRelease(jsEmptyIString); 2120 JSStringRelease(jsOneIString); 2121 JSStringRelease(goodSyntax); 2122 JSStringRelease(badSyntax); 2123 2124 JSGlobalContextRelease(context); 2125 JSClassRelease(globalObjectClass); 2126 2127 // Test for an infinite prototype chain that used to be created. This test 2128 // passes if the call to JSObjectHasProperty() does not hang. 2129 2130 JSClassDefinition prototypeLoopClassDefinition = kJSClassDefinitionEmpty; 2131 prototypeLoopClassDefinition.staticFunctions = globalObject_staticFunctions; 2132 JSClassRef prototypeLoopClass = JSClassCreate(&prototypeLoopClassDefinition); 2133 JSGlobalContextRef prototypeLoopContext = JSGlobalContextCreateInGroup(NULL, prototypeLoopClass); 2134 2135 JSStringRef nameProperty = JSStringCreateWithUTF8CString("name"); 2136 JSObjectHasProperty(prototypeLoopContext, JSContextGetGlobalObject(prototypeLoopContext), nameProperty); 2137 2138 JSGlobalContextRelease(prototypeLoopContext); 2139 JSClassRelease(prototypeLoopClass); 2140 2141 printf("PASS: Infinite prototype chain does not occur.\n"); 2142 2143 if (checkForCycleInPrototypeChain()) 2144 printf("PASS: A cycle in a prototype chain can't be created.\n"); 2145 else { 2146 printf("FAIL: A cycle in a prototype chain can be created.\n"); 2147 failed = true; 2148 } 2149 if (valueToObjectExceptionTest()) 2150 printf("PASS: throwException did not crash when handling an error with appendMessageToError set and no codeBlock available.\n"); 2151 2152 if (globalContextNameTest()) 2153 printf("PASS: global context name behaves as expected.\n"); 2154 2155 customGlobalObjectClassTest(); 2156 globalObjectSetPrototypeTest(); 2157 globalObjectPrivatePropertyTest(); 2158 2159 failed = finalizeMultithreadedMultiVMExecutionTest() || failed; 2160 2161 // Don't run this till after the MultithreadedMultiVMExecutionTest has finished. 2162 // This is because testExecutionTimeLimit() modifies JIT options at runtime 2163 // as part of its testing. This can wreak havoc on the rest of the system that 2164 // expects the options to be frozen. Ideally, we'll find a way for testExecutionTimeLimit() 2165 // to do its work without changing JIT options, but that is not easy to do. 2166 // For now, we'll just run it here at the end as a workaround. 2167 failed |= testExecutionTimeLimit(); 2168 2169 if (failed) { 2170 printf("FAIL: Some tests failed.\n"); 2171 return 1; 2172 } 2173 2174 printf("PASS: Program exited normally.\n"); 2175 return 0; 2176 } 2177 2178 static char* createStringWithContentsOfFile(const char* fileName) 2179 { 2180 char* buffer; 2181 2182 size_t buffer_size = 0; 2183 size_t buffer_capacity = 1024; 2184 buffer = (char*)malloc(buffer_capacity); 2185 2186 FILE* f = fopen(fileName, "r"); 2187 if (!f) { 2188 fprintf(stderr, "Could not open file: %s\n", fileName); 2189 free(buffer); 2190 return 0; 2191 } 2192 2193 while (!feof(f) && !ferror(f)) { 2194 buffer_size += fread(buffer + buffer_size, 1, buffer_capacity - buffer_size, f); 2195 if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0' 2196 buffer_capacity *= 2; 2197 buffer = (char*)realloc(buffer, buffer_capacity); 2198 ASSERT(buffer); 2199 } 2200 2201 ASSERT(buffer_size < buffer_capacity); 2202 } 2203 fclose(f); 2204 buffer[buffer_size] = '\0'; 2205 2206 return buffer; 2207 } 2208 2209 #if OS(WINDOWS) 2210 __declspec(dllexport) int WINAPI dllLauncherEntryPoint(int argc, char* argv[]) 2211 { 2212 return main(argc, argv); 2213 } 2214 #endif