1 | /* |
2 | * Copyright (C) 2016-2019 Apple Inc. All rights reserved. |
3 | * |
4 | * Redistribution and use in source and binary forms, with or without |
5 | * modification, are permitted provided that the following conditions |
6 | * are met: |
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. |
12 | * |
13 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' |
14 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
15 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
16 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS |
17 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
18 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
19 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
20 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
21 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
22 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
23 | * THE POSSIBILITY OF SUCH DAMAGE. |
24 | */ |
25 | |
26 | #pragma once |
27 | |
28 | #include "VM.h" |
29 | |
30 | namespace JSC { |
31 | |
32 | class JSCell; |
33 | class SlotVisitor; |
34 | class VM; |
35 | |
36 | // Note that if all you're doing is calling LazyProperty::get(), it's completely safe to bitcast |
37 | // this LazyProperty<JSCell, JSCell>. |
38 | template<typename OwnerType, typename ElementType> |
39 | class LazyProperty { |
40 | public: |
41 | struct Initializer { |
42 | Initializer(OwnerType* owner, LazyProperty& property) |
43 | : vm(Heap::heap(owner)->vm()) |
44 | , owner(owner) |
45 | , property(property) |
46 | { |
47 | } |
48 | |
49 | void set(ElementType* value) const; |
50 | |
51 | VM& vm; |
52 | OwnerType* owner; |
53 | LazyProperty& property; |
54 | }; |
55 | |
56 | private: |
57 | typedef ElementType* (*FuncType)(const Initializer&); |
58 | |
59 | public: |
60 | LazyProperty() |
61 | { |
62 | } |
63 | |
64 | // Tell the property to run the given callback next time someone tries to get the value |
65 | // using get(). The passed callback must be stateless. For example: |
66 | // |
67 | // property.initLater( |
68 | // [] (const LazyProperty<Foo, Bar>::Initializer& init) { |
69 | // init.set(...things...); |
70 | // }); |
71 | // |
72 | // This method is always inlineable and should always compile to a store of a constant |
73 | // pointer no matter how complicated the callback is. |
74 | template<typename Func> |
75 | void initLater(const Func&); |
76 | |
77 | // This lazily initializes the property. Note that this gracefully supports recursive calls. |
78 | // If this gets called while the property is being initialized, it will simply return null. |
79 | ElementType* get(const OwnerType* owner) const |
80 | { |
81 | ASSERT(!isCompilationThread()); |
82 | return getInitializedOnMainThread(owner); |
83 | } |
84 | |
85 | ElementType* getConcurrently() const |
86 | { |
87 | uintptr_t pointer = m_pointer; |
88 | if (pointer & lazyTag) |
89 | return nullptr; |
90 | return bitwise_cast<ElementType*>(pointer); |
91 | } |
92 | |
93 | ElementType* getInitializedOnMainThread(const OwnerType* owner) const |
94 | { |
95 | if (UNLIKELY(m_pointer & lazyTag)) { |
96 | ASSERT(!isCompilationThread()); |
97 | FuncType func = *bitwise_cast<FuncType*>(m_pointer & ~(lazyTag | initializingTag)); |
98 | return func(Initializer(const_cast<OwnerType*>(owner), *const_cast<LazyProperty*>(this))); |
99 | } |
100 | return bitwise_cast<ElementType*>(m_pointer); |
101 | } |
102 | |
103 | void setMayBeNull(VM&, const OwnerType* owner, ElementType*); |
104 | void set(VM&, const OwnerType* owner, ElementType*); |
105 | |
106 | void visit(SlotVisitor&); |
107 | |
108 | void dump(PrintStream&) const; |
109 | |
110 | private: |
111 | template<typename Func> |
112 | static ElementType* callFunc(const Initializer&); |
113 | |
114 | static const uintptr_t lazyTag = 1; |
115 | static const uintptr_t initializingTag = 2; |
116 | |
117 | uintptr_t m_pointer { 0 }; |
118 | }; |
119 | |
120 | // It's valid to bitcast any LazyProperty to LazyCellProperty if you're just going to call get() |
121 | // or getConcurrently(). |
122 | typedef LazyProperty<JSCell, JSCell> LazyCellProperty; |
123 | |
124 | } // namespace JSC |
125 | |