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