зеркало из https://github.com/mozilla/gecko-dev.git
124 строки
4.3 KiB
C++
124 строки
4.3 KiB
C++
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
|
/* 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, MOZ_MUST_USE
|
|
#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_FRIEND_API
|
|
|
|
#include "js/HeapAPI.h" // JS::shadow::String
|
|
#include "js/RootingAPI.h" // JS::Handle, JS::Rooted
|
|
#include "js/TypeDecls.h" // JSContext, JS::Latin1Char, JSString
|
|
#include "js/Vector.h" // js::Vector
|
|
|
|
class JSLinearString;
|
|
|
|
namespace JS {
|
|
|
|
MOZ_ALWAYS_INLINE size_t
|
|
GetStringLength(JSString* s)
|
|
{
|
|
return reinterpret_cast<shadow::String*>(s)->length();
|
|
}
|
|
|
|
/**
|
|
* This class provides safe access to a string's chars across a GC. Once
|
|
* we allocate strings and chars in the nursery (bug 903519), this class
|
|
* will have to make a copy of the string's chars if they are allocated
|
|
* in the nursery, 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_FRIEND_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_;
|
|
MOZ_INIT_OUTSIDE_CTOR union {
|
|
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)
|
|
{}
|
|
|
|
MOZ_MUST_USE bool init(JSContext* cx, JSString* s);
|
|
|
|
/* Like init(), but Latin1 chars are inflated to TwoByte. */
|
|
MOZ_MUST_USE 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_, GetStringLength(s_));
|
|
}
|
|
|
|
mozilla::Range<const char16_t> twoByteRange() const {
|
|
MOZ_ASSERT(state_ == TwoByte);
|
|
return mozilla::Range<const char16_t>(twoByteChars_,
|
|
GetStringLength(s_));
|
|
}
|
|
|
|
/* 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;
|
|
}
|
|
|
|
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 */
|