Changeset 217240 in webkit
- Timestamp:
- May 22, 2017 12:48:38 PM (7 years ago)
- Location:
- trunk/Source/JavaScriptCore
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/JavaScriptCore/API/APICast.h
r165676 r217240 59 59 ASSERT(c); 60 60 return reinterpret_cast<JSC::ExecState*>(c); 61 } 62 63 inline JSC::JSGlobalObject* toJSGlobalObject(JSGlobalContextRef context) 64 { 65 return toJS(context)->lexicalGlobalObject(); 61 66 } 62 67 -
trunk/Source/JavaScriptCore/API/JSContext.mm
r211740 r217240 44 44 JSVirtualMachine *m_virtualMachine; 45 45 JSGlobalContextRef m_context; 46 JSWrapperMap *m_wrapperMap;47 46 JSC::Strong<JSC::JSObject> m_exception; 48 47 } … … 51 50 { 52 51 return m_context; 52 } 53 54 - (void)ensureWrapperMap 55 { 56 if (!toJS([self JSGlobalContextRef])->lexicalGlobalObject()->wrapperMap()) 57 [[JSWrapperMap alloc] initWithGlobalContextRef:[self JSGlobalContextRef]]; 53 58 } 54 59 … … 66 71 m_virtualMachine = [virtualMachine retain]; 67 72 m_context = JSGlobalContextCreateInGroup(getGroupFromVirtualMachine(virtualMachine), 0); 68 m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self];69 73 70 74 self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { … … 72 76 }; 73 77 78 [self ensureWrapperMap]; 74 79 [m_virtualMachine addContext:self forGlobalContextRef:m_context]; 75 80 … … 80 85 { 81 86 m_exception.clear(); 82 [m_wrapperMap release];83 87 JSGlobalContextRelease(m_context); 84 88 [m_virtualMachine release]; … … 126 130 - (JSWrapperMap *)wrapperMap 127 131 { 128 return m_wrapperMap;132 return toJS(m_context)->lexicalGlobalObject()->wrapperMap(); 129 133 } 130 134 … … 259 263 ASSERT(m_virtualMachine); 260 264 m_context = JSGlobalContextRetain(context); 261 m_wrapperMap = [[JSWrapperMap alloc] initWithContext:self];265 [self ensureWrapperMap]; 262 266 263 267 self.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) { … … 310 314 { 311 315 JSC::JSLockHolder locker(toJS(m_context)); 312 return [ m_wrapperMap jsWrapperForObject:object];316 return [[self wrapperMap] jsWrapperForObject:object inContext:self]; 313 317 } 314 318 … … 316 320 { 317 321 JSC::JSLockHolder locker(toJS(m_context)); 318 return [ m_wrapperMap objcWrapperForJSValueRef:value];322 return [[self wrapperMap] objcWrapperForJSValueRef:value inContext:self]; 319 323 } 320 324 -
trunk/Source/JavaScriptCore/API/JSWrapperMap.h
r158762 r217240 32 32 @interface JSWrapperMap : NSObject 33 33 34 - (id)initWith Context:(JSContext *)context;34 - (id)initWithGlobalContextRef:(JSGlobalContextRef)context; 35 35 36 - (JSValue *)jsWrapperForObject:(id)object ;36 - (JSValue *)jsWrapperForObject:(id)object inContext:(JSContext *)context; 37 37 38 - (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value ;38 - (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value inContext:(JSContext *)context; 39 39 40 40 @end -
trunk/Source/JavaScriptCore/API/JSWrapperMap.mm
r211247 r217240 36 36 #import "ObjCCallbackFunction.h" 37 37 #import "ObjcRuntimeExtras.h" 38 #import "ObjectConstructor.h" 38 39 #import "WeakGCMap.h" 39 40 #import "WeakGCMapInlines.h" … … 364 365 365 366 @interface JSObjCClassInfo : NSObject { 366 JSContext *m_context;367 367 Class m_class; 368 368 bool m_block; … … 372 372 } 373 373 374 - (id)init WithContext:(JSContext *)context forClass:(Class)cls;375 - (JSC::JSObject *)wrapperForObject:(id)object ;376 - (JSC::JSObject *)constructor ;377 - (JSC::JSObject *)prototype ;374 - (id)initForClass:(Class)cls; 375 - (JSC::JSObject *)wrapperForObject:(id)object inContext:(JSContext *)context; 376 - (JSC::JSObject *)constructorInContext:(JSContext *)context; 377 - (JSC::JSObject *)prototypeInContext:(JSContext *)context; 378 378 379 379 @end … … 381 381 @implementation JSObjCClassInfo 382 382 383 - (id)init WithContext:(JSContext *)context forClass:(Class)cls383 - (id)initForClass:(Class)cls 384 384 { 385 385 self = [super init]; … … 388 388 389 389 const char* className = class_getName(cls); 390 m_context = context;391 390 m_class = cls; 392 391 m_block = [cls isSubclassOfClass:getNSBlockClass()]; … … 459 458 typedef std::pair<JSC::JSObject*, JSC::JSObject*> ConstructorPrototypePair; 460 459 461 - (ConstructorPrototypePair)allocateConstructorAndPrototype 462 { 463 JSObjCClassInfo* superClassInfo = [ m_context.wrapperMap classInfoForClass:class_getSuperclass(m_class)];460 - (ConstructorPrototypePair)allocateConstructorAndPrototypeInContext:(JSContext *)context 461 { 462 JSObjCClassInfo* superClassInfo = [context.wrapperMap classInfoForClass:class_getSuperclass(m_class)]; 464 463 465 464 ASSERT(!m_constructor || !m_prototype); … … 470 469 471 470 if (!superClassInfo) { 472 JSContextRef cContext = [m_context JSGlobalContextRef]; 473 JSValue *constructor = m_context[@"Object"]; 471 JSC::JSGlobalObject* globalObject = toJSGlobalObject([context JSGlobalContextRef]); 474 472 if (!jsConstructor) 475 jsConstructor = toJS(JSValueToObject(cContext, valueInternalValue(constructor), 0)); 476 477 if (!jsPrototype) { 478 JSValue *prototype = constructor[@"prototype"]; 479 jsPrototype = toJS(JSValueToObject(cContext, valueInternalValue(prototype), 0)); 480 } 473 jsConstructor = globalObject->objectConstructor(); 474 475 if (!jsPrototype) 476 jsPrototype = globalObject->objectPrototype(); 481 477 } else { 482 478 const char* className = class_getName(m_class); … … 484 480 // Create or grab the prototype/constructor pair. 485 481 if (!jsPrototype) 486 jsPrototype = objectWithCustomBrand( m_context, [NSString stringWithFormat:@"%sPrototype", className]);482 jsPrototype = objectWithCustomBrand(context, [NSString stringWithFormat:@"%sPrototype", className]); 487 483 488 484 if (!jsConstructor) 489 jsConstructor = allocateConstructorForCustomClass( m_context, className, m_class);490 491 JSValue* prototype = [JSValue valueWithJSValueRef:toRef(jsPrototype) inContext: m_context];492 JSValue* constructor = [JSValue valueWithJSValueRef:toRef(jsConstructor) inContext: m_context];485 jsConstructor = allocateConstructorForCustomClass(context, className, m_class); 486 487 JSValue* prototype = [JSValue valueWithJSValueRef:toRef(jsPrototype) inContext:context]; 488 JSValue* constructor = [JSValue valueWithJSValueRef:toRef(jsConstructor) inContext:context]; 493 489 putNonEnumerable(prototype, @"constructor", constructor); 494 490 putNonEnumerable(constructor, @"prototype", prototype); … … 496 492 Protocol *exportProtocol = getJSExportProtocol(); 497 493 forEachProtocolImplementingProtocol(m_class, exportProtocol, ^(Protocol *protocol){ 498 copyPrototypeProperties( m_context, m_class, protocol, prototype);499 copyMethodsToObject( m_context, m_class, protocol, NO, constructor);494 copyPrototypeProperties(context, m_class, protocol, prototype); 495 copyMethodsToObject(context, m_class, protocol, NO, constructor); 500 496 }); 501 497 502 498 // Set [Prototype]. 503 JSC::JSObject* superClassPrototype = [superClassInfo prototype ];504 JSObjectSetPrototype([ m_context JSGlobalContextRef], toRef(jsPrototype), toRef(superClassPrototype));499 JSC::JSObject* superClassPrototype = [superClassInfo prototypeInContext:context]; 500 JSObjectSetPrototype([context JSGlobalContextRef], toRef(jsPrototype), toRef(superClassPrototype)); 505 501 } 506 502 … … 510 506 } 511 507 512 - (JSC::JSObject*)wrapperForObject:(id)object 508 - (JSC::JSObject*)wrapperForObject:(id)object inContext:(JSContext *)context 513 509 { 514 510 ASSERT([object isKindOfClass:m_class]); 515 511 ASSERT(m_block == [object isKindOfClass:getNSBlockClass()]); 516 512 if (m_block) { 517 if (JSObjectRef method = objCCallbackFunctionForBlock( m_context, object)) {518 JSValue *constructor = [JSValue valueWithJSValueRef:method inContext: m_context];519 JSValue *prototype = [JSValue valueWithNewObjectInContext: m_context];513 if (JSObjectRef method = objCCallbackFunctionForBlock(context, object)) { 514 JSValue *constructor = [JSValue valueWithJSValueRef:method inContext:context]; 515 JSValue *prototype = [JSValue valueWithNewObjectInContext:context]; 520 516 putNonEnumerable(constructor, @"prototype", prototype); 521 517 putNonEnumerable(prototype, @"constructor", constructor); … … 524 520 } 525 521 526 JSC::JSObject* prototype = [self prototype ];527 528 JSC::JSObject* wrapper = makeWrapper([ m_context JSGlobalContextRef], m_classRef, object);529 JSObjectSetPrototype([ m_context JSGlobalContextRef], toRef(wrapper), toRef(prototype));522 JSC::JSObject* prototype = [self prototypeInContext:context]; 523 524 JSC::JSObject* wrapper = makeWrapper([context JSGlobalContextRef], m_classRef, object); 525 JSObjectSetPrototype([context JSGlobalContextRef], toRef(wrapper), toRef(prototype)); 530 526 return wrapper; 531 527 } 532 528 533 - (JSC::JSObject*)constructor 529 - (JSC::JSObject*)constructorInContext:(JSContext *)context 534 530 { 535 531 JSC::JSObject* constructor = m_constructor.get(); 536 532 if (!constructor) 537 constructor = [self allocateConstructorAndPrototype ].first;533 constructor = [self allocateConstructorAndPrototypeInContext:context].first; 538 534 ASSERT(!!constructor); 539 535 return constructor; 540 536 } 541 537 542 - (JSC::JSObject*)prototype 538 - (JSC::JSObject*)prototypeInContext:(JSContext *)context 543 539 { 544 540 JSC::JSObject* prototype = m_prototype.get(); 545 541 if (!prototype) 546 prototype = [self allocateConstructorAndPrototype ].second;542 prototype = [self allocateConstructorAndPrototypeInContext:context].second; 547 543 ASSERT(!!prototype); 548 544 return prototype; … … 552 548 553 549 @implementation JSWrapperMap { 554 JSContext *m_context;555 550 NSMutableDictionary *m_classMap; 556 551 std::unique_ptr<JSC::WeakGCMap<id, JSC::JSObject>> m_cachedJSWrappers; … … 558 553 } 559 554 560 - (id)initWith Context:(JSContext *)context555 - (id)initWithGlobalContextRef:(JSGlobalContextRef)context 561 556 { 562 557 self = [super init]; … … 568 563 m_cachedObjCWrappers = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0]; 569 564 570 m_cachedJSWrappers = std::make_unique<JSC::WeakGCMap<id, JSC::JSObject>>(toJS([context JSGlobalContextRef])->vm()); 571 572 m_context = context; 565 m_cachedJSWrappers = std::make_unique<JSC::WeakGCMap<id, JSC::JSObject>>(toJS(context)->vm()); 566 567 ASSERT(!toJSGlobalObject(context)->wrapperMap()); 568 toJSGlobalObject(context)->setWrapperMap(self); 573 569 m_classMap = [[NSMutableDictionary alloc] init]; 574 570 return self; … … 595 591 return m_classMap[cls] = [self classInfoForClass:class_getSuperclass(cls)]; 596 592 597 return m_classMap[cls] = [[[JSObjCClassInfo alloc] initWithContext:m_context forClass:cls] autorelease]; 598 } 599 600 - (JSValue *)jsWrapperForObject:(id)object 601 { 593 return m_classMap[cls] = [[[JSObjCClassInfo alloc] initForClass:cls] autorelease]; 594 } 595 596 - (JSValue *)jsWrapperForObject:(id)object inContext:(JSContext *)context 597 { 598 ASSERT(toJSGlobalObject([context JSGlobalContextRef])->wrapperMap() == self); 602 599 JSC::JSObject* jsWrapper = m_cachedJSWrappers->get(object); 603 600 if (jsWrapper) 604 return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext: m_context];601 return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:context]; 605 602 606 603 if (class_isMetaClass(object_getClass(object))) 607 jsWrapper = [[self classInfoForClass:(Class)object] constructor ];604 jsWrapper = [[self classInfoForClass:(Class)object] constructorInContext:context]; 608 605 else { 609 606 JSObjCClassInfo* classInfo = [self classInfoForClass:[object class]]; 610 jsWrapper = [classInfo wrapperForObject:object ];607 jsWrapper = [classInfo wrapperForObject:object inContext:context]; 611 608 } 612 609 … … 617 614 // but still, would probably nicer if we made it so that only one associated object was required, broadcasting object dealloc. 618 615 m_cachedJSWrappers->set(object, jsWrapper); 619 return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:m_context]; 620 } 621 622 - (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value 623 { 616 return [JSValue valueWithJSValueRef:toRef(jsWrapper) inContext:context]; 617 } 618 619 - (JSValue *)objcWrapperForJSValueRef:(JSValueRef)value inContext:context 620 { 621 ASSERT(toJSGlobalObject([context JSGlobalContextRef])->wrapperMap() == self); 624 622 JSValue *wrapper = static_cast<JSValue *>(NSMapGet(m_cachedObjCWrappers, value)); 625 623 if (!wrapper) { 626 wrapper = [[[JSValue alloc] initWithValue:value inContext: m_context] autorelease];624 wrapper = [[[JSValue alloc] initWithValue:value inContext:context] autorelease]; 627 625 NSMapInsert(m_cachedObjCWrappers, value, wrapper); 628 626 } -
trunk/Source/JavaScriptCore/API/tests/JSExportTests.mm
r164439 r217240 126 126 @end 127 127 128 @protocol AJSExport <JSExport> 129 - (instancetype)init; 130 @end 131 132 @interface A : NSObject <AJSExport> 133 @end 134 135 @implementation A 136 @end 137 138 static void wrapperLifetimeIsTiedToGlobalObject() 139 { 140 JSGlobalContextRef contextRef; 141 @autoreleasepool { 142 JSContext *context = [[JSContext alloc] init]; 143 contextRef = JSGlobalContextRetain(context.JSGlobalContextRef); 144 context[@"A"] = A.class; 145 checkResult(@"Initial wrapper's constructor is itself", [[context evaluateScript:@"new A().constructor === A"] toBool]); 146 } 147 148 @autoreleasepool { 149 JSContext *context = [JSContext contextWithJSGlobalContextRef:contextRef]; 150 checkResult(@"New context's wrapper's constructor is itself", [[context evaluateScript:@"new A().constructor === A"] toBool]); 151 } 152 153 JSGlobalContextRelease(contextRef); 154 } 155 156 static void wrapperForNSObjectisObject() 157 { 158 @autoreleasepool { 159 JSContext *context = [[JSContext alloc] init]; 160 context[@"Object"] = [[NSNull alloc] init]; 161 context.exception = nil; 162 163 context[@"A"] = NSObject.class; 164 NSLog(@"here: %@", [context exception]); 165 } 166 } 167 128 168 void runJSExportTests() 129 169 { … … 133 173 [JSExportTests exportDynamicallyGeneratedProtocolTest]; 134 174 } 175 wrapperLifetimeIsTiedToGlobalObject(); 176 wrapperForNSObjectisObject(); 135 177 } 136 178 -
trunk/Source/JavaScriptCore/API/tests/testapi.mm
r206876 r217240 513 513 static void testObjectiveCAPIMain() 514 514 { 515 runJSExportTests(); 516 515 517 @autoreleasepool { 516 518 JSVirtualMachine* vm = [[JSVirtualMachine alloc] init]; … … 1469 1471 checkResult(@"Ran code in five concurrent VMs that GC'd", ok); 1470 1472 } 1471 1473 1472 1474 currentThisInsideBlockGetterTest(); 1473 1475 runDateTests(); … … 1508 1510 } 1509 1511 1512 1510 1513 void testObjectiveCAPI() 1511 1514 { -
trunk/Source/JavaScriptCore/ChangeLog
r217221 r217240 1 2017-05-22 Keith Miller <keith_miller@apple.com> 2 3 [Cocoa] An exported Objective C class’s prototype and constructor don't persist across JSContext deallocation 4 https://bugs.webkit.org/show_bug.cgi?id=167708 5 6 Reviewed by Geoffrey Garen. 7 8 This patch moves the Objective C wrapper map to the global object. In order to make this work the JSWrapperMap 9 class no longer holds a reference to the JSContext. Instead, the context must be provided when getting a wrapper. 10 11 Also, this patch fixes a "bug" where we would observe changes to the Object property on the global object when 12 creating a wrapper for NSObject. 13 14 * API/APICast.h: 15 (toJSGlobalObject): 16 * API/JSContext.mm: 17 (-[JSContext ensureWrapperMap]): 18 (-[JSContext initWithVirtualMachine:]): 19 (-[JSContext dealloc]): 20 (-[JSContext wrapperMap]): 21 (-[JSContext initWithGlobalContextRef:]): 22 (-[JSContext wrapperForObjCObject:]): 23 (-[JSContext wrapperForJSObject:]): 24 * API/JSWrapperMap.h: 25 * API/JSWrapperMap.mm: 26 (-[JSObjCClassInfo initForClass:]): 27 (-[JSObjCClassInfo allocateConstructorAndPrototypeInContext:]): 28 (-[JSObjCClassInfo wrapperForObject:inContext:]): 29 (-[JSObjCClassInfo constructorInContext:]): 30 (-[JSObjCClassInfo prototypeInContext:]): 31 (-[JSWrapperMap initWithGlobalContextRef:]): 32 (-[JSWrapperMap classInfoForClass:]): 33 (-[JSWrapperMap jsWrapperForObject:inContext:]): 34 (-[JSWrapperMap objcWrapperForJSValueRef:inContext:]): 35 (-[JSObjCClassInfo initWithContext:forClass:]): Deleted. 36 (-[JSObjCClassInfo allocateConstructorAndPrototype]): Deleted. 37 (-[JSObjCClassInfo wrapperForObject:]): Deleted. 38 (-[JSObjCClassInfo constructor]): Deleted. 39 (-[JSObjCClassInfo prototype]): Deleted. 40 (-[JSWrapperMap initWithContext:]): Deleted. 41 (-[JSWrapperMap jsWrapperForObject:]): Deleted. 42 (-[JSWrapperMap objcWrapperForJSValueRef:]): Deleted. 43 * API/tests/JSExportTests.mm: 44 (wrapperLifetimeIsTiedToGlobalObject): 45 (runJSExportTests): 46 * API/tests/testapi.mm: 47 * runtime/JSGlobalObject.h: 48 (JSC::JSGlobalObject::wrapperMap): 49 (JSC::JSGlobalObject::setWrapperMap): 50 1 51 2017-05-22 Filip Pizlo <fpizlo@apple.com> 2 52 -
trunk/Source/JavaScriptCore/runtime/JSGlobalObject.h
r217060 r217240 46 46 #include <array> 47 47 #include <wtf/HashSet.h> 48 #include <wtf/RetainPtr.h> 48 49 49 50 struct OpaqueJSClass; 50 51 struct OpaqueJSClassContextData; 52 OBJC_CLASS JSWrapperMap; 51 53 52 54 namespace Inspector { … … 830 832 bool needsSiteSpecificQuirks() const { return m_needsSiteSpecificQuirks; } 831 833 834 #if JSC_OBJC_API_ENABLED 835 JSWrapperMap* wrapperMap() const { return m_wrapperMap.get(); } 836 void setWrapperMap(JSWrapperMap* map) { m_wrapperMap = map; } 837 #endif 838 832 839 protected: 833 840 struct GlobalPropertyInfo { … … 859 866 860 867 bool m_needsSiteSpecificQuirks { false }; 868 #if JSC_OBJC_API_ENABLED 869 RetainPtr<JSWrapperMap> m_wrapperMap; 870 #endif 861 871 }; 862 872
Note: See TracChangeset
for help on using the changeset viewer.