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 mozilla::Maybe
<js::Vector
<uint8_t, InlineCapacity
>> ownChars_
;
57 enum State
{ Uninitialized
, Latin1
, TwoByte
};
61 explicit AutoStableStringChars(JSContext
* cx
)
62 : s_(cx
), state_(Uninitialized
) {}
64 [[nodiscard
]] bool init(JSContext
* cx
, JSString
* s
);
66 /* Like init(), but Latin1 chars are inflated to TwoByte. */
67 [[nodiscard
]] bool initTwoByte(JSContext
* cx
, JSString
* s
);
69 bool isLatin1() const { return state_
== Latin1
; }
70 bool isTwoByte() const { return state_
== TwoByte
; }
72 const Latin1Char
* latin1Chars() const {
73 MOZ_ASSERT(state_
== Latin1
);
76 const char16_t
* twoByteChars() const {
77 MOZ_ASSERT(state_
== TwoByte
);
81 mozilla::Range
<const Latin1Char
> latin1Range() const {
82 MOZ_ASSERT(state_
== Latin1
);
83 return mozilla::Range
<const Latin1Char
>(latin1Chars_
, length());
86 mozilla::Range
<const char16_t
> twoByteRange() const {
87 MOZ_ASSERT(state_
== TwoByte
);
88 return mozilla::Range
<const char16_t
>(twoByteChars_
, length());
91 /* If we own the chars, transfer ownership to the caller. */
92 bool maybeGiveOwnershipToCaller() {
93 MOZ_ASSERT(state_
!= Uninitialized
);
94 if (!ownChars_
.isSome() || !ownChars_
->extractRawBuffer()) {
97 state_
= Uninitialized
;
102 size_t length() const { return GetStringLength(s_
); }
105 AutoStableStringChars(const AutoStableStringChars
& other
) = delete;
106 void operator=(const AutoStableStringChars
& other
) = delete;
108 template <typename T
>
109 T
* allocOwnChars(JSContext
* cx
, size_t count
);
110 bool copyLatin1Chars(JSContext
* cx
, Handle
<JSLinearString
*> linearString
);
111 bool copyTwoByteChars(JSContext
* cx
, Handle
<JSLinearString
*> linearString
);
112 bool copyAndInflateLatin1Chars(JSContext
*,
113 Handle
<JSLinearString
*> linearString
);
118 #endif /* js_StableStringChars_h */