StableStringChars.h (4221B)
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/. */ 5 6 /* 7 * Safely access the contents of a string even as GC can cause the string's 8 * contents to move around in memory. 9 */ 10 11 #ifndef js_StableStringChars_h 12 #define js_StableStringChars_h 13 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 18 19 #include <stddef.h> // size_t 20 #include <stdint.h> // uint8_t 21 22 #include "jstypes.h" // JS_PUBLIC_API 23 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 29 30 class JSLinearString; 31 32 namespace JS { 33 34 /** 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. 41 */ 42 class MOZ_STACK_CLASS JS_PUBLIC_API AutoStableStringChars final { 43 /* 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. 47 */ 48 static const size_t InlineCapacity = 24; 49 50 /* Ensure the string is kept alive while we're using its chars. */ 51 Rooted<JSString*> s_; 52 union MOZ_INIT_OUTSIDE_CTOR { 53 const char16_t* twoByteChars_; 54 const Latin1Char* latin1Chars_; 55 }; 56 MOZ_INIT_OUTSIDE_CTOR uint32_t length_; 57 mozilla::Maybe<js::Vector<uint8_t, InlineCapacity>> ownChars_; 58 enum State { Uninitialized, Latin1, TwoByte }; 59 State state_; 60 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); 64 65 public: 66 explicit AutoStableStringChars(JSContext* cx) 67 : s_(cx), state_(Uninitialized) {} 68 69 [[nodiscard]] bool init(JSContext* cx, JSString* s); 70 71 /* Like init(), but Latin1 chars are inflated to TwoByte. */ 72 [[nodiscard]] bool initTwoByte(JSContext* cx, JSString* s); 73 74 bool isLatin1() const { return state_ == Latin1; } 75 bool isTwoByte() const { return state_ == TwoByte; } 76 77 const Latin1Char* latin1Chars() const { 78 MOZ_ASSERT(state_ == Latin1); 79 return latin1Chars_; 80 } 81 const char16_t* twoByteChars() const { 82 MOZ_ASSERT(state_ == TwoByte); 83 return twoByteChars_; 84 } 85 86 mozilla::Range<const Latin1Char> latin1Range() const { 87 MOZ_ASSERT(state_ == Latin1); 88 return mozilla::Range<const Latin1Char>(latin1Chars_, length()); 89 } 90 91 mozilla::Range<const char16_t> twoByteRange() const { 92 MOZ_ASSERT(state_ == TwoByte); 93 return mozilla::Range<const char16_t>(twoByteChars_, length()); 94 } 95 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()) { 100 return false; 101 } 102 state_ = Uninitialized; 103 ownChars_.reset(); 104 return true; 105 } 106 107 size_t length() const { 108 MOZ_ASSERT(state_ != Uninitialized); 109 return length_; 110 } 111 112 private: 113 AutoStableStringChars(const AutoStableStringChars& other) = delete; 114 void operator=(const AutoStableStringChars& other) = delete; 115 116 template <typename T> 117 T* allocOwnChars(JSContext* cx, size_t count); 118 bool copyLatin1Chars(JSContext* cx, JSLinearString* linearString); 119 bool copyTwoByteChars(JSContext* cx, JSLinearString* linearString); 120 bool copyAndInflateLatin1Chars(JSContext*, JSLinearString* linearString); 121 }; 122 123 } // namespace JS 124 125 #endif /* js_StableStringChars_h */