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#include "DirectArgumentsOffset.h"
29#include "ScopeOffset.h"
30#include "VirtualRegister.h"
31#include <wtf/HashMap.h>
32
33namespace JSC {
34
35enum class VarKind : uint8_t {
36 Invalid,
37 Scope,
38 Stack,
39 DirectArgument
40};
41
42class VarOffset {
43public:
44 VarOffset()
45 : m_kind(VarKind::Invalid)
46 , m_offset(UINT_MAX)
47 {
48 }
49
50 VarOffset(WTF::HashTableDeletedValueType)
51 : m_kind(VarKind::Invalid)
52 , m_offset(0)
53 {
54 }
55
56 explicit VarOffset(VirtualRegister stackOffset)
57 {
58 if (!stackOffset.isValid()) {
59 m_kind = VarKind::Invalid;
60 m_offset = UINT_MAX;
61 } else {
62 m_kind = VarKind::Stack;
63 m_offset = stackOffset.offset();
64 }
65 }
66
67 explicit VarOffset(ScopeOffset scopeOffset)
68 {
69 if (!scopeOffset) {
70 m_kind = VarKind::Invalid;
71 m_offset = UINT_MAX;
72 } else {
73 m_kind = VarKind::Scope;
74 m_offset = scopeOffset.offset();
75 }
76 }
77
78 explicit VarOffset(DirectArgumentsOffset capturedArgumentsOffset)
79 {
80 if (!capturedArgumentsOffset) {
81 m_kind = VarKind::Invalid;
82 m_offset = UINT_MAX;
83 } else {
84 m_kind = VarKind::DirectArgument;
85 m_offset = capturedArgumentsOffset.offset();
86 }
87 }
88
89 static VarOffset assemble(VarKind kind, unsigned offset)
90 {
91 VarOffset result;
92 result.m_kind = kind;
93 result.m_offset = offset;
94 result.checkSanity();
95 return result;
96 }
97
98 bool isValid() const
99 {
100 return m_kind != VarKind::Invalid;
101 }
102
103 bool operator!() const
104 {
105 return !isValid();
106 }
107
108 VarKind kind() const { return m_kind; }
109
110 bool isStack() const
111 {
112 return m_kind == VarKind::Stack;
113 }
114
115 bool isScope() const
116 {
117 return m_kind == VarKind::Scope;
118 }
119
120 bool isDirectArgument() const
121 {
122 return m_kind == VarKind::DirectArgument;
123 }
124
125 VirtualRegister stackOffsetUnchecked() const
126 {
127 if (!isStack())
128 return VirtualRegister();
129 return VirtualRegister(m_offset);
130 }
131
132 ScopeOffset scopeOffsetUnchecked() const
133 {
134 if (!isScope())
135 return ScopeOffset();
136 return ScopeOffset(m_offset);
137 }
138
139 DirectArgumentsOffset capturedArgumentsOffsetUnchecked() const
140 {
141 if (!isDirectArgument())
142 return DirectArgumentsOffset();
143 return DirectArgumentsOffset(m_offset);
144 }
145
146 VirtualRegister stackOffset() const
147 {
148 ASSERT(isStack());
149 return VirtualRegister(m_offset);
150 }
151
152 ScopeOffset scopeOffset() const
153 {
154 ASSERT(isScope());
155 return ScopeOffset(m_offset);
156 }
157
158 DirectArgumentsOffset capturedArgumentsOffset() const
159 {
160 ASSERT(isDirectArgument());
161 return DirectArgumentsOffset(m_offset);
162 }
163
164 unsigned rawOffset() const
165 {
166 ASSERT(isValid());
167 return m_offset;
168 }
169
170 void checkSanity() const
171 {
172 if (ASSERT_DISABLED)
173 return;
174
175 switch (m_kind) {
176 case VarKind::Invalid:
177 ASSERT(m_offset == UINT_MAX);
178 return;
179 case VarKind::Scope:
180 ASSERT(scopeOffset());
181 return;
182 case VarKind::Stack:
183 ASSERT(stackOffset().isValid());
184 return;
185 case VarKind::DirectArgument:
186 ASSERT(capturedArgumentsOffset());
187 return;
188 }
189
190 ASSERT_NOT_REACHED();
191 }
192
193 bool operator==(const VarOffset& other) const
194 {
195 return m_kind == other.m_kind
196 && m_offset == other.m_offset;
197 }
198
199 bool operator!=(const VarOffset& other) const
200 {
201 return !(*this == other);
202 }
203
204 unsigned hash() const
205 {
206 return WTF::IntHash<unsigned>::hash((static_cast<unsigned>(m_kind) << 20) + m_offset);
207 }
208
209 bool isHashTableDeletedValue() const
210 {
211 return m_kind == VarKind::Invalid && !m_offset;
212 }
213
214 void dump(PrintStream&) const;
215
216private:
217 VarKind m_kind;
218 unsigned m_offset;
219};
220
221struct VarOffsetHash {
222 static unsigned hash(const VarOffset& key) { return key.hash(); }
223 static bool equal(const VarOffset& a, const VarOffset& b) { return a == b; }
224 static constexpr bool safeToCompareToEmptyOrDeleted = true;
225};
226
227} // namespace JSC
228
229namespace WTF {
230
231void printInternal(PrintStream&, JSC::VarKind);
232
233template<typename T> struct DefaultHash;
234template<> struct DefaultHash<JSC::VarOffset> {
235 typedef JSC::VarOffsetHash Hash;
236};
237
238template<typename T> struct HashTraits;
239template<> struct HashTraits<JSC::VarOffset> : SimpleClassHashTraits<JSC::VarOffset> {
240 static constexpr bool emptyValueIsZero = false;
241};
242
243} // namespace WTF
244