2 * Copyright (C) 2013-2015 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
26 #import <JavaScriptCore/JavaScriptCore.h>
28 #import "CurrentThisInsideBlockGetterTest.h"
30 #import "JSExportTests.h"
31 #import "Regress141809.h"
35 extern "C" void JSSynchronousGarbageCollectForDebugging(JSContextRef);
36 extern "C" void JSSynchronousEdenCollectForDebugging(JSContextRef);
38 extern "C" bool _Block_has_signature(id);
39 extern "C" const char * _Block_signature(id);
42 extern "C" void testObjectiveCAPI(void);
43 extern "C" void checkResult(NSString *, bool);
45 #if JSC_OBJC_API_ENABLED
47 @interface UnexportedObject : NSObject
50 @implementation UnexportedObject
53 @protocol ParentObject <JSExport>
56 @interface ParentObject : NSObject<ParentObject>
57 + (NSString *)parentTest;
60 @implementation ParentObject
61 + (NSString *)parentTest
63 return [self description];
67 @protocol TestObject <JSExport>
69 @property int variable;
70 @property (readonly) int six;
71 @property CGPoint point;
72 + (NSString *)classTest;
73 + (NSString *)parentTest;
74 - (NSString *)getString;
75 JSExportAs(testArgumentTypes,
76 - (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o
78 - (void)callback:(JSValue *)function;
79 - (void)bogusCallback:(void(^)(int))function;
82 @interface TestObject : ParentObject <TestObject>
87 @implementation TestObject
93 return [[TestObject alloc] init];
95 + (NSString *)classTest
97 return @"classTest - okay";
99 - (NSString *)getString
103 - (NSString *)testArgumentTypesWithInt:(int)i double:(double)d boolean:(BOOL)b string:(NSString *)s number:(NSNumber *)n array:(NSArray *)a dictionary:(NSDictionary *)o
105 return [NSString stringWithFormat:@"%d,%g,%d,%@,%d,%@,%@", i, d, b==YES?true:false,s,[n intValue],a[1],o[@"x"]];
107 - (void)callback:(JSValue *)function
109 [function callWithArguments:[NSArray arrayWithObject:[NSNumber numberWithInt:42]]];
111 - (void)bogusCallback:(void(^)(int))function
117 bool testXYZTested = false;
119 @protocol TextXYZ <JSExport>
120 - (id)initWithString:(NSString*)string;
122 @property (readonly) int y;
123 @property (assign) JSValue *onclick;
124 @property (assign) JSValue *weakOnclick;
125 - (void)test:(NSString *)message;
128 @interface TextXYZ : NSObject <TextXYZ>
135 @implementation TextXYZ {
136 JSManagedValue *m_weakOnclickHandler;
137 JSManagedValue *m_onclickHandler;
142 - (id)initWithString:(NSString*)string
148 NSLog(@"%@", string);
152 - (void)test:(NSString *)message
154 testXYZTested = [message isEqual:@"test"] && x == 13 & y == 4 && z == 5;
156 - (void)setWeakOnclick:(JSValue *)value
158 m_weakOnclickHandler = [JSManagedValue managedValueWithValue:value];
161 - (void)setOnclick:(JSValue *)value
163 m_onclickHandler = [JSManagedValue managedValueWithValue:value];
164 [value.context.virtualMachine addManagedReference:m_onclickHandler withOwner:self];
166 - (JSValue *)weakOnclick
168 return [m_weakOnclickHandler value];
172 return [m_onclickHandler value];
176 if (!m_onclickHandler)
179 JSValue *function = [m_onclickHandler value];
180 [function callWithArguments:[NSArray array]];
186 @protocol TinyDOMNode <JSExport>
187 - (void)appendChild:(TinyDOMNode *)child;
188 - (NSUInteger)numberOfChildren;
189 - (TinyDOMNode *)childAtIndex:(NSUInteger)index;
190 - (void)removeChildAtIndex:(NSUInteger)index;
193 @interface TinyDOMNode : NSObject<TinyDOMNode>
196 @implementation TinyDOMNode {
197 NSMutableArray *m_children;
198 JSVirtualMachine *m_sharedVirtualMachine;
201 - (id)initWithVirtualMachine:(JSVirtualMachine *)virtualMachine
207 m_children = [[NSMutableArray alloc] initWithCapacity:0];
208 m_sharedVirtualMachine = virtualMachine;
209 #if !__has_feature(objc_arc)
210 [m_sharedVirtualMachine retain];
216 - (void)appendChild:(TinyDOMNode *)child
218 [m_sharedVirtualMachine addManagedReference:child withOwner:self];
219 [m_children addObject:child];
222 - (NSUInteger)numberOfChildren
224 return [m_children count];
227 - (TinyDOMNode *)childAtIndex:(NSUInteger)index
229 if (index >= [m_children count])
231 return [m_children objectAtIndex:index];
234 - (void)removeChildAtIndex:(NSUInteger)index
236 if (index >= [m_children count])
238 [m_sharedVirtualMachine removeManagedReference:[m_children objectAtIndex:index] withOwner:self];
239 [m_children removeObjectAtIndex:index];
244 @interface JSCollection : NSObject
245 - (void)setValue:(JSValue *)value forKey:(NSString *)key;
246 - (JSValue *)valueForKey:(NSString *)key;
249 @implementation JSCollection {
250 NSMutableDictionary *_dict;
258 _dict = [[NSMutableDictionary alloc] init];
263 - (void)setValue:(JSValue *)value forKey:(NSString *)key
265 JSManagedValue *oldManagedValue = [_dict objectForKey:key];
266 if (oldManagedValue) {
267 JSValue* oldValue = [oldManagedValue value];
269 [oldValue.context.virtualMachine removeManagedReference:oldManagedValue withOwner:self];
271 JSManagedValue *managedValue = [JSManagedValue managedValueWithValue:value];
272 [value.context.virtualMachine addManagedReference:managedValue withOwner:self];
273 [_dict setObject:managedValue forKey:key];
276 - (JSValue *)valueForKey:(NSString *)key
278 JSManagedValue *managedValue = [_dict objectForKey:key];
281 return [managedValue value];
285 @protocol InitA <JSExport>
286 - (id)initWithA:(int)a;
290 @protocol InitB <JSExport>
291 - (id)initWithA:(int)a b:(int)b;
294 @protocol InitC <JSExport>
298 @interface ClassA : NSObject<InitA>
301 @interface ClassB : ClassA<InitB>
304 @interface ClassC : ClassB<InitA, InitB>
307 @interface ClassCPrime : ClassB<InitA, InitC>
310 @interface ClassD : NSObject<InitA>
311 - (id)initWithA:(int)a;
314 @interface ClassE : ClassD
315 - (id)initWithA:(int)a;
318 @implementation ClassA {
321 - (id)initWithA:(int)a
337 @implementation ClassB {
340 - (id)initWithA:(int)a b:(int)b
342 self = [super initWithA:a];
352 @implementation ClassC {
355 - (id)initWithA:(int)a
357 return [self initWithA:a b:0];
359 - (id)initWithA:(int)a b:(int)b
361 self = [super initWithA:a b:b];
371 @implementation ClassCPrime
372 - (id)initWithA:(int)a
374 self = [super initWithA:a b:0];
381 return [self initWithA:42];
385 @implementation ClassD
387 - (id)initWithA:(int)a
390 return [[ClassE alloc] initWithA:a];
398 @implementation ClassE {
402 - (id)initWithA:(int)a
414 static bool evilAllocationObjectWasDealloced = false;
416 @interface EvilAllocationObject : NSObject
417 - (JSValue *)doEvilThingsWithContext:(JSContext *)context;
420 @implementation EvilAllocationObject {
421 JSContext *m_context;
423 - (id)initWithContext:(JSContext *)context
435 [self doEvilThingsWithContext:m_context];
436 evilAllocationObjectWasDealloced = true;
437 #if !__has_feature(objc_arc)
442 - (JSValue *)doEvilThingsWithContext:(JSContext *)context
444 JSValue *result = [context evaluateScript:@" \
448 for (var i = 0; i < 10000; ++i) { \
455 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
460 extern "C" void checkResult(NSString *description, bool passed)
462 NSLog(@"TEST: \"%@\": %@", description, passed ? @"PASSED" : @"FAILED");
467 static bool blockSignatureContainsClass()
469 static bool containsClass = ^{
470 id block = ^(NSString *string){ return string; };
471 return _Block_has_signature(block) && strstr(_Block_signature(block), "NSString");
473 return containsClass;
476 static void* threadMain(void* contextPtr)
478 JSContext *context = (__bridge JSContext*)contextPtr;
480 // Do something to enter the VM.
481 TestObject *testObject = [TestObject testObject];
482 context[@"testObject"] = testObject;
483 pthread_exit(nullptr);
486 void testObjectiveCAPI()
488 NSLog(@"Testing Objective-C API");
491 JSVirtualMachine* vm = [[JSVirtualMachine alloc] init];
492 JSContext* context = [[JSContext alloc] initWithVirtualMachine:vm];
493 [context evaluateScript:@"bad"];
497 JSContext *context = [[JSContext alloc] init];
498 JSValue *result = [context evaluateScript:@"2 + 2"];
499 checkResult(@"2 + 2", [result isNumber] && [result toInt32] == 4);
503 JSContext *context = [[JSContext alloc] init];
504 NSString *result = [NSString stringWithFormat:@"Two plus two is %@", [context evaluateScript:@"2 + 2"]];
505 checkResult(@"stringWithFormat", [result isEqual:@"Two plus two is 4"]);
509 JSContext *context = [[JSContext alloc] init];
510 context[@"message"] = @"Hello";
511 JSValue *result = [context evaluateScript:@"message + ', World!'"];
512 checkResult(@"Hello, World!", [result isString] && [result isEqualToObject:@"Hello, World!"]);
516 JSContext *context = [[JSContext alloc] init];
517 JSValue *result = [context evaluateScript:@"({ x:42 })"];
518 checkResult(@"({ x:42 })", [result isObject] && [result[@"x"] isEqualToObject:@42]);
519 id obj = [result toObject];
520 checkResult(@"Check dictionary literal", [obj isKindOfClass:[NSDictionary class]]);
521 id num = (NSDictionary *)obj[@"x"];
522 checkResult(@"Check numeric literal", [num isKindOfClass:[NSNumber class]]);
526 JSCollection* myPrivateProperties = [[JSCollection alloc] init];
529 JSContext* context = [[JSContext alloc] init];
530 TestObject* rootObject = [TestObject testObject];
531 context[@"root"] = rootObject;
532 [context.virtualMachine addManagedReference:myPrivateProperties withOwner:rootObject];
533 [myPrivateProperties setValue:[JSValue valueWithBool:true inContext:context] forKey:@"is_ham"];
534 [myPrivateProperties setValue:[JSValue valueWithObject:@"hello!" inContext:context] forKey:@"message"];
535 [myPrivateProperties setValue:[JSValue valueWithInt32:42 inContext:context] forKey:@"my_number"];
536 [myPrivateProperties setValue:[JSValue valueWithNullInContext:context] forKey:@"definitely_null"];
537 [myPrivateProperties setValue:[JSValue valueWithUndefinedInContext:context] forKey:@"not_sure_if_undefined"];
539 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
541 JSValue *isHam = [myPrivateProperties valueForKey:@"is_ham"];
542 JSValue *message = [myPrivateProperties valueForKey:@"message"];
543 JSValue *myNumber = [myPrivateProperties valueForKey:@"my_number"];
544 JSValue *definitelyNull = [myPrivateProperties valueForKey:@"definitely_null"];
545 JSValue *notSureIfUndefined = [myPrivateProperties valueForKey:@"not_sure_if_undefined"];
546 checkResult(@"is_ham is true", [isHam isBoolean] && [isHam toBool]);
547 checkResult(@"message is hello!", [message isString] && [@"hello!" isEqualToString:[message toString]]);
548 checkResult(@"my_number is 42", [myNumber isNumber] && [myNumber toInt32] == 42);
549 checkResult(@"definitely_null is null", [definitelyNull isNull]);
550 checkResult(@"not_sure_if_undefined is undefined", [notSureIfUndefined isUndefined]);
553 checkResult(@"is_ham is nil", ![myPrivateProperties valueForKey:@"is_ham"]);
554 checkResult(@"message is nil", ![myPrivateProperties valueForKey:@"message"]);
555 checkResult(@"my_number is 42", ![myPrivateProperties valueForKey:@"my_number"]);
556 checkResult(@"definitely_null is null", ![myPrivateProperties valueForKey:@"definitely_null"]);
557 checkResult(@"not_sure_if_undefined is undefined", ![myPrivateProperties valueForKey:@"not_sure_if_undefined"]);
561 JSContext *context = [[JSContext alloc] init];
562 JSValue *message = [JSValue valueWithObject:@"hello" inContext:context];
563 TestObject *rootObject = [TestObject testObject];
564 JSCollection *collection = [[JSCollection alloc] init];
565 context[@"root"] = rootObject;
567 JSValue *jsCollection = [JSValue valueWithObject:collection inContext:context];
568 JSManagedValue *weakCollection = [JSManagedValue managedValueWithValue:jsCollection andOwner:rootObject];
569 [context.virtualMachine addManagedReference:weakCollection withOwner:message];
570 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
575 JSContext *context = [[JSContext alloc] init];
577 context[@"blockCallback"] = ^(int value){
580 [context evaluateScript:@"blockCallback(42)"];
581 checkResult(@"blockCallback", result == 42);
584 if (blockSignatureContainsClass()) {
586 JSContext *context = [[JSContext alloc] init];
587 __block bool result = false;
588 context[@"blockCallback"] = ^(NSString *value){
589 result = [@"42" isEqualToString:value] == YES;
591 [context evaluateScript:@"blockCallback(42)"];
592 checkResult(@"blockCallback(NSString *)", result);
595 NSLog(@"Skipping 'blockCallback(NSString *)' test case");
598 JSContext *context = [[JSContext alloc] init];
599 checkResult(@"!context.exception", !context.exception);
600 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
601 checkResult(@"context.exception", context.exception);
605 JSContext *context = [[JSContext alloc] init];
606 __block bool caught = false;
607 context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
612 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
613 checkResult(@"JSContext.exceptionHandler", caught);
617 JSContext *context = [[JSContext alloc] init];
618 __block int expectedExceptionLineNumber = 1;
619 __block bool sawExpectedExceptionLineNumber = false;
620 context.exceptionHandler = ^(JSContext *, JSValue *exception) {
621 sawExpectedExceptionLineNumber = [exception[@"line"] toInt32] == expectedExceptionLineNumber;
623 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
624 checkResult(@"evaluteScript exception on line 1", sawExpectedExceptionLineNumber);
626 expectedExceptionLineNumber = 2;
627 sawExpectedExceptionLineNumber = false;
628 [context evaluateScript:@"// Line 1\n!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
629 checkResult(@"evaluteScript exception on line 2", sawExpectedExceptionLineNumber);
633 JSContext *context = [[JSContext alloc] init];
634 __block bool emptyExceptionSourceURL = false;
635 context.exceptionHandler = ^(JSContext *, JSValue *exception) {
636 emptyExceptionSourceURL = [exception[@"sourceURL"] isUndefined];
638 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
639 checkResult(@"evaluteScript: exception has no sourceURL", emptyExceptionSourceURL);
641 __block NSString *exceptionSourceURL = nil;
642 context.exceptionHandler = ^(JSContext *, JSValue *exception) {
643 exceptionSourceURL = [exception[@"sourceURL"] toString];
645 NSURL *url = [NSURL fileURLWithPath:@"/foo/bar.js"];
646 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()" withSourceURL:url];
647 checkResult(@"evaluateScript:withSourceURL: exception has expected sourceURL", [exceptionSourceURL isEqualToString:[url absoluteString]]);
651 JSContext *context = [[JSContext alloc] init];
652 context[@"callback"] = ^{
653 JSContext *context = [JSContext currentContext];
654 context.exception = [JSValue valueWithNewErrorFromMessage:@"Something went wrong." inContext:context];
656 JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"];
657 checkResult(@"Explicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]);
658 checkResult(@"Explicit throw in callback - not thrown to Objective-C", !context.exception);
662 JSContext *context = [[JSContext alloc] init];
663 context[@"callback"] = ^{
664 JSContext *context = [JSContext currentContext];
665 [context evaluateScript:@"!@#$%^&*() THIS IS NOT VALID JAVASCRIPT SYNTAX !@#$%^&*()"];
667 JSValue *result = [context evaluateScript:@"var result; try { callback(); } catch (e) { result = 'Caught exception'; }"];
668 checkResult(@"Implicit throw in callback - was caught by JavaScript", [result isEqualToObject:@"Caught exception"]);
669 checkResult(@"Implicit throw in callback - not thrown to Objective-C", !context.exception);
673 JSContext *context = [[JSContext alloc] init];
674 [context evaluateScript:
675 @"function sum(array) { \
677 for (var i in array) \
678 result += array[i]; \
681 JSValue *array = [JSValue valueWithObject:@[@13, @2, @7] inContext:context];
682 JSValue *sumFunction = context[@"sum"];
683 JSValue *result = [sumFunction callWithArguments:@[ array ]];
684 checkResult(@"sum([13, 2, 7])", [result toInt32] == 22);
688 JSContext *context = [[JSContext alloc] init];
689 JSValue *mulAddFunction = [context evaluateScript:
690 @"(function(array, object) { \
692 for (var i in array) \
693 result.push(array[i] * object.x + object.y); \
696 JSValue *result = [mulAddFunction callWithArguments:@[ @[ @2, @4, @8 ], @{ @"x":@0.5, @"y":@42 } ]];
697 checkResult(@"mulAddFunction", [result isObject] && [[result toString] isEqual:@"43,44,46"]);
701 JSContext *context = [[JSContext alloc] init];
702 JSValue *array = [JSValue valueWithNewArrayInContext:context];
703 checkResult(@"arrayLengthEmpty", [[array[@"length"] toNumber] unsignedIntegerValue] == 0);
704 JSValue *value1 = [JSValue valueWithInt32:42 inContext:context];
705 JSValue *value2 = [JSValue valueWithInt32:24 inContext:context];
706 NSUInteger lowIndex = 5;
707 NSUInteger maxLength = UINT_MAX;
709 [array setValue:value1 atIndex:lowIndex];
710 checkResult(@"array.length after put to low index", [[array[@"length"] toNumber] unsignedIntegerValue] == (lowIndex + 1));
712 [array setValue:value1 atIndex:(maxLength - 1)];
713 checkResult(@"array.length after put to maxLength - 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength);
715 [array setValue:value2 atIndex:maxLength];
716 checkResult(@"array.length after put to maxLength", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength);
718 [array setValue:value2 atIndex:(maxLength + 1)];
719 checkResult(@"array.length after put to maxLength + 1", [[array[@"length"] toNumber] unsignedIntegerValue] == maxLength);
721 if (sizeof(NSUInteger) == 8)
722 checkResult(@"valueAtIndex:0 is undefined", [[array valueAtIndex:0] isUndefined]);
724 checkResult(@"valueAtIndex:0", [[array valueAtIndex:0] toInt32] == 24);
725 checkResult(@"valueAtIndex:lowIndex", [[array valueAtIndex:lowIndex] toInt32] == 42);
726 checkResult(@"valueAtIndex:maxLength - 1", [[array valueAtIndex:(maxLength - 1)] toInt32] == 42);
727 checkResult(@"valueAtIndex:maxLength", [[array valueAtIndex:maxLength] toInt32] == 24);
728 checkResult(@"valueAtIndex:maxLength + 1", [[array valueAtIndex:(maxLength + 1)] toInt32] == 24);
732 JSContext *context = [[JSContext alloc] init];
733 JSValue *object = [JSValue valueWithNewObjectInContext:context];
735 object[@"point"] = @{ @"x":@1, @"y":@2 };
736 object[@"point"][@"x"] = @3;
737 CGPoint point = [object[@"point"] toPoint];
738 checkResult(@"toPoint", point.x == 3 && point.y == 2);
740 object[@{ @"toString":^{ return @"foo"; } }] = @"bar";
741 checkResult(@"toString in object literal used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]);
743 object[[@"foobar" substringToIndex:3]] = @"bar";
744 checkResult(@"substring used as subscript", [[object[@"foo"] toString] isEqual:@"bar"]);
748 JSContext *context = [[JSContext alloc] init];
749 TextXYZ *testXYZ = [[TextXYZ alloc] init];
750 context[@"testXYZ"] = testXYZ;
754 [context evaluateScript:@"testXYZ.x = 13; testXYZ.y = 14;"];
755 [context evaluateScript:@"testXYZ.test('test')"];
756 checkResult(@"TextXYZ - testXYZTested", testXYZTested);
757 JSValue *result = [context evaluateScript:@"testXYZ.x + ',' + testXYZ.y + ',' + testXYZ.z"];
758 checkResult(@"TextXYZ - result", [result isEqualToObject:@"13,4,undefined"]);
762 JSContext *context = [[JSContext alloc] init];
763 [context[@"Object"][@"prototype"] defineProperty:@"getterProperty" descriptor:@{
764 JSPropertyDescriptorGetKey:^{
765 return [JSContext currentThis][@"x"];
768 JSValue *object = [JSValue valueWithObject:@{ @"x":@101 } inContext:context];
769 int result = [object [@"getterProperty"] toInt32];
770 checkResult(@"getterProperty", result == 101);
774 JSContext *context = [[JSContext alloc] init];
775 context[@"concatenate"] = ^{
776 NSArray *arguments = [JSContext currentArguments];
777 if (![arguments count])
779 NSString *message = [arguments[0] description];
780 for (NSUInteger index = 1; index < [arguments count]; ++index)
781 message = [NSString stringWithFormat:@"%@ %@", message, arguments[index]];
784 JSValue *result = [context evaluateScript:@"concatenate('Hello,', 'World!')"];
785 checkResult(@"concatenate", [result isEqualToObject:@"Hello, World!"]);
789 JSContext *context = [[JSContext alloc] init];
790 context[@"foo"] = @YES;
791 checkResult(@"@YES is boolean", [context[@"foo"] isBoolean]);
792 JSValue *result = [context evaluateScript:@"typeof foo"];
793 checkResult(@"@YES is boolean", [result isEqualToObject:@"boolean"]);
797 JSContext *context = [[JSContext alloc] init];
798 JSValue *result = [context evaluateScript:@"String(console)"];
799 checkResult(@"String(console)", [result isEqualToObject:@"[object Console]"]);
800 result = [context evaluateScript:@"typeof console.log"];
801 checkResult(@"typeof console.log", [result isEqualToObject:@"function"]);
805 JSContext *context = [[JSContext alloc] init];
806 TestObject* testObject = [TestObject testObject];
807 context[@"testObject"] = testObject;
808 JSValue *result = [context evaluateScript:@"String(testObject)"];
809 checkResult(@"String(testObject)", [result isEqualToObject:@"[object TestObject]"]);
813 JSContext *context = [[JSContext alloc] init];
814 TestObject* testObject = [TestObject testObject];
815 context[@"testObject"] = testObject;
816 JSValue *result = [context evaluateScript:@"String(testObject.__proto__)"];
817 checkResult(@"String(testObject.__proto__)", [result isEqualToObject:@"[object TestObjectPrototype]"]);
821 JSContext *context = [[JSContext alloc] init];
822 context[@"TestObject"] = [TestObject class];
823 JSValue *result = [context evaluateScript:@"String(TestObject)"];
824 checkResult(@"String(TestObject)", [result isEqualToObject:@"function TestObject() {\n [native code]\n}"]);
828 JSContext *context = [[JSContext alloc] init];
829 JSValue* value = [JSValue valueWithObject:[TestObject class] inContext:context];
830 checkResult(@"[value toObject] == [TestObject class]", [value toObject] == [TestObject class]);
834 JSContext *context = [[JSContext alloc] init];
835 context[@"TestObject"] = [TestObject class];
836 JSValue *result = [context evaluateScript:@"TestObject.parentTest()"];
837 checkResult(@"TestObject.parentTest()", [result isEqualToObject:@"TestObject"]);
841 JSContext *context = [[JSContext alloc] init];
842 TestObject* testObject = [TestObject testObject];
843 context[@"testObjectA"] = testObject;
844 context[@"testObjectB"] = testObject;
845 JSValue *result = [context evaluateScript:@"testObjectA == testObjectB"];
846 checkResult(@"testObjectA == testObjectB", [result isBoolean] && [result toBool]);
850 JSContext *context = [[JSContext alloc] init];
851 TestObject* testObject = [TestObject testObject];
852 context[@"testObject"] = testObject;
853 testObject.point = (CGPoint){3,4};
854 JSValue *result = [context evaluateScript:@"var result = JSON.stringify(testObject.point); testObject.point = {x:12,y:14}; result"];
855 checkResult(@"testObject.point - result", [result isEqualToObject:@"{\"x\":3,\"y\":4}"]);
856 checkResult(@"testObject.point - {x:12,y:14}", testObject.point.x == 12 && testObject.point.y == 14);
860 JSContext *context = [[JSContext alloc] init];
861 TestObject* testObject = [TestObject testObject];
863 context[@"testObject"] = testObject;
864 context[@"mul"] = ^(int x, int y){ return x * y; };
865 JSValue *result = [context evaluateScript:@"mul(testObject.six, 7)"];
866 checkResult(@"mul(testObject.six, 7)", [result isNumber] && [result toInt32] == 42);
870 JSContext *context = [[JSContext alloc] init];
871 TestObject* testObject = [TestObject testObject];
872 context[@"testObject"] = testObject;
873 context[@"testObject"][@"variable"] = @4;
874 [context evaluateScript:@"++testObject.variable"];
875 checkResult(@"++testObject.variable", testObject.variable == 5);
879 JSContext *context = [[JSContext alloc] init];
880 context[@"point"] = @{ @"x":@6, @"y":@7 };
881 JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"];
882 checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]);
886 JSContext *context = [[JSContext alloc] init];
887 context[@"point"] = @{ @"x":@6, @"y":@7 };
888 JSValue *result = [context evaluateScript:@"point.x + ',' + point.y"];
889 checkResult(@"point.x + ',' + point.y", [result isEqualToObject:@"6,7"]);
893 JSContext *context = [[JSContext alloc] init];
894 TestObject* testObject = [TestObject testObject];
895 context[@"testObject"] = testObject;
896 JSValue *result = [context evaluateScript:@"testObject.getString()"];
897 checkResult(@"testObject.getString()", [result isString] && [result toInt32] == 42);
901 JSContext *context = [[JSContext alloc] init];
902 TestObject* testObject = [TestObject testObject];
903 context[@"testObject"] = testObject;
904 JSValue *result = [context evaluateScript:@"testObject.testArgumentTypes(101,0.5,true,'foo',666,[false,'bar',false],{x:'baz'})"];
905 checkResult(@"testObject.testArgumentTypes", [result isEqualToObject:@"101,0.5,1,foo,666,bar,baz"]);
909 JSContext *context = [[JSContext alloc] init];
910 TestObject* testObject = [TestObject testObject];
911 context[@"testObject"] = testObject;
912 JSValue *result = [context evaluateScript:@"testObject.getString.call(testObject)"];
913 checkResult(@"testObject.getString.call(testObject)", [result isString] && [result toInt32] == 42);
917 JSContext *context = [[JSContext alloc] init];
918 TestObject* testObject = [TestObject testObject];
919 context[@"testObject"] = testObject;
920 checkResult(@"testObject.getString.call({}) pre", !context.exception);
921 [context evaluateScript:@"testObject.getString.call({})"];
922 checkResult(@"testObject.getString.call({}) post", context.exception);
926 JSContext *context = [[JSContext alloc] init];
927 TestObject* testObject = [TestObject testObject];
928 context[@"testObject"] = testObject;
929 JSValue *result = [context evaluateScript:@"var result = 0; testObject.callback(function(x){ result = x; }); result"];
930 checkResult(@"testObject.callback", [result isNumber] && [result toInt32] == 42);
931 result = [context evaluateScript:@"testObject.bogusCallback"];
932 checkResult(@"testObject.bogusCallback == undefined", [result isUndefined]);
936 JSContext *context = [[JSContext alloc] init];
937 TestObject *testObject = [TestObject testObject];
938 context[@"testObject"] = testObject;
939 JSValue *result = [context evaluateScript:@"Function.prototype.toString.call(testObject.callback)"];
940 checkResult(@"Function.prototype.toString", !context.exception && ![result isUndefined]);
944 JSContext *context1 = [[JSContext alloc] init];
945 JSContext *context2 = [[JSContext alloc] initWithVirtualMachine:context1.virtualMachine];
946 JSValue *value = [JSValue valueWithDouble:42 inContext:context2];
947 context1[@"passValueBetweenContexts"] = value;
948 JSValue *result = [context1 evaluateScript:@"passValueBetweenContexts"];
949 checkResult(@"[value isEqualToObject:result]", [value isEqualToObject:result]);
953 JSContext *context = [[JSContext alloc] init];
954 context[@"handleTheDictionary"] = ^(NSDictionary *dict) {
955 NSDictionary *expectedDict = @{
956 @"foo" : [NSNumber numberWithInt:1],
958 @"baz": [NSNumber numberWithInt:2]
961 checkResult(@"recursively convert nested dictionaries", [dict isEqualToDictionary:expectedDict]);
963 [context evaluateScript:@"var myDict = { \
967 handleTheDictionary(myDict);"];
969 context[@"handleTheArray"] = ^(NSArray *array) {
970 NSArray *expectedArray = @[@"foo", @"bar", @[@"baz"]];
971 checkResult(@"recursively convert nested arrays", [array isEqualToArray:expectedArray]);
973 [context evaluateScript:@"var myArray = ['foo', 'bar', ['baz']]; handleTheArray(myArray);"];
977 JSContext *context = [[JSContext alloc] init];
978 TestObject *testObject = [TestObject testObject];
980 context[@"testObject"] = testObject;
981 [context evaluateScript:@"var constructor = Object.getPrototypeOf(testObject).constructor; constructor.prototype = undefined;"];
982 [context evaluateScript:@"testObject = undefined"];
985 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
988 context[@"testObject"] = testObject;
993 JSContext *context = [[JSContext alloc] init];
994 TextXYZ *testXYZ = [[TextXYZ alloc] init];
997 context[@"testXYZ"] = testXYZ;
999 [context evaluateScript:@" \
1001 testXYZ.onclick = function() { \
1005 testXYZ.weakOnclick = function() { \
1013 JSValue *result = [context evaluateScript:@"didClick"];
1014 checkResult(@"Event handler onclick", [result toBool]);
1017 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1020 JSValue *result = [context evaluateScript:@"testXYZ.onclick"];
1021 checkResult(@"onclick still around after GC", !([result isNull] || [result isUndefined]));
1026 JSValue *result = [context evaluateScript:@"testXYZ.weakOnclick"];
1027 checkResult(@"weakOnclick not around after GC", [result isNull] || [result isUndefined]);
1031 [context evaluateScript:@" \
1037 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1041 JSValue *result = [context evaluateScript:@"didClick"];
1042 checkResult(@"Event handler onclick doesn't fire", ![result toBool]);
1047 JSVirtualMachine *vm = [[JSVirtualMachine alloc] init];
1048 TestObject *testObject = [TestObject testObject];
1049 JSManagedValue *weakValue;
1051 JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
1052 context[@"testObject"] = testObject;
1053 weakValue = [[JSManagedValue alloc] initWithValue:context[@"testObject"]];
1057 JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
1058 context[@"testObject"] = testObject;
1059 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1060 checkResult(@"weak value == nil", ![weakValue value]);
1061 checkResult(@"root is still alive", ![context[@"testObject"] isUndefined]);
1066 JSContext *context = [[JSContext alloc] init];
1067 TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1068 TinyDOMNode *lastNode = root;
1069 for (NSUInteger i = 0; i < 3; i++) {
1070 TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1071 [lastNode appendChild:newNode];
1076 context[@"root"] = root;
1077 context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){
1078 TinyDOMNode *lastNode = nil;
1081 head = [lastNode childAtIndex:0];
1085 [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"];
1088 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1090 JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
1091 checkResult(@"My custom property == 42", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
1095 JSContext *context = [[JSContext alloc] init];
1096 TinyDOMNode *root = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1097 TinyDOMNode *lastNode = root;
1098 for (NSUInteger i = 0; i < 3; i++) {
1099 TinyDOMNode *newNode = [[TinyDOMNode alloc] initWithVirtualMachine:context.virtualMachine];
1100 [lastNode appendChild:newNode];
1105 context[@"root"] = root;
1106 context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){
1107 TinyDOMNode *lastNode = nil;
1110 head = [lastNode childAtIndex:0];
1114 [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"];
1116 [root appendChild:[root childAtIndex:0]];
1117 [root removeChildAtIndex:0];
1120 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1122 JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
1123 checkResult(@"duplicate calls to addManagedReference don't cause things to die", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
1127 JSContext *context = [[JSContext alloc] init];
1128 JSValue *o = [JSValue valueWithNewObjectInContext:context];
1130 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1132 checkResult(@"JSValue correctly protected its internal value", [[o[@"foo"] toString] isEqualToString:@"foo"]);
1136 JSContext *context = [[JSContext alloc] init];
1137 TestObject *testObject = [TestObject testObject];
1138 context[@"testObject"] = testObject;
1139 [context evaluateScript:@"testObject.__lookupGetter__('variable').call({})"];
1140 checkResult(@"Make sure we throw an exception when calling getter on incorrect |this|", context.exception);
1144 TestObject *testObject = [TestObject testObject];
1145 JSManagedValue *managedTestObject;
1147 JSContext *context = [[JSContext alloc] init];
1148 context[@"testObject"] = testObject;
1149 managedTestObject = [JSManagedValue managedValueWithValue:context[@"testObject"]];
1150 [context.virtualMachine addManagedReference:managedTestObject withOwner:testObject];
1155 JSContext *context = [[JSContext alloc] init];
1156 TestObject *testObject = [TestObject testObject];
1157 context[@"testObject"] = testObject;
1158 JSManagedValue *managedValue = nil;
1160 JSValue *object = [JSValue valueWithNewObjectInContext:context];
1161 managedValue = [JSManagedValue managedValueWithValue:object andOwner:testObject];
1162 [context.virtualMachine addManagedReference:managedValue withOwner:testObject];
1164 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1168 JSContext *context = [[JSContext alloc] init];
1169 context[@"MyClass"] = ^{
1170 JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
1171 JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef];
1172 JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL);
1173 JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentContext][@"MyClass"][@"prototype"] JSValueRef]);
1177 context[@"MyOtherClass"] = ^{
1178 JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
1179 JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef];
1180 JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL);
1181 JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentContext][@"MyOtherClass"][@"prototype"] JSValueRef]);
1185 context.exceptionHandler = ^(JSContext *context, JSValue *exception) {
1186 NSLog(@"EXCEPTION: %@", [exception toString]);
1187 context.exception = nil;
1190 JSValue *constructor1 = context[@"MyClass"];
1191 JSValue *constructor2 = context[@"MyOtherClass"];
1193 JSValue *value1 = [context evaluateScript:@"new MyClass()"];
1194 checkResult(@"value1 instanceof MyClass", [value1 isInstanceOf:constructor1]);
1195 checkResult(@"!(value1 instanceof MyOtherClass)", ![value1 isInstanceOf:constructor2]);
1196 checkResult(@"MyClass.prototype.constructor === MyClass", [[context evaluateScript:@"MyClass.prototype.constructor === MyClass"] toBool]);
1197 checkResult(@"MyClass instanceof Function", [[context evaluateScript:@"MyClass instanceof Function"] toBool]);
1199 JSValue *value2 = [context evaluateScript:@"new MyOtherClass()"];
1200 checkResult(@"value2 instanceof MyOtherClass", [value2 isInstanceOf:constructor2]);
1201 checkResult(@"!(value2 instanceof MyClass)", ![value2 isInstanceOf:constructor1]);
1202 checkResult(@"MyOtherClass.prototype.constructor === MyOtherClass", [[context evaluateScript:@"MyOtherClass.prototype.constructor === MyOtherClass"] toBool]);
1203 checkResult(@"MyOtherClass instanceof Function", [[context evaluateScript:@"MyOtherClass instanceof Function"] toBool]);
1207 JSContext *context = [[JSContext alloc] init];
1208 context[@"MyClass"] = ^{
1209 NSLog(@"I'm intentionally not returning anything.");
1211 JSValue *result = [context evaluateScript:@"new MyClass()"];
1212 checkResult(@"result === undefined", [result isUndefined]);
1213 checkResult(@"exception.message is correct'", context.exception
1214 && [@"Objective-C blocks called as constructors must return an object." isEqualToString:[context.exception[@"message"] toString]]);
1218 checkResult(@"[JSContext currentThis] == nil outside of callback", ![JSContext currentThis]);
1219 checkResult(@"[JSContext currentArguments] == nil outside of callback", ![JSContext currentArguments]);
1220 if ([JSContext currentCallee])
1221 checkResult(@"[JSContext currentCallee] == nil outside of callback", ![JSContext currentCallee]);
1224 if ([JSContext currentCallee]) {
1226 JSContext *context = [[JSContext alloc] init];
1227 context[@"testFunction"] = ^{
1228 checkResult(@"testFunction.foo === 42", [[JSContext currentCallee][@"foo"] toInt32] == 42);
1230 context[@"testFunction"][@"foo"] = @42;
1231 [context[@"testFunction"] callWithArguments:nil];
1233 context[@"TestConstructor"] = ^{
1234 JSValue *newThis = [JSValue valueWithNewObjectInContext:[JSContext currentContext]];
1235 JSGlobalContextRef contextRef = [[JSContext currentContext] JSGlobalContextRef];
1236 JSObjectRef newThisRef = JSValueToObject(contextRef, [newThis JSValueRef], NULL);
1237 JSObjectSetPrototype(contextRef, newThisRef, [[JSContext currentCallee][@"prototype"] JSValueRef]);
1240 checkResult(@"(new TestConstructor) instanceof TestConstructor", [context evaluateScript:@"(new TestConstructor) instanceof TestConstructor"]);
1245 JSContext *context = [[JSContext alloc] init];
1246 context[@"TestObject"] = [TestObject class];
1247 JSValue *testObject = [context evaluateScript:@"(new TestObject())"];
1248 checkResult(@"testObject instanceof TestObject", [testObject isInstanceOf:context[@"TestObject"]]);
1250 context[@"TextXYZ"] = [TextXYZ class];
1251 JSValue *textObject = [context evaluateScript:@"(new TextXYZ(\"Called TextXYZ constructor!\"))"];
1252 checkResult(@"textObject instanceof TextXYZ", [textObject isInstanceOf:context[@"TextXYZ"]]);
1256 JSContext *context = [[JSContext alloc] init];
1257 context[@"ClassA"] = [ClassA class];
1258 context[@"ClassB"] = [ClassB class];
1259 context[@"ClassC"] = [ClassC class]; // Should print error message about too many inits found.
1260 context[@"ClassCPrime"] = [ClassCPrime class]; // Ditto.
1262 JSValue *a = [context evaluateScript:@"(new ClassA(42))"];
1263 checkResult(@"a instanceof ClassA", [a isInstanceOf:context[@"ClassA"]]);
1264 checkResult(@"a.initialize() is callable", [[a invokeMethod:@"initialize" withArguments:@[]] toInt32] == 42);
1266 JSValue *b = [context evaluateScript:@"(new ClassB(42, 53))"];
1267 checkResult(@"b instanceof ClassB", [b isInstanceOf:context[@"ClassB"]]);
1269 JSValue *canConstructClassC = [context evaluateScript:@"(function() { \
1271 (new ClassC(1, 2)); \
1277 checkResult(@"shouldn't be able to construct ClassC", ![canConstructClassC toBool]);
1278 JSValue *canConstructClassCPrime = [context evaluateScript:@"(function() { \
1280 (new ClassCPrime(1)); \
1286 checkResult(@"shouldn't be able to construct ClassCPrime", ![canConstructClassCPrime toBool]);
1290 JSContext *context = [[JSContext alloc] init];
1291 context[@"ClassD"] = [ClassD class];
1292 context[@"ClassE"] = [ClassE class];
1294 JSValue *d = [context evaluateScript:@"(new ClassD())"];
1295 checkResult(@"Returning instance of ClassE from ClassD's init has correct class", [d isInstanceOf:context[@"ClassE"]]);
1299 JSContext *context = [[JSContext alloc] init];
1300 while (!evilAllocationObjectWasDealloced) {
1302 EvilAllocationObject *evilObject = [[EvilAllocationObject alloc] initWithContext:context];
1303 context[@"evilObject"] = evilObject;
1304 context[@"evilObject"] = nil;
1307 checkResult(@"EvilAllocationObject was successfully dealloced without crashing", evilAllocationObjectWasDealloced);
1311 JSContext *context = [[JSContext alloc] init];
1312 checkResult(@"default context.name is nil", context.name == nil);
1313 NSString *name1 = @"Name1";
1314 NSString *name2 = @"Name2";
1315 context.name = name1;
1316 NSString *fetchedName1 = context.name;
1317 context.name = name2;
1318 NSString *fetchedName2 = context.name;
1320 NSString *fetchedName3 = context.name;
1321 checkResult(@"fetched context.name was expected", [fetchedName1 isEqualToString:name1]);
1322 checkResult(@"fetched context.name was expected", [fetchedName2 isEqualToString:name2]);
1323 checkResult(@"fetched context.name was expected", ![fetchedName1 isEqualToString:fetchedName2]);
1324 checkResult(@"fetched context.name was expected", fetchedName3 == nil);
1328 JSContext *context = [[JSContext alloc] init];
1329 context[@"UnexportedObject"] = [UnexportedObject class];
1330 context[@"makeObject"] = ^{
1331 return [[UnexportedObject alloc] init];
1333 JSValue *result = [context evaluateScript:@"(makeObject() instanceof UnexportedObject)"];
1334 checkResult(@"makeObject() instanceof UnexportedObject", [result isBoolean] && [result toBool]);
1338 JSContext *context = [[JSContext alloc] init];
1339 [[JSValue valueWithInt32:42 inContext:context] toDictionary];
1340 [[JSValue valueWithInt32:42 inContext:context] toArray];
1344 JSContext *context = [[JSContext alloc] init];
1346 // Create the root, make it reachable from JS, and force an EdenCollection
1347 // so that we scan the external object graph.
1348 TestObject *root = [TestObject testObject];
1350 context[@"root"] = root;
1352 JSSynchronousEdenCollectForDebugging([context JSGlobalContextRef]);
1354 // Create a new Obj-C object only reachable via the external object graph
1355 // through the object we already scanned during the EdenCollection.
1356 TestObject *child = [TestObject testObject];
1357 [context.virtualMachine addManagedReference:child withOwner:root];
1359 // Create a new managed JSValue that will only be kept alive if we properly rescan
1360 // the external object graph.
1361 JSManagedValue *managedJSObject = nil;
1363 JSValue *jsObject = [JSValue valueWithObject:@"hello" inContext:context];
1364 managedJSObject = [JSManagedValue managedValueWithValue:jsObject];
1365 [context.virtualMachine addManagedReference:managedJSObject withOwner:child];
1368 // Force another EdenCollection. It should rescan the new part of the external object graph.
1369 JSSynchronousEdenCollectForDebugging([context JSGlobalContextRef]);
1371 // Check that the managed JSValue is still alive.
1372 checkResult(@"EdenCollection doesn't reclaim new managed values", [managedJSObject value] != nil);
1376 JSContext *context = [[JSContext alloc] init];
1379 pthread_create(&threadID, NULL, &threadMain, (__bridge void*)context);
1380 pthread_join(threadID, nullptr);
1381 JSSynchronousGarbageCollectForDebugging([context JSGlobalContextRef]);
1383 checkResult(@"Did not crash after entering the VM from another thread", true);
1386 currentThisInsideBlockGetterTest();
1394 void testObjectiveCAPI()
1398 #endif // JSC_OBJC_API_ENABLED