mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-23 04:41:11 +00:00
ed2b5c23e3
Differential Revision: https://phabricator.services.mozilla.com/D209877
127 lines
4.2 KiB
C++
127 lines
4.2 KiB
C++
/* -*- 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. When it
|
|
* has nursery-allocated out of lines 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_;
|
|
};
|
|
MOZ_INIT_OUTSIDE_CTOR uint32_t length_;
|
|
mozilla::Maybe<js::Vector<uint8_t, InlineCapacity>> ownChars_;
|
|
enum State { Uninitialized, Latin1, TwoByte };
|
|
State state_;
|
|
|
|
// Prevent the string that owns s's chars from being collected (by storing it
|
|
// in s_) or deduplicated.
|
|
void holdStableChars(JSLinearString* s);
|
|
|
|
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 {
|
|
MOZ_ASSERT(state_ != Uninitialized);
|
|
return length_;
|
|
}
|
|
|
|
private:
|
|
AutoStableStringChars(const AutoStableStringChars& other) = delete;
|
|
void operator=(const AutoStableStringChars& other) = delete;
|
|
|
|
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 */
|