| Index: Source/heap/HeapTest.cpp | 
| diff --git a/Source/heap/HeapTest.cpp b/Source/heap/HeapTest.cpp | 
| index 3c6ad7765778cb555defc67623bd3d98ecc18971..1d31ad61d7c1c99394f25468f1b38e4e5a5fcf34 100644 | 
| --- a/Source/heap/HeapTest.cpp | 
| +++ b/Source/heap/HeapTest.cpp | 
| @@ -759,6 +759,193 @@ private: | 
| WeakMember<Bar> m_weakBar; | 
| }; | 
|  | 
| + | 
| +class SuperClass; | 
| + | 
| +class PointsBack : public RefCountedWillBeGarbageCollectedFinalized<PointsBack> { | 
| +    DECLARE_GC_INFO; | 
| +public: | 
| +    static PassRefPtrWillBePtr<PointsBack> create() | 
| +    { | 
| +        return adoptRefWillBeNoop(new PointsBack()); | 
| +    } | 
| + | 
| +    ~PointsBack() | 
| +    { | 
| +        --s_aliveCount; | 
| +    } | 
| + | 
| +    void setBackPointer(SuperClass* backPointer) | 
| +    { | 
| +        m_backPointer = backPointer; | 
| +    } | 
| + | 
| +    SuperClass* backPointer() const { return m_backPointer; } | 
| + | 
| +    void trace(Visitor* visitor) | 
| +    { | 
| +#if ENABLE_OILPAN | 
| +        visitor->trace(m_backPointer); | 
| +#endif | 
| +    } | 
| + | 
| +    static int s_aliveCount; | 
| +private: | 
| +    PointsBack() : m_backPointer(nullptr) | 
| +    { | 
| +        ++s_aliveCount; | 
| +    } | 
| + | 
| +    PtrWillBeWeakMember<SuperClass> m_backPointer; | 
| +}; | 
| + | 
| +int PointsBack::s_aliveCount = 0; | 
| + | 
| +class SuperClass : public RefCountedWillBeGarbageCollectedFinalized<SuperClass> { | 
| +    DECLARE_GC_INFO; | 
| +public: | 
| +    static PassRefPtrWillBePtr<SuperClass> create(PassRefPtrWillBePtr<PointsBack> pointsBack) | 
| +    { | 
| +        return adoptRefWillBeNoop(new SuperClass(pointsBack)); | 
| +    } | 
| + | 
| +    virtual ~SuperClass() | 
| +    { | 
| +#if !ENABLE_OILPAN | 
| +        m_pointsBack->setBackPointer(0); | 
| +#endif | 
| +        --s_aliveCount; | 
| +    } | 
| + | 
| +    void doStuff(PassRefPtrWillBePtr<SuperClass> targetPass, PointsBack* pointsBack, int superClassCount) | 
| +    { | 
| +        RefPtrWillBePtr<SuperClass> target = targetPass; | 
| +        Heap::collectGarbage(ThreadState::HeapPointersOnStack); | 
| +        EXPECT_EQ(pointsBack, target->pointsBack()); | 
| +        EXPECT_EQ(superClassCount, SuperClass::s_aliveCount); | 
| +    } | 
| + | 
| +    virtual void trace(Visitor* visitor) | 
| +    { | 
| +#if ENABLE_OILPAN | 
| +        visitor->trace(m_pointsBack); | 
| +#endif | 
| +    } | 
| + | 
| +    PointsBack* pointsBack() const { return m_pointsBack.get(); } | 
| + | 
| +    static int s_aliveCount; | 
| +protected: | 
| +    explicit SuperClass(PassRefPtrWillBePtr<PointsBack> pointsBack) | 
| +        : m_pointsBack(pointsBack) | 
| +    { | 
| +        m_pointsBack->setBackPointer(this); | 
| +        ++s_aliveCount; | 
| +    } | 
| + | 
| +private: | 
| +    RefPtrWillBeMember<PointsBack> m_pointsBack; | 
| +}; | 
| + | 
| +int SuperClass::s_aliveCount = 0; | 
| +class SubData : public NoBaseWillBeGarbageCollectedFinalized<SubData> { | 
| +    DECLARE_GC_INFO | 
| +public: | 
| +    SubData() { ++s_aliveCount; } | 
| +    ~SubData() { --s_aliveCount; } | 
| + | 
| +    void trace(Visitor*) { } | 
| + | 
| +    static int s_aliveCount; | 
| +}; | 
| + | 
| +int SubData::s_aliveCount = 0; | 
| + | 
| +class SubClass : public SuperClass { | 
| +public: | 
| +    static PassRefPtrWillBePtr<SubClass> create(PassRefPtrWillBePtr<PointsBack> pointsBack) | 
| +    { | 
| +        return adoptRefWillBeNoop(new SubClass(pointsBack)); | 
| +    } | 
| + | 
| +    virtual ~SubClass() | 
| +    { | 
| +        --s_aliveCount; | 
| +    } | 
| + | 
| +    virtual void trace(Visitor* visitor) | 
| +    { | 
| +#if ENABLE_OILPAN | 
| +        SuperClass::trace(visitor); | 
| +        visitor->trace(m_data); | 
| +#endif | 
| +    } | 
| + | 
| +    static int s_aliveCount; | 
| +private: | 
| +    explicit SubClass(PassRefPtrWillBePtr<PointsBack> pointsBack) | 
| +        : SuperClass(pointsBack) | 
| +        , m_data(adoptPtrWillBeNoop(new SubData())) | 
| +    { | 
| +        ++s_aliveCount; | 
| +    } | 
| + | 
| +private: | 
| +    OwnPtrWillBeMember<SubData> m_data; | 
| +}; | 
| + | 
| +int SubClass::s_aliveCount = 0; | 
| + | 
| +TEST(HeapTest, Transition) | 
| +{ | 
| +    RefPtrWillBePersistent<PointsBack> pointsBack1 = PointsBack::create(); | 
| +    RefPtrWillBePersistent<PointsBack> pointsBack2 = PointsBack::create(); | 
| +    RefPtrWillBePersistent<SuperClass> superClass = SuperClass::create(pointsBack1); | 
| +    RefPtrWillBePersistent<SubClass> subClass = SubClass::create(pointsBack2); | 
| +    EXPECT_EQ(2, PointsBack::s_aliveCount); | 
| +    EXPECT_EQ(2, SuperClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubData::s_aliveCount); | 
| + | 
| +    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 
| +    EXPECT_EQ(2, PointsBack::s_aliveCount); | 
| +    EXPECT_EQ(2, SuperClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubData::s_aliveCount); | 
| + | 
| +    superClass->doStuff(superClass.release(), pointsBack1.get(), 2); | 
| +    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 
| +    EXPECT_EQ(2, PointsBack::s_aliveCount); | 
| +    EXPECT_EQ(1, SuperClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubData::s_aliveCount); | 
| +    EXPECT_EQ(0, pointsBack1->backPointer()); | 
| + | 
| +    pointsBack1.release(); | 
| +    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 
| +    EXPECT_EQ(1, PointsBack::s_aliveCount); | 
| +    EXPECT_EQ(1, SuperClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubClass::s_aliveCount); | 
| +    EXPECT_EQ(1, SubData::s_aliveCount); | 
| + | 
| +    subClass->doStuff(subClass.release(), pointsBack2.get(), 1); | 
| +    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 
| +    EXPECT_EQ(1, PointsBack::s_aliveCount); | 
| +    EXPECT_EQ(0, SuperClass::s_aliveCount); | 
| +    EXPECT_EQ(0, SubClass::s_aliveCount); | 
| +    EXPECT_EQ(0, SubData::s_aliveCount); | 
| +    EXPECT_EQ(0, pointsBack2->backPointer()); | 
| + | 
| +    pointsBack2.release(); | 
| +    Heap::collectGarbage(ThreadState::NoHeapPointersOnStack); | 
| +    EXPECT_EQ(0, PointsBack::s_aliveCount); | 
| +    EXPECT_EQ(0, SuperClass::s_aliveCount); | 
| +    EXPECT_EQ(0, SubClass::s_aliveCount); | 
| +    EXPECT_EQ(0, SubData::s_aliveCount); | 
| + | 
| +    EXPECT_TRUE(superClass == subClass); | 
| +} | 
| + | 
| TEST(HeapTest, Threading) | 
| { | 
| ThreadedHeapTester::test(); | 
| @@ -1427,10 +1614,13 @@ DEFINE_GC_INFO(HeapAllocatedArray); | 
| DEFINE_GC_INFO(HeapTestSuperClass); | 
| DEFINE_GC_INFO(IntWrapper); | 
| DEFINE_GC_INFO(LargeObject); | 
| +DEFINE_GC_INFO(PointsBack); | 
| DEFINE_GC_INFO(RefCountedAndGarbageCollected); | 
| DEFINE_GC_INFO(RefCountedAndGarbageCollected2); | 
| DEFINE_GC_INFO(SimpleFinalizedObject); | 
| DEFINE_GC_INFO(SimpleObject); | 
| +DEFINE_GC_INFO(SuperClass); | 
| +DEFINE_GC_INFO(SubData); | 
| DEFINE_GC_INFO(TestTypedHeapClass); | 
| DEFINE_GC_INFO(TraceCounter); | 
|  | 
|  |