Changeset 146558 in webkit


Ignore:
Timestamp:
Mar 21, 2013 8:12:49 PM (11 years ago)
Author:
mhahnenberg@apple.com
Message:

Objective-C API: Need a good way to preserve custom properties on JS wrappers
https://bugs.webkit.org/show_bug.cgi?id=112608

Reviewed by Geoffrey Garen.

Currently, we just use a weak map, which means that garbage collection can cause a wrapper to
disappear if it isn't directly exported to JavaScript.

The most straightforward and safe way (with respect to garbage collection and concurrency) is to have
clients add and remove their external references along with their owners. Effectively, the client is
recording the structure of the external object graph so that the garbage collector can make sure to
mark any wrappers that are reachable through either the JS object graph of the external Obj-C object
graph. By keeping these wrappers alive, this has the effect that custom properties on these wrappers
will also remain alive.

The rule for if an object needs to be tracked by the runtime (and therefore whether the client should report it) is as follows:
For a particular object, its references to its children should be added if:

  1. The child is referenced from JavaScript.
  2. The child contains references to other objects for which (1) or (2) are true.
  • API/JSAPIWrapperObject.mm:

(JSAPIWrapperObjectHandleOwner::finalize):
(JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots): A wrapper object is kept alive only if its JSGlobalObject
is marked and its corresponding Objective-C object was added to the set of opaque roots.
(JSC::JSAPIWrapperObject::visitChildren): We now call out to scanExternalObjectGraph, which handles adding all Objective-C
objects to the set of opaque roots.

  • API/JSAPIWrapperObject.h:

(JSAPIWrapperObject):

  • API/JSContext.mm: Moved dealloc to its proper place in the main implementation.

(-[JSContext dealloc]):

  • API/JSVirtualMachine.h:
  • API/JSVirtualMachine.mm:

(-[JSVirtualMachine initWithContextGroupRef:]):
(-[JSVirtualMachine dealloc]):
(getInternalObjcObject): Helper funciton to get the Objective-C object out of JSManagedValues or JSValues if there is one.
(-[JSVirtualMachine addManagedReference:withOwner:]): Adds the Objective-C object to the set of objects
owned by the owner object in that particular virtual machine.
(-[JSVirtualMachine removeManagedReference:withOwner:]): Removes the relationship between the two objects.
(-[JSVirtualMachine externalObjectGraph]):
(scanExternalObjectGraph): Does a depth-first search of the external object graph in a particular virtual machine starting at
the specified root. Each new object it encounters it adds to the set of opaque roots. These opaque roots will keep their
corresponding wrapper objects alive if they have them.

  • API/JSManagedReferenceInternal.h: Added.
  • API/JSVirtualMachine.mm: Added the per-JSVirtualMachine map between objects and the objects they own, which is more formally

known as that virtual machine's external object graph.

  • API/JSWrapperMap.mm:

(-[JSWrapperMap dealloc]): We were leaking this before :-(
(-[JSVirtualMachine initWithContextGroupRef:]):
(-[JSVirtualMachine dealloc]):
(-[JSVirtualMachine externalObjectGraph]):

  • API/JSVirtualMachineInternal.h:
  • API/tests/testapi.mm: Added two new tests using the TinyDOMNode class. The first tests that a custom property added to a wrapper

doesn't vanish after GC, even though that wrapper isn't directly accessible to the JS garbage collector but is accessible through
the external Objective-C object graph. The second test makes sure that adding an object to the external object graph with the same
owner doesn't cause any sort of problems.
(+[TinyDOMNode sharedVirtualMachine]):
(-[TinyDOMNode init]):
(-[TinyDOMNode dealloc]):
(-[TinyDOMNode appendChild:]):
(-[TinyDOMNode numberOfChildren]):
(-[TinyDOMNode childAtIndex:]):
(-[TinyDOMNode removeChildAtIndex:]):

(SlotVisitor):

  • heap/SlotVisitorInlines.h:

(JSC::SlotVisitor::containsOpaqueRootTriState): Added a new method to SlotVisitor to allow scanExternalObjectGraph to have a
thread-safe view of opaque roots during parallel marking. The set of opaque roots available to any one SlotVisitor isn't guaranteed
to be 100% correct, but that just results in a small duplication of work in scanExternalObjectGraph. To indicate this change for
false negatives we return a TriState that's either true or mixed, but never false.

Location:
trunk/Source/JavaScriptCore
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/JSAPIWrapperObject.h

    r146494 r146558  
    5656} // namespace JSC
    5757
    58 #endif
     58#endif // JSC_OBJC_API_ENABLED
    5959
    6060#endif // JSAPIWrapperObject_h
  • trunk/Source/JavaScriptCore/API/JSAPIWrapperObject.mm

    r146494 r146558  
    3030#include "JSCallbackObject.h"
    3131#include "JSCellInlines.h"
     32#include "JSVirtualMachineInternal.h"
    3233#include "SlotVisitorInlines.h"
    3334#include "Structure.h"
     
    3940public:
    4041    virtual void finalize(JSC::Handle<JSC::Unknown>, void*);
     42    virtual bool isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown>, void* context, JSC::SlotVisitor&);
    4143};
    4244
     
    4951void JSAPIWrapperObjectHandleOwner::finalize(JSC::Handle<JSC::Unknown> handle, void*)
    5052{
    51     JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
    5253    JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
    5354    if (!wrapperObject->wrappedObject())
    5455        return;
    5556    [static_cast<id>(wrapperObject->wrappedObject()) release];
     57    JSC::WeakSet::deallocate(JSC::WeakImpl::asWeakImpl(handle.slot()));
     58}
     59
     60bool JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots(JSC::Handle<JSC::Unknown> handle, void*, JSC::SlotVisitor& visitor)
     61{
     62    JSC::JSAPIWrapperObject* wrapperObject = JSC::jsCast<JSC::JSAPIWrapperObject*>(handle.get().asCell());
     63    // We use the JSGlobalObject when processing weak handles to prevent the situation where using
     64    // the same Objective-C object in multiple global objects keeps all of the global objects alive.
     65    if (!wrapperObject->wrappedObject())
     66        return false;
     67    return JSC::Heap::isMarked(wrapperObject->structure()->globalObject()) && visitor.containsOpaqueRoot(wrapperObject->wrappedObject());
    5668}
    5769
     
    93105
    94106    if (thisObject->wrappedObject())
    95         visitor.addOpaqueRoot(thisObject->wrappedObject());
     107        scanExternalObjectGraph(cell->structure()->globalObject()->globalData(), visitor, thisObject->wrappedObject());
    96108}
    97109
  • trunk/Source/JavaScriptCore/API/JSContext.mm

    r145119 r146558  
    7979}
    8080
     81- (void)dealloc
     82{
     83    [m_wrapperMap release];
     84    JSGlobalContextRelease(m_context);
     85    [m_virtualMachine release];
     86    [self.exceptionHandler release];
     87    [super dealloc];
     88}
     89
    8190- (JSValue *)evaluateScript:(NSString *)script
    8291{
     
    196205}
    197206
    198 - (void)dealloc
    199 {
    200     [m_wrapperMap release];
    201     JSGlobalContextRelease(m_context);
    202     [m_virtualMachine release];
    203     [self.exceptionHandler release];
    204     [super dealloc];
    205 }
    206 
    207207- (void)notifyException:(JSValueRef)exceptionValue
    208208{
  • trunk/Source/JavaScriptCore/API/JSVirtualMachine.h

    r143637 r146558  
    3838- (id)init;
    3939
     40- (void)addManagedReference:(id)object withOwner:(id)owner;
     41- (void)removeManagedReference:(id)object withOwner:(id)owner;
     42
    4043@end
    4144
  • trunk/Source/JavaScriptCore/API/JSVirtualMachine.mm

    r145119 r146558  
    3131
    3232#import "APICast.h"
     33#import "APIShims.h"
     34#import "JSVirtualMachine.h"
    3335#import "JSVirtualMachineInternal.h"
     36#import "JSWrapperMap.h"
    3437
    3538static NSMapTable *globalWrapperCache = 0;
     
    8083    JSContextGroupRef m_group;
    8184    NSMapTable *m_contextCache;
     85    NSMapTable *m_externalObjectGraph;
    8286}
    8387
     
    102106    NSPointerFunctionsOptions valueOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
    103107    m_contextCache = [[NSMapTable alloc] initWithKeyOptions:keyOptions valueOptions:valueOptions capacity:0];
     108   
     109    NSPointerFunctionsOptions weakIDOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
     110    NSPointerFunctionsOptions strongIDOptions = NSPointerFunctionsStrongMemory | NSPointerFunctionsObjectPersonality;
     111    m_externalObjectGraph = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:strongIDOptions capacity:0];
    104112   
    105113    [JSVMWrapperCache addWrapper:self forJSContextGroupRef:group];
     
    108116}
    109117
     118- (void)dealloc
     119{
     120    JSContextGroupRelease(m_group);
     121    [m_contextCache release];
     122    [m_externalObjectGraph release];
     123    [super dealloc];
     124}
     125
     126static id getInternalObjcObject(id object)
     127{
     128    if ([object isKindOfClass:[JSManagedValue class]])
     129        object = [static_cast<JSManagedValue *>(object) value];
     130   
     131    if ([object isKindOfClass:[JSValue class]]) {
     132        JSValue *value = static_cast<JSValue *>(object);
     133        object = tryUnwrapObjcObject([value.context globalContextRef], [value JSValueRef]);
     134    }
     135   
     136    return object;
     137}
     138
     139- (void)addManagedReference:(id)object withOwner:(id)owner
     140{   
     141    object = getInternalObjcObject(object);
     142    owner = getInternalObjcObject(owner);
     143   
     144    if (!object || !owner)
     145        return;
     146   
     147    JSC::APIEntryShim shim(toJS(m_group));
     148   
     149    NSMapTable *ownedObjects = [m_externalObjectGraph objectForKey:owner];
     150    if (!ownedObjects) {
     151        NSPointerFunctionsOptions weakIDOptions = NSPointerFunctionsWeakMemory | NSPointerFunctionsObjectPersonality;
     152        NSPointerFunctionsOptions integerOptions = NSPointerFunctionsOpaqueMemory | NSPointerFunctionsIntegerPersonality;
     153        ownedObjects = [[NSMapTable alloc] initWithKeyOptions:weakIDOptions valueOptions:integerOptions capacity:1];
     154
     155        [m_externalObjectGraph setObject:ownedObjects forKey:owner];
     156        [ownedObjects release];
     157    }
     158    NSMapInsert(ownedObjects, object, reinterpret_cast<void*>(reinterpret_cast<size_t>(NSMapGet(ownedObjects, object)) + 1));
     159}
     160
     161- (void)removeManagedReference:(id)object withOwner:(id)owner
     162{
     163    object = getInternalObjcObject(object);
     164    owner = getInternalObjcObject(owner);
     165   
     166    if (!object || !owner)
     167        return;
     168   
     169    JSC::APIEntryShim shim(toJS(m_group));
     170   
     171    NSMapTable *ownedObjects = [m_externalObjectGraph objectForKey:owner];
     172    if (!ownedObjects)
     173        return;
     174   
     175    size_t count = reinterpret_cast<size_t>(NSMapGet(ownedObjects, object));
     176    if (count > 1) {
     177        NSMapInsert(ownedObjects, object, reinterpret_cast<void*>(count - 1));
     178        return;
     179    }
     180   
     181    if (count == 1)
     182        NSMapRemove(ownedObjects, object);
     183
     184    if (![ownedObjects count])
     185        [m_externalObjectGraph removeObjectForKey:owner];
     186}
     187
    110188@end
    111189
    112190@implementation JSVirtualMachine(Internal)
    113 
    114 - (void)dealloc
    115 {
    116     JSContextGroupRelease(m_group);
    117     [super dealloc];
    118 }
    119191
    120192JSContextGroupRef getGroupFromVirtualMachine(JSVirtualMachine *virtualMachine)
     
    141213}
    142214
    143 @end
    144 
     215- (NSMapTable *)externalObjectGraph
     216{
     217    return m_externalObjectGraph;
     218}
     219
     220@end
     221
     222void scanExternalObjectGraph(JSC::JSGlobalData& globalData, JSC::SlotVisitor& visitor, void* root)
     223{
     224    @autoreleasepool {
     225        JSVirtualMachine *virtualMachine = [JSVirtualMachine virtualMachineWithContextGroupRef:toRef(&globalData)];
     226        NSMapTable *externalObjectGraph = [virtualMachine externalObjectGraph];
     227        Vector<void*> stack;
     228        stack.append(root);
     229        while (!stack.isEmpty()) {
     230            void* nextRoot = stack.last();
     231            stack.removeLast();
     232            if (visitor.containsOpaqueRootTriState(nextRoot) == TrueTriState)
     233                continue;
     234            visitor.addOpaqueRoot(nextRoot);
     235           
     236            NSMapTable *ownedObjects = [externalObjectGraph objectForKey:static_cast<id>(nextRoot)];
     237            id ownedObject;
     238            NSEnumerator *enumerator = [ownedObjects keyEnumerator];
     239            while ((ownedObject = [enumerator nextObject])) {
     240                ASSERT(reinterpret_cast<size_t>(NSMapGet(ownedObjects, ownedObject)) == 1);
     241                stack.append(static_cast<void*>(ownedObject));
     242            }
     243        }
     244    }
     245}
    145246
    146247#endif
  • trunk/Source/JavaScriptCore/API/JSVirtualMachineInternal.h

    r143637 r146558  
    2727#define JSVirtualMachineInternal_h
    2828
    29 #import <JavaScriptCore/JSVirtualMachine.h>
    3029#import <JavaScriptCore/JavaScriptCore.h>
    3130
    3231#if JSC_OBJC_API_ENABLED
    3332
     33namespace JSC {
     34class JSGlobalData;
     35class SlotVisitor;
     36}
     37
     38#if defined(__OBJC__)
    3439@interface JSVirtualMachine(Internal)
    3540
     
    4146- (void)addContext:(JSContext *)wrapper forGlobalContextRef:(JSGlobalContextRef)globalContext;
    4247
     48- (NSMapTable *)externalObjectGraph;
     49
    4350@end
     51#endif // defined(__OBJC__)
     52
     53void scanExternalObjectGraph(JSC::JSGlobalData&, JSC::SlotVisitor&, void* root);
    4454
    4555#endif
  • trunk/Source/JavaScriptCore/API/JSWrapperMap.mm

    r146494 r146558  
    435435- (void)dealloc
    436436{
     437    [m_cachedObjCWrappers release];
    437438    [m_classMap release];
    438439    [super dealloc];
  • trunk/Source/JavaScriptCore/API/tests/testapi.mm

    r146494 r146558  
    154154@end
    155155
     156@class TinyDOMNode;
     157
     158@protocol TinyDOMNode <JSExport>
     159- (void)appendChild:(TinyDOMNode *)child;
     160- (NSUInteger)numberOfChildren;
     161- (TinyDOMNode *)childAtIndex:(NSUInteger)index;
     162- (void)removeChildAtIndex:(NSUInteger)index;
     163@end
     164
     165@interface TinyDOMNode : NSObject<TinyDOMNode>
     166+ (JSVirtualMachine *)sharedVirtualMachine;
     167+ (void)clearSharedVirtualMachine;
     168@end
     169
     170@implementation TinyDOMNode {
     171    NSMutableArray *m_children;
     172}
     173
     174static JSVirtualMachine *sharedInstance = nil;
     175
     176+ (JSVirtualMachine *)sharedVirtualMachine
     177{
     178    if (!sharedInstance)
     179        sharedInstance = [[JSVirtualMachine alloc] init];
     180    return sharedInstance;
     181}
     182
     183+ (void)clearSharedVirtualMachine
     184{
     185    sharedInstance = nil;
     186}
     187
     188- (id)init
     189{
     190    self = [super init];
     191    if (!self)
     192        return nil;
     193
     194    m_children = [[NSMutableArray alloc] initWithCapacity:0];
     195
     196    return self;
     197}
     198
     199- (void)dealloc
     200{
     201    NSEnumerator *enumerator = [m_children objectEnumerator];
     202    id nextChild;
     203    while ((nextChild = [enumerator nextObject]))
     204        [[TinyDOMNode sharedVirtualMachine] removeManagedReference:nextChild withOwner:self];
     205}
     206
     207- (void)appendChild:(TinyDOMNode *)child
     208{
     209    [[TinyDOMNode sharedVirtualMachine] addManagedReference:child withOwner:self];
     210    [m_children addObject:child];
     211}
     212
     213- (NSUInteger)numberOfChildren
     214{
     215    return [m_children count];
     216}
     217
     218- (TinyDOMNode *)childAtIndex:(NSUInteger)index
     219{
     220    if (index >= [m_children count])
     221        return nil;
     222    return [m_children objectAtIndex:index];
     223}
     224
     225- (void)removeChildAtIndex:(NSUInteger)index
     226{
     227    if (index >= [m_children count])
     228        return;
     229    [[TinyDOMNode sharedVirtualMachine] removeManagedReference:[m_children objectAtIndex:index] withOwner:self];
     230    [m_children removeObjectAtIndex:index];
     231}
     232
     233@end
     234
    156235static void checkResult(NSString *description, bool passed)
    157236{
     
    649728    }
    650729
     730    @autoreleasepool {
     731        JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine];
     732        JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
     733        TinyDOMNode *root = [[TinyDOMNode alloc] init];
     734        TinyDOMNode *lastNode = root;
     735        for (NSUInteger i = 0; i < 3; i++) {
     736            TinyDOMNode *newNode = [[TinyDOMNode alloc] init];
     737            [lastNode appendChild:newNode];
     738            lastNode = newNode;
     739        }
     740
     741        @autoreleasepool {
     742            context[@"root"] = root;
     743            context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){
     744                TinyDOMNode *lastNode = nil;
     745                while (head) {
     746                    lastNode = head;
     747                    head = [lastNode childAtIndex:0];
     748                }
     749                return lastNode;
     750            };
     751            [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"];
     752        }
     753
     754        JSSynchronousGarbageCollectForDebugging([context globalContextRef]);
     755
     756        JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
     757        checkResult(@"My custom property == 42", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
     758
     759        [TinyDOMNode clearSharedVirtualMachine];
     760    }
     761
     762    @autoreleasepool {
     763        JSVirtualMachine *vm = [TinyDOMNode sharedVirtualMachine];
     764        JSContext *context = [[JSContext alloc] initWithVirtualMachine:vm];
     765        TinyDOMNode *root = [[TinyDOMNode alloc] init];
     766        TinyDOMNode *lastNode = root;
     767        for (NSUInteger i = 0; i < 3; i++) {
     768            TinyDOMNode *newNode = [[TinyDOMNode alloc] init];
     769            [lastNode appendChild:newNode];
     770            lastNode = newNode;
     771        }
     772
     773        @autoreleasepool {
     774            context[@"root"] = root;
     775            context[@"getLastNodeInChain"] = ^(TinyDOMNode *head){
     776                TinyDOMNode *lastNode = nil;
     777                while (head) {
     778                    lastNode = head;
     779                    head = [lastNode childAtIndex:0];
     780                }
     781                return lastNode;
     782            };
     783            [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty = 42;"];
     784
     785            [root appendChild:[root childAtIndex:0]];
     786            [root removeChildAtIndex:0];
     787        }
     788
     789        JSSynchronousGarbageCollectForDebugging([context globalContextRef]);
     790
     791        JSValue *myCustomProperty = [context evaluateScript:@"getLastNodeInChain(root).myCustomProperty"];
     792        checkResult(@"duplicate calls to addManagedReference don't cause things to die", [myCustomProperty isNumber] && [myCustomProperty toInt32] == 42);
     793
     794        [TinyDOMNode clearSharedVirtualMachine];
     795    }
    651796}
    652797
  • trunk/Source/JavaScriptCore/ChangeLog

    r146552 r146558  
     12013-03-21  Mark Hahnenberg  <mhahnenberg@apple.com>
     2
     3        Objective-C API: Need a good way to preserve custom properties on JS wrappers
     4        https://bugs.webkit.org/show_bug.cgi?id=112608
     5
     6        Reviewed by Geoffrey Garen.
     7
     8        Currently, we just use a weak map, which means that garbage collection can cause a wrapper to
     9        disappear if it isn't directly exported to JavaScript.
     10
     11        The most straightforward and safe way (with respect to garbage collection and concurrency) is to have
     12        clients add and remove their external references along with their owners. Effectively, the client is
     13        recording the structure of the external object graph so that the garbage collector can make sure to
     14        mark any wrappers that are reachable through either the JS object graph of the external Obj-C object
     15        graph. By keeping these wrappers alive, this has the effect that custom properties on these wrappers
     16        will also remain alive.
     17
     18        The rule for if an object needs to be tracked by the runtime (and therefore whether the client should report it) is as follows:
     19        For a particular object, its references to its children should be added if:
     20        1. The child is referenced from JavaScript.
     21        2. The child contains references to other objects for which (1) or (2) are true.
     22
     23        * API/JSAPIWrapperObject.mm:
     24        (JSAPIWrapperObjectHandleOwner::finalize):
     25        (JSAPIWrapperObjectHandleOwner::isReachableFromOpaqueRoots): A wrapper object is kept alive only if its JSGlobalObject
     26        is marked and its corresponding Objective-C object was added to the set of opaque roots.
     27        (JSC::JSAPIWrapperObject::visitChildren): We now call out to scanExternalObjectGraph, which handles adding all Objective-C
     28        objects to the set of opaque roots.
     29        * API/JSAPIWrapperObject.h:
     30        (JSAPIWrapperObject):
     31        * API/JSContext.mm: Moved dealloc to its proper place in the main implementation.
     32        (-[JSContext dealloc]):
     33        * API/JSVirtualMachine.h:
     34        * API/JSVirtualMachine.mm:
     35        (-[JSVirtualMachine initWithContextGroupRef:]):
     36        (-[JSVirtualMachine dealloc]):
     37        (getInternalObjcObject): Helper funciton to get the Objective-C object out of JSManagedValues or JSValues if there is one.
     38        (-[JSVirtualMachine addManagedReference:withOwner:]): Adds the Objective-C object to the set of objects
     39        owned by the owner object in that particular virtual machine.
     40        (-[JSVirtualMachine removeManagedReference:withOwner:]): Removes the relationship between the two objects.
     41        (-[JSVirtualMachine externalObjectGraph]):
     42        (scanExternalObjectGraph): Does a depth-first search of the external object graph in a particular virtual machine starting at
     43        the specified root. Each new object it encounters it adds to the set of opaque roots. These opaque roots will keep their
     44        corresponding wrapper objects alive if they have them.
     45        * API/JSManagedReferenceInternal.h: Added.
     46        * API/JSVirtualMachine.mm: Added the per-JSVirtualMachine map between objects and the objects they own, which is more formally
     47        known as that virtual machine's external object graph.
     48        * API/JSWrapperMap.mm:
     49        (-[JSWrapperMap dealloc]): We were leaking this before :-(
     50        (-[JSVirtualMachine initWithContextGroupRef:]):
     51        (-[JSVirtualMachine dealloc]):
     52        (-[JSVirtualMachine externalObjectGraph]):
     53        * API/JSVirtualMachineInternal.h:
     54        * API/tests/testapi.mm: Added two new tests using the TinyDOMNode class. The first tests that a custom property added to a wrapper
     55        doesn't vanish after GC, even though that wrapper isn't directly accessible to the JS garbage collector but is accessible through
     56        the external Objective-C object graph. The second test makes sure that adding an object to the external object graph with the same
     57        owner doesn't cause any sort of problems.
     58        (+[TinyDOMNode sharedVirtualMachine]):
     59        (-[TinyDOMNode init]):
     60        (-[TinyDOMNode dealloc]):
     61        (-[TinyDOMNode appendChild:]):
     62        (-[TinyDOMNode numberOfChildren]):
     63        (-[TinyDOMNode childAtIndex:]):
     64        (-[TinyDOMNode removeChildAtIndex:]):
     65        * JavaScriptCore.xcodeproj/project.pbxproj:
     66        * heap/SlotVisitor.h:
     67        (SlotVisitor):
     68        * heap/SlotVisitorInlines.h:
     69        (JSC::SlotVisitor::containsOpaqueRootTriState): Added a new method to SlotVisitor to allow scanExternalObjectGraph to have a
     70        thread-safe view of opaque roots during parallel marking. The set of opaque roots available to any one SlotVisitor isn't guaranteed
     71        to be 100% correct, but that just results in a small duplication of work in scanExternalObjectGraph. To indicate this change for
     72        false negatives we return a TriState that's either true or mixed, but never false.
     73
    1742013-03-21  Mark Lam  <mark.lam@apple.com>
    275
  • trunk/Source/JavaScriptCore/heap/SlotVisitor.h

    r146383 r146558  
    6363    void addOpaqueRoot(void*);
    6464    bool containsOpaqueRoot(void*);
     65    TriState containsOpaqueRootTriState(void*);
    6566    int opaqueRootCount();
    6667
  • trunk/Source/JavaScriptCore/heap/SlotVisitorInlines.h

    r138067 r146558  
    122122}
    123123
     124inline TriState SlotVisitor::containsOpaqueRootTriState(void* root)
     125{
     126    if (m_opaqueRoots.contains(root))
     127        return TrueTriState;
     128    MutexLocker locker(m_shared.m_opaqueRootsLock);
     129    if (m_shared.m_opaqueRoots.contains(root))
     130        return TrueTriState;
     131    return MixedTriState;
     132}
     133
    124134inline int SlotVisitor::opaqueRootCount()
    125135{
Note: See TracChangeset for help on using the changeset viewer.