/ API / tests / testapi.c
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(&gtm, 0, sizeof(gtm));
 185      strftime(timeZoneName, sizeof(timeZoneName), "%Z", &gtm);
 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