forked from chakra-core/ChakraCore
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathConcatString.h
More file actions
280 lines (241 loc) · 12.2 KB
/
ConcatString.h
File metadata and controls
280 lines (241 loc) · 12.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
//-------------------------------------------------------------------------------------------------------
// Copyright (C) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
//-------------------------------------------------------------------------------------------------------
#pragma once
namespace Js
{
class LiteralStringWithPropertyStringPtr : public LiteralString
{
private:
PropertyString * propertyString;
public:
PropertyString * GetPropertyString() const;
void SetPropertyString(PropertyString * propStr);
template <typename StringType> static LiteralStringWithPropertyStringPtr * ConvertString(StringType * originalString);
static uint GetOffsetOfPropertyString() { return offsetof(LiteralStringWithPropertyStringPtr, propertyString); }
protected:
LiteralStringWithPropertyStringPtr(StaticType* stringTypeStatic);
DEFINE_VTABLE_CTOR(LiteralStringWithPropertyStringPtr, LiteralString);
DECLARE_CONCRETE_STRING_CLASS;
public:
virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
{
return VTableValue::VtableLiteralStringWithPropertyStringPtr;
}
};
// Base class for concat strings.
// Concat string is a virtual string, or a non-leaf node in concat string tree.
// It does not hold characters by itself but has one or more child nodes.
// Only leaf nodes (which are not concat strings) hold the actual characters.
// The flattening happens on demand (call GetString() or GetSz()),
// until then we don't create actual big char16* buffer, just keep concat tree as a tree.
// The result of flattening the concat string tree is concat of all leaf nodes from left to right.
// Usage pattern:
// // Create concat tree using one of non-abstract derived classes.
// JavascriptString* result = concatTree->GetString(); // At this time we flatten the tree into 1 actual wchat_t* string.
class ConcatStringBase _ABSTRACT : public LiteralString // vtable will be switched to LiteralString's vtable after flattening
{
friend JavascriptString;
private:
bool hasOnlyLiterals;
protected:
ConcatStringBase(StaticType* stringTypeStatic);
DEFINE_VTABLE_CTOR_ABSTRACT(ConcatStringBase, LiteralString);
virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer,
StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) = 0;
void CopyImpl(_Out_writes_(m_charLength) char16 *const buffer,
int itemCount, _In_reads_(itemCount) JavascriptString * const * items,
StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth);
// Subclass can call this to implement GetSz and use the actual type to avoid virtual call to Copy.
template <typename ConcatStringType> const char16 * GetSzImpl();
public:
virtual const char16* GetSz() = 0; // Force subclass to call GetSzImpl with the real type to avoid virtual calls
using JavascriptString::Copy;
virtual bool IsTree() const override sealed;
bool HasOnlyLiterals()
{
return hasOnlyLiterals;
}
void SetHasNonLiteral()
{
hasOnlyLiterals = false;
}
};
// Concat string with N (or less) child nodes.
// Use it when you know the number of children at compile time.
// There could be less nodes than N. When we find 1st NULL node going incrementing the index,
// we see this as indication that the rest on the right are empty and stop iterating.
// Usage pattern:
// ConcatStringN<3>* tree = ConcatStringN<3>::New(scriptContext);
// tree->SetItem(0, javascriptString1);
// tree->SetItem(1, javascriptString2);
// tree->SetItem(2, javascriptString3);
template <int N>
class ConcatStringN : public ConcatStringBase
{
friend JavascriptString;
protected:
ConcatStringN(StaticType* stringTypeStatic, bool doZeroSlotsAndLength = true);
DEFINE_VTABLE_CTOR(ConcatStringN<N>, ConcatStringBase);
DECLARE_CONCRETE_STRING_CLASS;
virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override
{
__super::CopyImpl(buffer, N, AddressOf(m_slots[0]), nestedStringTreeCopyInfos, recursionDepth);
}
virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const
{
items = AddressOf(m_slots[0]);
return N;
}
public:
static ConcatStringN<N>* New(ScriptContext* scriptContext);
const char16 * GetSz() override sealed;
void SetItem(_In_range_(0, N - 1) int index, JavascriptString* value);
protected:
Field(JavascriptString*) m_slots[N]; // These contain the child nodes. 1 slot is per 1 item (JavascriptString*).
};
// Concat string that uses binary tree, each node has 2 children.
// Usage pattern:
// ConcatString* str = ConcatString::New(javascriptString1, javascriptString2);
// Note: it's preferred you would use the following for concats, that would figure out whether concat string is optimal or create a new string is better.
// JavascriptString::Concat(javascriptString1, javascriptString2);
class ConcatString sealed : public ConcatStringN<2>
{
ConcatString(JavascriptString* a, JavascriptString* b);
protected:
DEFINE_VTABLE_CTOR(ConcatString, ConcatStringN<2>);
DECLARE_CONCRETE_STRING_CLASS;
public:
static ConcatString* New(JavascriptString* a, JavascriptString* b);
static const int MaxDepth = 1000;
JavascriptString *LeftString() const { Assert(!IsFinalized()); return m_slots[0]; }
JavascriptString *RightString() const { Assert(!IsFinalized()); return m_slots[1]; }
};
// Concat string with any number of child nodes, can grow dynamically.
// Usage pattern:
// ConcatStringBuilder* tree = ConcatStringBuider::New(scriptContext, 5);
// tree->Append(javascriptString1);
// tree->Append(javascriptString2);
// ...
// Implementation details:
// - uses chunks, max chunk size is specified by c_maxChunkSlotCount, until we fit into that, we realloc, otherwise create new chunk.
// - We use chunks in order to avoid big allocations, we don't expect lots of reallocs, that why chunk size is relatively big.
// - the chunks are linked using m_prevChunk field. flattening happens from left to right, i.e. first we need to get
// head chunk -- the one that has m_prevChunk == NULL.
class ConcatStringBuilder sealed : public ConcatStringBase
{
friend JavascriptString;
ConcatStringBuilder(ScriptContext* scriptContext, int initialSlotCount);
ConcatStringBuilder(const ConcatStringBuilder& other);
void AllocateSlots(int requestedSlotCount);
ConcatStringBuilder* GetHead() const;
protected:
DEFINE_VTABLE_CTOR(ConcatStringBuilder, ConcatStringBase);
DECLARE_CONCRETE_STRING_CLASS;
virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override sealed;
public:
static ConcatStringBuilder* New(ScriptContext* scriptContext, int initialSlotCount);
const char16 * GetSz() override sealed;
void Append(JavascriptString* str);
private:
// MAX number of slots in one chunk. Until we fit into this, we realloc, otherwise create new chunk.
static const int c_maxChunkSlotCount = 1024;
int GetItemCount() const;
Field(Field(JavascriptString*)*) m_slots; // Array of child nodes.
Field(int) m_slotCount; // Number of allocated slots (1 slot holds 1 item) in this chunk.
Field(int) m_count; // Actual number of items in this chunk.
Field(ConcatStringBuilder*) m_prevChunk;
};
// Concat string that wraps another string.
// Use it when you need to wrap something with e.g. { and }.
// Usage pattern:
// result = ConcatStringWrapping<_u('{'), _u('}')>::New(result);
template <char16 L, char16 R>
class ConcatStringWrapping sealed : public ConcatStringBase
{
friend JavascriptString;
ConcatStringWrapping(JavascriptString* inner);
JavascriptString* GetFirstItem() const;
JavascriptString* GetLastItem() const;
protected:
DEFINE_VTABLE_CTOR(ConcatStringWrapping, ConcatStringBase);
DECLARE_CONCRETE_STRING_CLASS;
virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override sealed
{
const_cast<ConcatStringWrapping *>(this)->EnsureAllSlots();
__super::CopyImpl(buffer, _countof(m_slots), AddressOf(m_slots[0]), nestedStringTreeCopyInfos, recursionDepth);
}
virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const override sealed
{
const_cast<ConcatStringWrapping *>(this)->EnsureAllSlots();
items = AddressOf(m_slots[0]);
return _countof(m_slots);
}
public:
static ConcatStringWrapping<L, R>* New(JavascriptString* inner);
const char16 * GetSz() override sealed;
private:
void EnsureAllSlots()
{
m_slots[0] = this->GetFirstItem();
m_slots[1] = m_inner;
m_slots[2] = this->GetLastItem();
}
Field(JavascriptString *) m_inner;
// Use the padding space for the concat
Field(JavascriptString *) m_slots[3];
};
// Make sure the padding doesn't add tot he size of ConcatStringWrapping
#if defined(_M_X64_OR_ARM64)
CompileAssert(sizeof(ConcatStringWrapping<_u('"'), _u('"')>) == 64);
#else
CompileAssert(sizeof(ConcatStringWrapping<_u('"'), _u('"')>) == 32);
#endif
// Concat string with N child nodes. Use it when you don't know the number of children at compile time.
// Usage pattern:
// ConcatStringMulti* tree = ConcatStringMulti::New(3, scriptContext);
// tree->SetItem(0, javascriptString1);
// tree->SetItem(1, javascriptString2);
// tree->SetItem(2, javascriptString3);
class ConcatStringMulti sealed : public ConcatStringBase
{
friend JavascriptString;
protected:
ConcatStringMulti(uint slotCount, JavascriptString * a1, JavascriptString * a2, StaticType* stringTypeStatic);
DEFINE_VTABLE_CTOR(ConcatStringMulti, ConcatStringBase);
DECLARE_CONCRETE_STRING_CLASS;
virtual void CopyVirtual(_Out_writes_(m_charLength) char16 *const buffer, StringCopyInfoStack &nestedStringTreeCopyInfos, const byte recursionDepth) override
{
Assert(IsFilled());
__super::CopyImpl(buffer, slotCount, AddressOf(m_slots[0]), nestedStringTreeCopyInfos, recursionDepth);
}
virtual int GetRandomAccessItemsFromConcatString(Js::JavascriptString * const *& items) const
{
Assert(IsFilled());
items = AddressOf(m_slots[0]);
return slotCount;
}
public:
static ConcatStringMulti * New(uint slotCount, JavascriptString * a1, JavascriptString * a2, ScriptContext* scriptContext);
const char16 * GetSz() override sealed;
static bool Is(Var var);
static ConcatStringMulti * FromVar(Var value);
static size_t GetAllocSize(uint slotCount);
void SetItem(_In_range_(0, slotCount - 1) uint index, JavascriptString* value);
static uint32 GetOffsetOfSlotCount() { return offsetof(ConcatStringMulti, slotCount); }
static uint32 GetOffsetOfSlots() { return offsetof(ConcatStringMulti, m_slots); }
protected:
Field(uint) slotCount;
Field(uint) __alignment;
Field(JavascriptString*) m_slots[]; // These contain the child nodes.
#if DBG
bool IsFilled() const;
#endif
public:
virtual VTableValue DummyVirtualFunctionToHinderLinkerICF()
{
return VTableValue::VtableConcatStringMulti;
}
};
}