summaryrefslogtreecommitdiffstats
path: root/js/public/StableStringChars.h
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--js/public/StableStringChars.h119
1 files changed, 119 insertions, 0 deletions
diff --git a/js/public/StableStringChars.h b/js/public/StableStringChars.h
new file mode 100644
index 0000000000..a12813d89c
--- /dev/null
+++ b/js/public/StableStringChars.h
@@ -0,0 +1,119 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+/*
+ * Safely access the contents of a string even as GC can cause the string's
+ * contents to move around in memory.
+ */
+
+#ifndef js_StableStringChars_h
+#define js_StableStringChars_h
+
+#include "mozilla/Assertions.h" // MOZ_ASSERT
+#include "mozilla/Attributes.h" // MOZ_INIT_OUTSIDE_CTOR, MOZ_STACK_CLASS
+#include "mozilla/Maybe.h" // mozilla::Maybe
+#include "mozilla/Range.h" // mozilla::Range
+
+#include <stddef.h> // size_t
+#include <stdint.h> // uint8_t
+
+#include "jstypes.h" // JS_PUBLIC_API
+
+#include "js/AllocPolicy.h"
+#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
+#include "js/String.h" // JS::GetStringLength
+#include "js/TypeDecls.h" // JSContext, JS::Latin1Char, JSString
+#include "js/Vector.h" // js::Vector
+
+class JSLinearString;
+
+namespace JS {
+
+/**
+ * This class provides safe access to a string's chars across a GC. If we ever
+ * nursery allocate strings' out of line chars, this class will have to make a
+ * copy, so it's best to avoid using this class unless you really need it. It's
+ * usually more efficient to use the latin1Chars/twoByteChars JSString methods
+ * and often the code can be rewritten so that only indexes instead of char
+ * pointers are used in parts of the code that can GC.
+ */
+class MOZ_STACK_CLASS JS_PUBLIC_API AutoStableStringChars final {
+ /*
+ * When copying string char, use this many bytes of inline storage. This is
+ * chosen to allow the inline string types to be copied without allocating.
+ * This is asserted in AutoStableStringChars::allocOwnChars.
+ */
+ static const size_t InlineCapacity = 24;
+
+ /* Ensure the string is kept alive while we're using its chars. */
+ Rooted<JSString*> s_;
+ union MOZ_INIT_OUTSIDE_CTOR {
+ const char16_t* twoByteChars_;
+ const Latin1Char* latin1Chars_;
+ };
+ mozilla::Maybe<js::Vector<uint8_t, InlineCapacity>> ownChars_;
+ enum State { Uninitialized, Latin1, TwoByte };
+ State state_;
+
+ public:
+ explicit AutoStableStringChars(JSContext* cx)
+ : s_(cx), state_(Uninitialized) {}
+
+ [[nodiscard]] bool init(JSContext* cx, JSString* s);
+
+ /* Like init(), but Latin1 chars are inflated to TwoByte. */
+ [[nodiscard]] bool initTwoByte(JSContext* cx, JSString* s);
+
+ bool isLatin1() const { return state_ == Latin1; }
+ bool isTwoByte() const { return state_ == TwoByte; }
+
+ const Latin1Char* latin1Chars() const {
+ MOZ_ASSERT(state_ == Latin1);
+ return latin1Chars_;
+ }
+ const char16_t* twoByteChars() const {
+ MOZ_ASSERT(state_ == TwoByte);
+ return twoByteChars_;
+ }
+
+ mozilla::Range<const Latin1Char> latin1Range() const {
+ MOZ_ASSERT(state_ == Latin1);
+ return mozilla::Range<const Latin1Char>(latin1Chars_, length());
+ }
+
+ mozilla::Range<const char16_t> twoByteRange() const {
+ MOZ_ASSERT(state_ == TwoByte);
+ return mozilla::Range<const char16_t>(twoByteChars_, length());
+ }
+
+ /* If we own the chars, transfer ownership to the caller. */
+ bool maybeGiveOwnershipToCaller() {
+ MOZ_ASSERT(state_ != Uninitialized);
+ if (!ownChars_.isSome() || !ownChars_->extractRawBuffer()) {
+ return false;
+ }
+ state_ = Uninitialized;
+ ownChars_.reset();
+ return true;
+ }
+
+ size_t length() const { return GetStringLength(s_); }
+
+ private:
+ AutoStableStringChars(const AutoStableStringChars& other) = delete;
+ void operator=(const AutoStableStringChars& other) = delete;
+
+ bool baseIsInline(Handle<JSLinearString*> linearString);
+ template <typename T>
+ T* allocOwnChars(JSContext* cx, size_t count);
+ bool copyLatin1Chars(JSContext* cx, Handle<JSLinearString*> linearString);
+ bool copyTwoByteChars(JSContext* cx, Handle<JSLinearString*> linearString);
+ bool copyAndInflateLatin1Chars(JSContext*,
+ Handle<JSLinearString*> linearString);
+};
+
+} // namespace JS
+
+#endif /* js_StableStringChars_h */