1/*
2 * Copyright (C) 2016 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 "Heap.h"
29#include <wtf/StdLibExtras.h>
30
31namespace JSC {
32
33template<typename OwnerType, typename ElementType>
34void LazyProperty<OwnerType, ElementType>::Initializer::set(ElementType* value) const
35{
36 property.set(vm, owner, value);
37}
38
39template<typename OwnerType, typename ElementType>
40template<typename Func>
41void LazyProperty<OwnerType, ElementType>::initLater(const Func&)
42{
43 RELEASE_ASSERT(isStatelessLambda<Func>());
44 // Logically we just want to stuff the function pointer into m_pointer, but then we'd be sad
45 // because a function pointer is not guaranteed to be a multiple of anything. The tag bits
46 // may be used for things. We address this problem by indirecting through a global const
47 // variable. The "theFunc" variable is guaranteed to be native-aligned, i.e. at least a
48 // multiple of 4.
49 static const FuncType theFunc = callFunc<Func>;
50 m_pointer = lazyTag | bitwise_cast<uintptr_t>(&theFunc);
51}
52
53template<typename OwnerType, typename ElementType>
54void LazyProperty<OwnerType, ElementType>::setMayBeNull(VM& vm, const OwnerType* owner, ElementType* value)
55{
56 vm.heap.writeBarrier(owner, value);
57 m_pointer = bitwise_cast<uintptr_t>(value);
58 RELEASE_ASSERT(!(m_pointer & lazyTag));
59}
60
61template<typename OwnerType, typename ElementType>
62void LazyProperty<OwnerType, ElementType>::set(VM& vm, const OwnerType* owner, ElementType* value)
63{
64 RELEASE_ASSERT(value);
65 setMayBeNull(vm, owner, value);
66}
67
68template<typename OwnerType, typename ElementType>
69void LazyProperty<OwnerType, ElementType>::visit(SlotVisitor& visitor)
70{
71 if (m_pointer && !(m_pointer & lazyTag))
72 visitor.appendUnbarriered(bitwise_cast<ElementType*>(m_pointer));
73}
74
75template<typename OwnerType, typename ElementType>
76void LazyProperty<OwnerType, ElementType>::dump(PrintStream& out) const
77{
78 if (!m_pointer) {
79 out.print("<null>");
80 return;
81 }
82 if (m_pointer & lazyTag) {
83 out.print("Lazy:", RawPointer(bitwise_cast<void*>(m_pointer & ~lazyTag)));
84 if (m_pointer & initializingTag)
85 out.print("(Initializing)");
86 return;
87 }
88 out.print(RawPointer(bitwise_cast<void*>(m_pointer)));
89}
90
91template<typename OwnerType, typename ElementType>
92template<typename Func>
93ElementType* LazyProperty<OwnerType, ElementType>::callFunc(const Initializer& initializer)
94{
95 if (initializer.property.m_pointer & initializingTag)
96 return nullptr;
97 initializer.property.m_pointer |= initializingTag;
98 callStatelessLambda<void, Func>(initializer);
99 RELEASE_ASSERT(!(initializer.property.m_pointer & lazyTag));
100 RELEASE_ASSERT(!(initializer.property.m_pointer & initializingTag));
101 return bitwise_cast<ElementType*>(initializer.property.m_pointer);
102}
103
104} // namespace JSC
105