1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 * Safely access the contents of a string even as GC can cause the string's
8 * contents to move around in memory.
11 #ifndef js_StableStringChars_h
12 #define js_StableStringChars_h
14 #include "mozilla/Assertions.h" // MOZ_ASSERT
15 #include "mozilla/Attributes.h" // MOZ_INIT_OUTSIDE_CTOR, MOZ_STACK_CLASS
16 #include "mozilla/Maybe.h" // mozilla::Maybe
17 #include "mozilla/Range.h" // mozilla::Range
19 #include <stddef.h> // size_t
20 #include <stdint.h> // uint8_t
22 #include "jstypes.h" // JS_PUBLIC_API
24 #include "js/AllocPolicy.h"
25 #include "js/RootingAPI.h" // JS::Handle, JS::Rooted
26 #include "js/String.h" // JS::GetStringLength
27 #include "js/TypeDecls.h" // JSContext, JS::Latin1Char, JSString
28 #include "js/Vector.h" // js::Vector
35 * This class provides safe access to a string's chars across a GC. When it
36 * has nursery-allocated out of lines chars, this class will have to make a
37 * copy, so it's best to avoid using this class unless you really need it. It's
38 * usually more efficient to use the latin1Chars/twoByteChars JSString methods
39 * and often the code can be rewritten so that only indexes instead of char
40 * pointers are used in parts of the code that can GC.
42 class MOZ_STACK_CLASS JS_PUBLIC_API AutoStableStringChars final
{
44 * When copying string char, use this many bytes of inline storage. This is
45 * chosen to allow the inline string types to be copied without allocating.
46 * This is asserted in AutoStableStringChars::allocOwnChars.
48 static const size_t InlineCapacity
= 24;
50 /* Ensure the string is kept alive while we're using its chars. */
52 union MOZ_INIT_OUTSIDE_CTOR
{
53 const char16_t
* twoByteChars_
;
54 const Latin1Char
* latin1Chars_
;
56 MOZ_INIT_OUTSIDE_CTOR
uint32_t length_
;
57 mozilla::Maybe
<js::Vector
<uint8_t, InlineCapacity
>> ownChars_
;
58 enum State
{ Uninitialized
, Latin1
, TwoByte
};
61 // Prevent the string that owns s's chars from being collected (by storing it
62 // in s_) or deduplicated.
63 void holdStableChars(JSLinearString
* s
);
66 explicit AutoStableStringChars(JSContext
* cx
)
67 : s_(cx
), state_(Uninitialized
) {}
69 [[nodiscard
]] bool init(JSContext
* cx
, JSString
* s
);
71 /* Like init(), but Latin1 chars are inflated to TwoByte. */
72 [[nodiscard
]] bool initTwoByte(JSContext
* cx
, JSString
* s
);
74 bool isLatin1() const { return state_
== Latin1
; }
75 bool isTwoByte() const { return state_
== TwoByte
; }
77 const Latin1Char
* latin1Chars() const {
78 MOZ_ASSERT(state_
== Latin1
);
81 const char16_t
* twoByteChars() const {
82 MOZ_ASSERT(state_
== TwoByte
);
86 mozilla::Range
<const Latin1Char
> latin1Range() const {
87 MOZ_ASSERT(state_
== Latin1
);
88 return mozilla::Range
<const Latin1Char
>(latin1Chars_
, length());
91 mozilla::Range
<const char16_t
> twoByteRange() const {
92 MOZ_ASSERT(state_
== TwoByte
);
93 return mozilla::Range
<const char16_t
>(twoByteChars_
, length());
96 /* If we own the chars, transfer ownership to the caller. */
97 bool maybeGiveOwnershipToCaller() {
98 MOZ_ASSERT(state_
!= Uninitialized
);
99 if (!ownChars_
.isSome() || !ownChars_
->extractRawBuffer()) {
102 state_
= Uninitialized
;
107 size_t length() const {
108 MOZ_ASSERT(state_
!= Uninitialized
);
113 AutoStableStringChars(const AutoStableStringChars
& other
) = delete;
114 void operator=(const AutoStableStringChars
& other
) = delete;
116 template <typename T
>
117 T
* allocOwnChars(JSContext
* cx
, size_t count
);
118 bool copyLatin1Chars(JSContext
* cx
, Handle
<JSLinearString
*> linearString
);
119 bool copyTwoByteChars(JSContext
* cx
, Handle
<JSLinearString
*> linearString
);
120 bool copyAndInflateLatin1Chars(JSContext
*,
121 Handle
<JSLinearString
*> linearString
);
126 #endif /* js_StableStringChars_h */