| /* | 
 |  * Copyright (C) 2016-2021 Apple Inc. All rights reserved. | 
 |  * | 
 |  * Redistribution and use in source and binary forms, with or without | 
 |  * modification, are permitted provided that the following conditions | 
 |  * are met: | 
 |  * 1. Redistributions of source code must retain the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer. | 
 |  * 2. Redistributions in binary form must reproduce the above copyright | 
 |  *    notice, this list of conditions and the following disclaimer in the | 
 |  *    documentation and/or other materials provided with the distribution. | 
 |  * | 
 |  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' | 
 |  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, | 
 |  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | 
 |  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS | 
 |  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | 
 |  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | 
 |  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | 
 |  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | 
 |  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | 
 |  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF | 
 |  * THE POSSIBILITY OF SUCH DAMAGE. | 
 |  */ | 
 |  | 
 | #pragma once | 
 |  | 
 | #include "VM.h" | 
 |  | 
 | namespace JSC { | 
 |  | 
 | class JSCell; | 
 | class SlotVisitor; | 
 | class VM; | 
 |  | 
 | // Note that if all you're doing is calling LazyProperty::get(), it's completely safe to bitcast | 
 | // this LazyProperty<JSCell, JSCell>. | 
 | template<typename OwnerType, typename ElementType> | 
 | class LazyProperty { | 
 | public: | 
 |     struct Initializer { | 
 |         Initializer(OwnerType* owner, LazyProperty& property) | 
 |             : vm(Heap::heap(owner)->vm()) | 
 |             , owner(owner) | 
 |             , property(property) | 
 |         { | 
 |         } | 
 |          | 
 |         void set(ElementType* value) const; | 
 |  | 
 |         VM& vm; | 
 |         OwnerType* owner; | 
 |         LazyProperty& property; | 
 |     }; | 
 |  | 
 | private: | 
 |     typedef ElementType* (*FuncType)(const Initializer&); | 
 |  | 
 | public: | 
 |     LazyProperty() | 
 |     { | 
 |     } | 
 |  | 
 |     // Tell the property to run the given callback next time someone tries to get the value | 
 |     // using get(). The passed callback must be stateless. For example: | 
 |     // | 
 |     //     property.initLater( | 
 |     //         [] (const LazyProperty<Foo, Bar>::Initializer& init) { | 
 |     //             init.set(...things...); | 
 |     //         }); | 
 |     // | 
 |     // This method is always inlineable and should always compile to a store of a constant | 
 |     // pointer no matter how complicated the callback is. | 
 |     template<typename Func> | 
 |     void initLater(const Func&); | 
 |  | 
 |     // This lazily initializes the property. Note that this gracefully supports recursive calls. | 
 |     // If this gets called while the property is being initialized, it will simply return null. | 
 |     ElementType* get(const OwnerType* owner) const | 
 |     { | 
 |         ASSERT(!isCompilationThread()); | 
 |         return getInitializedOnMainThread(owner); | 
 |     } | 
 |      | 
 |     ElementType* getConcurrently() const | 
 |     { | 
 |         uintptr_t pointer = m_pointer; | 
 |         if (pointer & lazyTag) | 
 |             return nullptr; | 
 |         return bitwise_cast<ElementType*>(pointer); | 
 |     } | 
 |  | 
 |     ElementType* getInitializedOnMainThread(const OwnerType* owner) const | 
 |     { | 
 |         if (UNLIKELY(m_pointer & lazyTag)) { | 
 |             ASSERT(!isCompilationThread()); | 
 |             FuncType func = *bitwise_cast<FuncType*>(m_pointer & ~(lazyTag | initializingTag)); | 
 |             return func(Initializer(const_cast<OwnerType*>(owner), *const_cast<LazyProperty*>(this))); | 
 |         } | 
 |         return bitwise_cast<ElementType*>(m_pointer); | 
 |     } | 
 |      | 
 |     void setMayBeNull(VM&, const OwnerType* owner, ElementType*); | 
 |     void set(VM&, const OwnerType* owner, ElementType*); | 
 |      | 
 |     template<typename Visitor> void visit(Visitor&); | 
 |      | 
 |     void dump(PrintStream&) const; | 
 |      | 
 | private: | 
 |     template<typename Func> | 
 |     static ElementType* callFunc(const Initializer&); | 
 |      | 
 |     static const uintptr_t lazyTag = 1; | 
 |     static const uintptr_t initializingTag = 2; | 
 |      | 
 |     uintptr_t m_pointer { 0 }; | 
 | }; | 
 |  | 
 | // It's valid to bitcast any LazyProperty to LazyCellProperty if you're just going to call get() | 
 | // or getConcurrently(). | 
 | typedef LazyProperty<JSCell, JSCell> LazyCellProperty; | 
 |  | 
 | } // namespace JSC |