1/*
2 * Copyright (C) 2015-2016 Yusuke Suzuki <utatane.tea@gmail.com>.
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 <wtf/text/UniquedStringImpl.h>
29
30namespace WTF {
31
32class RegisteredSymbolImpl;
33
34// SymbolImpl is used to represent the symbol string impl.
35// It is uniqued string impl, but is not registered in Atomic String tables, so it's not atomic.
36class SymbolImpl : public UniquedStringImpl {
37public:
38 using Flags = unsigned;
39 static constexpr Flags s_flagDefault = 0u;
40 static constexpr Flags s_flagIsNullSymbol = 0b001u;
41 static constexpr Flags s_flagIsRegistered = 0b010u;
42 static constexpr Flags s_flagIsPrivate = 0b100u;
43
44 unsigned hashForSymbol() const { return m_hashForSymbol; }
45 bool isNullSymbol() const { return m_flags & s_flagIsNullSymbol; }
46 bool isRegistered() const { return m_flags & s_flagIsRegistered; }
47 bool isPrivate() const { return m_flags & s_flagIsPrivate; }
48
49 SymbolRegistry* symbolRegistry() const;
50
51 RegisteredSymbolImpl* asRegisteredSymbolImpl();
52
53 WTF_EXPORT_PRIVATE static Ref<SymbolImpl> createNullSymbol();
54 WTF_EXPORT_PRIVATE static Ref<SymbolImpl> create(StringImpl& rep);
55
56 class StaticSymbolImpl : private StringImplShape {
57 WTF_MAKE_NONCOPYABLE(StaticSymbolImpl);
58 public:
59 template<unsigned characterCount>
60 constexpr StaticSymbolImpl(const char (&characters)[characterCount], Flags flags = s_flagDefault)
61 : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
62 s_hashFlag8BitBuffer | s_hashFlagDidReportCost | StringSymbol | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
63 , m_hashForSymbol(StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount)
64 , m_flags(flags)
65 {
66 }
67
68 template<unsigned characterCount>
69 constexpr StaticSymbolImpl(const char16_t (&characters)[characterCount], Flags flags = s_flagDefault)
70 : StringImplShape(s_refCountFlagIsStaticString, characterCount - 1, characters,
71 s_hashFlagDidReportCost | StringSymbol | BufferInternal | (StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount), ConstructWithConstExpr)
72 , m_hashForSymbol(StringHasher::computeLiteralHashAndMaskTop8Bits(characters) << s_flagCount)
73 , m_flags(flags)
74 {
75 }
76
77 operator SymbolImpl&()
78 {
79 return *reinterpret_cast<SymbolImpl*>(this);
80 }
81
82 StringImpl* m_owner { nullptr }; // We do not make StaticSymbolImpl BufferSubstring. Thus we can make this nullptr.
83 unsigned m_hashForSymbol;
84 Flags m_flags;
85 };
86
87protected:
88 WTF_EXPORT_PRIVATE static unsigned nextHashForSymbol();
89
90 friend class StringImpl;
91
92 SymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base, Flags flags = s_flagDefault)
93 : UniquedStringImpl(CreateSymbol, characters, length)
94 , m_owner(&base.leakRef())
95 , m_hashForSymbol(nextHashForSymbol())
96 , m_flags(flags)
97 {
98 ASSERT(StringImpl::tailOffset<StringImpl*>() == OBJECT_OFFSETOF(SymbolImpl, m_owner));
99 }
100
101 SymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base, Flags flags = s_flagDefault)
102 : UniquedStringImpl(CreateSymbol, characters, length)
103 , m_owner(&base.leakRef())
104 , m_hashForSymbol(nextHashForSymbol())
105 , m_flags(flags)
106 {
107 ASSERT(StringImpl::tailOffset<StringImpl*>() == OBJECT_OFFSETOF(SymbolImpl, m_owner));
108 }
109
110 SymbolImpl(Flags flags = s_flagDefault)
111 : UniquedStringImpl(CreateSymbol)
112 , m_owner(StringImpl::empty())
113 , m_hashForSymbol(nextHashForSymbol())
114 , m_flags(flags | s_flagIsNullSymbol)
115 {
116 ASSERT(StringImpl::tailOffset<StringImpl*>() == OBJECT_OFFSETOF(SymbolImpl, m_owner));
117 }
118
119 // The pointer to the owner string should be immediately following after the StringImpl layout,
120 // since we would like to align the layout of SymbolImpl to the one of BufferSubstring StringImpl.
121 StringImpl* m_owner;
122 unsigned m_hashForSymbol;
123 Flags m_flags { s_flagDefault };
124};
125static_assert(sizeof(SymbolImpl) == sizeof(SymbolImpl::StaticSymbolImpl), "");
126
127class PrivateSymbolImpl : public SymbolImpl {
128public:
129 WTF_EXPORT_PRIVATE static Ref<PrivateSymbolImpl> createNullSymbol();
130 WTF_EXPORT_PRIVATE static Ref<PrivateSymbolImpl> create(StringImpl& rep);
131
132private:
133 PrivateSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base)
134 : SymbolImpl(characters, length, WTFMove(base), s_flagIsPrivate)
135 {
136 }
137
138 PrivateSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base)
139 : SymbolImpl(characters, length, WTFMove(base), s_flagIsPrivate)
140 {
141 }
142
143 PrivateSymbolImpl()
144 : SymbolImpl(s_flagIsPrivate)
145 {
146 }
147};
148
149class RegisteredSymbolImpl : public SymbolImpl {
150private:
151 friend class StringImpl;
152 friend class SymbolImpl;
153 friend class SymbolRegistry;
154
155 SymbolRegistry* symbolRegistry() const { return m_symbolRegistry; }
156 void clearSymbolRegistry() { m_symbolRegistry = nullptr; }
157
158 static Ref<RegisteredSymbolImpl> create(StringImpl& rep, SymbolRegistry&);
159
160 RegisteredSymbolImpl(const LChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
161 : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
162 , m_symbolRegistry(&registry)
163 {
164 }
165
166 RegisteredSymbolImpl(const UChar* characters, unsigned length, Ref<StringImpl>&& base, SymbolRegistry& registry)
167 : SymbolImpl(characters, length, WTFMove(base), s_flagIsRegistered)
168 , m_symbolRegistry(&registry)
169 {
170 }
171
172 SymbolRegistry* m_symbolRegistry;
173};
174
175inline unsigned StringImpl::symbolAwareHash() const
176{
177 if (isSymbol())
178 return static_cast<const SymbolImpl*>(this)->hashForSymbol();
179 return hash();
180}
181
182inline unsigned StringImpl::existingSymbolAwareHash() const
183{
184 if (isSymbol())
185 return static_cast<const SymbolImpl*>(this)->hashForSymbol();
186 return existingHash();
187}
188
189inline SymbolRegistry* SymbolImpl::symbolRegistry() const
190{
191 if (isRegistered())
192 return static_cast<const RegisteredSymbolImpl*>(this)->symbolRegistry();
193 return nullptr;
194}
195
196inline RegisteredSymbolImpl* SymbolImpl::asRegisteredSymbolImpl()
197{
198 ASSERT(isRegistered());
199 return static_cast<RegisteredSymbolImpl*>(this);
200}
201
202#if !ASSERT_DISABLED
203// SymbolImpls created from StaticStringImpl will ASSERT
204// in the generic ValueCheck<T>::checkConsistency
205// as they are not allocated by fastMalloc.
206// We don't currently have any way to detect that case
207// so we ignore the consistency check for all SymbolImpls*.
208template<> struct
209ValueCheck<SymbolImpl*> {
210 static void checkConsistency(const SymbolImpl*) { }
211};
212
213template<> struct
214ValueCheck<const SymbolImpl*> {
215 static void checkConsistency(const SymbolImpl*) { }
216};
217#endif
218
219} // namespace WTF
220
221using WTF::SymbolImpl;
222using WTF::PrivateSymbolImpl;
223using WTF::RegisteredSymbolImpl;
224