1/*
2 * Copyright (C) 2015-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. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#if ENABLE(DFG_JIT)
29
30#include "DFGCommon.h"
31#include "DFGInsertionSet.h"
32#include <wtf/PrintStream.h>
33
34namespace JSC { namespace DFG {
35
36class LazyNode {
37public:
38 static constexpr size_t jsConstantTag = 0;
39 static constexpr size_t doubleConstantTag = 1;
40 static constexpr size_t int52ConstantTag = 2;
41
42 static constexpr uintptr_t tagMask = 0x3;
43 static constexpr uintptr_t pointerMask = ~tagMask;
44
45 explicit LazyNode(Node* node = nullptr)
46 : m_node(node)
47 , m_value(reinterpret_cast<uintptr_t>(nullptr))
48 {
49 if (node && node->isConstant())
50 setFrozenValue(node->constant(), node->op());
51 }
52
53 explicit LazyNode(FrozenValue* value, NodeType op = JSConstant)
54 : m_node(nullptr)
55 , m_value(reinterpret_cast<uintptr_t>(nullptr))
56 {
57 setFrozenValue(value, op);
58 }
59
60 LazyNode(std::nullptr_t)
61 : m_node(nullptr)
62 , m_value(reinterpret_cast<uintptr_t>(nullptr))
63 {
64 }
65
66 LazyNode(WTF::HashTableDeletedValueType)
67 : m_node(reinterpret_cast<Node*>(-1))
68 {
69 }
70
71 void setNode(Node* node)
72 {
73 m_node = node;
74 if (node && node->isConstant())
75 setFrozenValue(node->constant(), node->op());
76 }
77
78 bool isHashTableDeletedValue() const { return m_node == reinterpret_cast<Node*>(-1); }
79
80 bool isNode() const { return m_node; }
81
82 NodeType op() const
83 {
84 if (m_node)
85 return m_node->op();
86
87 switch (m_value & tagMask) {
88 case jsConstantTag:
89 return JSConstant;
90 case doubleConstantTag:
91 return DoubleConstant;
92 case int52ConstantTag:
93 return Int52Constant;
94 default:
95 RELEASE_ASSERT_NOT_REACHED();
96 }
97 }
98
99 Node* asNode() const
100 {
101 ASSERT(m_node || !asValue());
102 return m_node;
103 }
104
105 FrozenValue* asValue() const
106 {
107 return reinterpret_cast<FrozenValue*>(m_value & pointerMask);
108 }
109
110 unsigned hash() const
111 {
112 void* toHash = m_node;
113 if (FrozenValue* value = asValue())
114 toHash = value;
115 return WTF::PtrHash<void*>::hash(toHash);
116 }
117
118 bool operator==(const LazyNode& other) const
119 {
120 if (asValue() || other.asValue())
121 return m_value == other.m_value;
122 return m_node == other.m_node;
123 }
124
125 bool operator!=(const LazyNode& other) const
126 {
127 return !(*this == other);
128 }
129
130 Node* ensureIsNode(InsertionSet& insertionSet, BasicBlock* block, unsigned nodeIndex)
131 {
132 if (!m_node)
133 m_node = insertionSet.insertConstant(nodeIndex, block->at(nodeIndex)->origin, asValue(), op());
134
135 return asNode();
136 }
137
138 Node* operator->() const { return asNode(); }
139
140 Node& operator*() const { return *asNode(); }
141
142 bool operator!() const { return !asValue() && !asNode(); }
143
144 explicit operator bool() const { return !!*this; }
145
146 void dump(PrintStream& out) const;
147
148private:
149 void setFrozenValue(FrozenValue* value, NodeType op)
150 {
151 ASSERT(value);
152 m_value = reinterpret_cast<uintptr_t>(value);
153 ASSERT(m_value == (m_value & pointerMask));
154 switch (op) {
155 case JSConstant:
156 m_value |= jsConstantTag;
157 break;
158 case DoubleConstant:
159 m_value |= doubleConstantTag;
160 break;
161 case Int52Constant:
162 m_value |= int52ConstantTag;
163 break;
164 default:
165 RELEASE_ASSERT_NOT_REACHED();
166 break;
167 }
168 }
169
170 Node* m_node;
171 uintptr_t m_value;
172};
173
174} } // namespace JSC::DFG
175
176namespace WTF {
177
178template<typename T> struct HashTraits;
179template<> struct HashTraits<JSC::DFG::LazyNode> : SimpleClassHashTraits<JSC::DFG::LazyNode> {
180 static constexpr bool emptyValueIsZero = true;
181};
182
183} // namespace WTF
184
185#endif // ENABLE(DFG_JIT)
186