forked from facebook/hhvm
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstring-data.h
More file actions
656 lines (565 loc) · 20 KB
/
Copy pathstring-data.h
File metadata and controls
656 lines (565 loc) · 20 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
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
/*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-present Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_STRING_DATA_H_
#define incl_HPHP_STRING_DATA_H_
#include <folly/Range.h>
#include "hphp/util/alloc.h"
#include "hphp/util/bstring.h"
#include "hphp/util/hash.h"
#include "hphp/util/word-mem.h"
#include "hphp/runtime/base/countable.h"
#include "hphp/runtime/base/datatype.h"
#include "hphp/runtime/base/exceptions.h"
#include "hphp/runtime/base/memory-manager.h"
#include "hphp/runtime/base/string-data-macros.h"
namespace HPHP {
//////////////////////////////////////////////////////////////////////
struct APCString;
struct Array;
struct String;
struct APCHandle;
//////////////////////////////////////////////////////////////////////
// Copy the passed-in string and free the buffer immediately.
enum AttachStringMode { AttachString };
// const char* points to client-owned memory, StringData will copy it
// at construct-time using req::malloc. This is only ok when the StringData
// itself was request-allocated.
enum CopyStringMode { CopyString };
/*
* Runtime representation of PHP strings.
*
* StringData's have two different modes, not all of which we want to
* keep forever. The main mode is Flat, which means StringData is a
* header in a contiguous allocation with the character array for the
* string. The other (Proxy) is for APCString-backed StringDatas.
*
* StringDatas can also be allocated in multiple ways. Normally, they
* are created through one of the Make overloads, which drops them in
* the request-local heap. They can also be low-malloced (for static
* strings), or uncounted-malloced for APC shared or uncounted strings.
*
* Here's a breakdown of string modes, and which configurations are
* allowed in which allocation mode:
*
* | Static | Malloced | Normal (request local)
* +--------+----------+-----------------------
* Flat | X | X | X
* Proxy | | | X
*/
struct StringData final : MaybeCountable,
type_scan::MarkCollectable<StringData> {
friend struct APCString;
friend StringData* allocFlat(size_t len);
/*
* Max length of a string, not counting the terminal 0.
*
* This is smaller than MAX_INT, and it plus StringData overhead should
* exactly equal a size class.
*/
#ifdef NO_M_DATA
static constexpr uint32_t MaxSize = 0x80000000U - 16 - 1;
#else
static constexpr uint32_t MaxSize = 0x80000000U - 24 - 1;
#endif
/*
* Creates an empty request-local string with an unspecified amount of
* reserved space. Ref-count is pre-initialized to 1.
*/
static StringData* Make();
/*
* Constructors that copy the string memory into this StringData, for
* request-local strings. Ref-count is pre-initialized to 1.
*
* Most strings are created this way.
*/
static StringData* Make(folly::StringPiece);
static StringData* Make(const char* data, CopyStringMode);
static StringData* Make(const char* data, size_t len, CopyStringMode);
static StringData* Make(const StringData* s, CopyStringMode);
static StringData* Make(folly::StringPiece r1, CopyStringMode);
/*
* Attach constructors for request-local strings.
*
* These do the same thing as the above CopyStringMode constructors, except
* that it will also free `data'. Ref-count is pre-initialized to 1.
*/
static StringData* Make(char* data, AttachStringMode);
static StringData* Make(char* data, size_t len, AttachStringMode);
/*
* Create a new request-local string by concatenating two existing
* strings. Ref-count is pre-initialized to 1.
*/
static StringData* Make(const StringData* s1, const StringData* s2);
static StringData* Make(const StringData* s1, folly::StringPiece s2);
static StringData* Make(const StringData* s1, const char* lit2);
static StringData* Make(folly::StringPiece s1, const char* lit2);
static StringData* Make(folly::StringPiece s1, folly::StringPiece s2);
static StringData* Make(folly::StringPiece s1, folly::StringPiece s2,
folly::StringPiece s3);
static StringData* Make(folly::StringPiece s1, folly::StringPiece s2,
folly::StringPiece s3, folly::StringPiece s4);
/*
* Create a new request-local empty string big enough to hold strings of
* length `reserve' (not counting the \0 terminator). Ref-count is
* pre-initialized to 1.
*/
static StringData* Make(size_t reserve);
/*
* Create a request-local "Proxy" StringData that wraps an APCString.
* Ref-count is pre-initialized to 1.
*/
static StringData* MakeProxy(const APCString* apcstr);
/*
* Allocate a string with malloc, using the low-memory allocator if
* jemalloc is available, and setting it as a static string.
*
* This api is only for the static-string-table.cpp. The returned
* StringData is not expected to be reference counted, and must be
* deallocated using destructStatic.
*/
static StringData* MakeStatic(folly::StringPiece);
/*
* Same as MakeStatic but the string allocated will *not* be in the static
* string table, will not be in low-memory, and should be deleted using
* ReleaseUncounted once the root goes out of scope.
*/
static StringData* MakeUncounted(folly::StringPiece);
/*
* Same as MakeStatic but initializes the empty string in aligned storage.
* This should be called by the static string table initialization code.
*/
static StringData* MakeEmpty();
/*
* return estimated capacity for a string of the given size, due to
* size-class rounding.
*/
static size_t estimateCap(size_t size);
/*
* Offset accessors for the JIT compiler.
*/
#ifndef NO_M_DATA
static constexpr ptrdiff_t dataOff() { return offsetof(StringData, m_data); }
#endif
static constexpr ptrdiff_t sizeOff() { return offsetof(StringData, m_len); }
static constexpr ptrdiff_t hashOff() { return offsetof(StringData, m_hash); }
/*
* Proxy StringData's have a sweep list running through them for
* decrefing the APCString they are fronting. This function
* must be called at request cleanup time to handle this.
*/
static unsigned sweepAll();
/*
* Called to return a StringData to the request allocator. This is
* normally called when the reference count goes to zero (e.g. with
* a helper like decRefStr).
*/
void release() noexcept;
size_t heapSize() const;
/*
* StringData objects allocated with MakeStatic should be freed
* using this function.
*/
void destructStatic();
/*
* StringData objects allocated with MakeUncounted should be freed
* using this function. It will remove a reference via
* uncountedDecRef, and if necessary destroy the StringData and
* return true.
*/
static void ReleaseUncounted(const StringData*);
/*
* Reference-counting related.
*/
ALWAYS_INLINE void decRefAndRelease() {
assertx(kindIsValid());
if (decReleaseCheck()) release();
}
bool kindIsValid() const { return m_kind == HeaderKind::String; }
/*
* Append the supplied range to this string. If there is not sufficient
* capacity in this string to contain the range, a new string may be
* returned. The new string's reference count will be pre-initialized to 1.
*
* Pre: !hasMultipleRefs()
* Pre: the string is request-local
*/
StringData* append(folly::StringPiece r);
StringData* append(folly::StringPiece r1, folly::StringPiece r2);
StringData* append(folly::StringPiece r1,
folly::StringPiece r2,
folly::StringPiece r3);
/*
* Reserve space for a string of length `maxLen' (not counting null
* terminator).
*
* May not be called for strings created with MakeUncounted or
* MakeStatic.
*
* Returns: possibly a new StringData, if we had to reallocate. The new
* string's reference count will be pre-initialized to 1.
*/
StringData* reserve(size_t maxLen);
/*
* Shrink a string down to length `len` (not counting null terminator).
*
* May not be called for strings created with MakeUncounted or
* MakeStatic.
*
* Returns: possibly a new StringData, if we decided to reallocate. The new
* string's reference count is be pre-initialized to 1. shrinkImpl
* always returns a new StringData.
*/
StringData* shrink(size_t len);
StringData* shrinkImpl(size_t len);
/*
* Returns a slice with extents sized to the *string* that this
* StringData wraps. This range does not include a null terminator.
*
* Note: please do not add new code that assumes the range does
* include a null-terminator if possible. (We would like to make
* this unnecessary eventually.)
*/
folly::StringPiece slice() const;
/*
* Returns a mutable slice with extents sized to the *buffer* this
* StringData wraps, not the string, minus space for an implicit
* null terminator.
*
* Note: please do not introduce new uses of this API that write
* nulls 1 byte past slice.len---we want to weed those out.
*/
folly::MutableStringPiece bufferSlice();
/*
* If external users of this object want to modify it (e.g. through
* bufferSlice or mutableData()), they are responsible for either
* calling setSize() if the mutation changed the size of the string,
* or invalidateHash() if not.
*
* Pre: !hasMultipleRefs()
*/
void invalidateHash();
void setSize(int len);
/*
* StringData should not generally be allocated on the stack,
* because references to it could escape. This function is for
* debugging: it asserts that the addres of this doesn't point into
* the C++ stack.
*/
void checkStack() const;
/*
* Access to the string's data as a null-terminated character array.
*
* Please try to prefer slice() in new code.
*
* The following extensions depend on the null terminator for correctness,
* and the lack of implicit copying (not perfect for Strings, but
* best-effort):
*
* - libsodium
* - mcrypt
* - openssl
*/
const char* data() const;
/*
* Mutable version of data().
*/
char* mutableData() const;
/*
* Accessor for the length of a string.
*
* Note: size() returns a signed int for historical reasons. It is
* guaranteed to be in the range (0 <= size() <= MaxSize)
*/
int size() const;
/*
* Returns: size() == 0
*/
bool empty() const;
/*
* Return the capacity of this string's buffer, not including the space
* for the null terminator. Always 0 for static/uncounted strings.
*/
uint32_t capacity() const;
/*
* Simultaneously query whether this string is numeric, and pull out
* the numeric value of the string (as either an int or a double).
*
* The allow_errors flag is a boolean that does something currently
* undocumented.
*
* If overflow is set its value is initialized to either zero to
* indicate that no overflow occurred or 1/-1 to inidicate the direction
* of overflow.
*
* Returns: KindOfNull, KindOfInt64 or KindOfDouble. The int64_t or
* double out reference params are populated in the latter two cases
* with the numeric value of the string. The KindOfNull case
* indicates the string is not numeric.
*/
DataType isNumericWithVal(int64_t&, double&, int allowErrors,
int* overflow = nullptr) const;
/*
* Returns true if this string is numeric.
*
* In effect: isNumericWithVal(i, d, false) != KindOfNull
*/
bool isNumeric() const;
/*
* Returns whether this string is numeric and an integer.
*
* In effect: isNumericWithVal(i, d, false) == KindOfInt64
*/
bool isInteger() const;
/*
* Returns true if this string is "strictly" an integer in the sense
* of is_strictly_integer from util/hash.h, and if so provides the
* integer value in res.
*/
bool isStrictlyInteger(int64_t& res) const;
/*
* Returns whether this string contains a single character '0'.
*/
bool isZero() const;
/*
* Change the character at offset `offset' to `c'.
*
* May return a reallocated StringData* if this string was a shared
* string. The new string's reference count is pre-initialized to 1.
*
* Pre: offset >= 0 && offset < size()
* !hasMultipleRefs()
* string must be request local
*/
StringData* modifyChar(int offset, char c);
/*
* Return a string containing the character at `offset', if it is in
* range. Otherwise raises a warning and returns an empty string.
*
* All return values are guaranteed to be static strings.
*/
StringData* getChar(int offset) const;
/*
* Increment this string in the manner of php's ++ operator. May return a new
* string if it had to resize. The new string's reference count is
* pre-initialized to 1.
*
* Pre: !isStatic() && !isEmpty()
* string must be request local
*/
StringData* increment();
/*
* Type conversion functions.
*/
bool toBoolean() const;
char toByte(int base = 10) const { return toInt64(base); }
short toInt16(int base = 10) const { return toInt64(base); }
int toInt32(int base = 10) const { return toInt64(base); }
int64_t toInt64(int base = 10) const;
double toDouble() const;
DataType toNumeric(int64_t& lval, double& dval) const;
std::string toCppString() const;
/*
* Returns: case insensitive hash value for this string.
*/
strhash_t hash() const;
NEVER_INLINE strhash_t hashHelper() const;
static strhash_t hash(const char* s, size_t len);
static strhash_t hash_unsafe(const char* s, size_t len);
/*
* Equality comparison, in the sense of php's string == operator.
* (I.e. numeric strings are compared numerically.)
*/
bool equal(const StringData* s) const;
/*
* Exact comparison, in the sense of php's string === operator.
* (Exact, case-sensitive comparison.)
*/
bool same(const StringData* s) const;
/*
* Case-insensitive exact string comparison. (Numeric strings are
* not treated specially.)
*/
bool isame(const StringData* s) const;
/*
* Implements comparison in the sense of php's operator < on
* strings. (I.e. this compares numeric strings numerically, and
* other strings lexicographically.)
*
* Returns: a number less than zero if *this is less than *v2,
* greater than zero if *this is greater than *v2, or zero if
* this->equal(v2).
*/
int compare(const StringData* v2) const;
/*
* Create a sub-string from start with specified length.
*
* If the start is outside the bounds of the string, or the length is
* negative, the empty string is returned. The range [start, start+length]
* gets clamped to [start, size()].
*/
StringData* substr(int start, int length = StringData::MaxSize);
/*
* Debug dumping of a StringData to stdout.
*/
void dump() const;
static StringData* node2str(StringDataNode* node) {
return reinterpret_cast<StringData*>(
uintptr_t(node) - offsetof(Proxy, node)
- sizeof(StringData)
);
}
#ifdef NO_M_DATA
static constexpr bool isProxy() { return false; }
#else
bool isProxy() const;
#endif
bool isImmutable() const;
bool checkSane() const;
void unProxy();
private:
struct Proxy {
StringDataNode node;
const APCString* apcstr;
};
private:
template<bool trueStatic>
static StringData* MakeShared(folly::StringPiece sl);
StringData(const StringData&) = delete;
StringData& operator=(const StringData&) = delete;
~StringData() = delete;
private:
const void* payload() const;
void* payload();
const Proxy* proxy() const;
Proxy* proxy();
#ifdef NO_M_DATA
static constexpr bool isFlat() { return true; }
#else
bool isFlat() const;
#endif
void releaseProxy();
int numericCompare(const StringData *v2) const;
StringData* escalate(size_t cap);
void enlist();
void delist();
void incrementHelper();
void preCompute();
// We have the next fields blocked into qword-size unions so
// StringData initialization can do fewer stores to initialize the
// fields. (gcc does not combine the stores itself.)
private:
#ifndef NO_M_DATA
// TODO(5601154): Add KindOfApcString and remove StringData m_data field.
char* m_data;
#endif
union {
struct {
uint32_t m_len;
mutable int32_t m_hash; // precomputed for persistent strings
};
uint64_t m_lenAndHash;
};
};
//////////////////////////////////////////////////////////////////////
/*
* The allocation overhead of a StringData: the struct plus the null byte
*/
auto constexpr kStringOverhead = sizeof(StringData) + 1;
static_assert(StringData::MaxSize + kStringOverhead == kSizeIndex2Size[103],
"max allocation size is a valid size class");
/*
* A reasonable length to reserve for small strings. This is also the
* default reserve size for StringData::Make().
*/
constexpr uint32_t SmallStringReserve = 64 - kStringOverhead;
/* this only exists so that clang won't warn on the subtraction */
inline constexpr uint32_t sizeClassParams2StringCapacity(
size_t lg_grp,
size_t lg_delta,
size_t ndelta
) {
return ((size_t{1} << lg_grp) + (ndelta << lg_delta)) > kStringOverhead
&& ((size_t{1} << lg_grp) + (ndelta << lg_delta))
<= StringData::MaxSize + kStringOverhead
? ((size_t{1} << lg_grp) + (ndelta << lg_delta)) - kStringOverhead
: 0;
}
alignas(64) constexpr uint32_t kSizeIndex2StringCapacity[] = {
#define SIZE_CLASS(index, lg_grp, lg_delta, ndelta, lg_delta_lookup, ncontig) \
sizeClassParams2StringCapacity(lg_grp, lg_delta, ndelta),
SIZE_CLASSES
#undef SIZE_CLASS
};
/*
* Call this if we tried to make a string longer than StringData::MaxSize
*/
void raiseStringLengthExceededError(size_t len);
/*
* DecRef a string s, calling release if its reference count goes to
* zero.
*/
void decRefStr(StringData* s);
//////////////////////////////////////////////////////////////////////
/*
* Function objects that forward to the StringData member functions of
* the same name.
*/
struct string_data_hash;
struct string_data_same;
struct string_data_isame;
struct string_data_lt;
struct string_data_lti;
//////////////////////////////////////////////////////////////////////
extern std::aligned_storage<
kStringOverhead,
alignof(StringData)
>::type s_theEmptyString;
/*
* Return the "static empty string". This is a singleton StaticString
* that can be used to return a StaticString for the empty string in
* as lightweight a manner as possible.
*/
ALWAYS_INLINE StringData* staticEmptyString() {
void* vp = &s_theEmptyString;
return static_cast<StringData*>(vp);
}
//////////////////////////////////////////////////////////////////////
}
namespace folly {
template<> class FormatValue<const HPHP::StringData*> {
public:
explicit FormatValue(const HPHP::StringData* str) : m_val(str) {}
template<typename Callback>
void format(FormatArg& arg, Callback& cb) const {
auto piece = folly::StringPiece(m_val->data(), m_val->size());
format_value::formatString(piece, arg, cb);
}
private:
const HPHP::StringData* m_val;
};
template<> class FormatValue<HPHP::StringData*> {
public:
explicit FormatValue(const HPHP::StringData* str) : m_val(str) {}
template<typename Callback>
void format(FormatArg& arg, Callback& cb) const {
FormatValue<const HPHP::StringData*>(m_val).format(arg, cb);
}
private:
const HPHP::StringData* m_val;
};
}
#include "hphp/runtime/base/string-data-inl.h"
#endif