Bug 1023778 part 5 - Add AutoStableStringChars class. r=terrence

This commit is contained in:
Jan de Mooij 2014-06-13 20:51:10 +02:00
parent 68114dd79c
commit 9990d4034b
2 changed files with 118 additions and 8 deletions

View File

@ -744,6 +744,57 @@ StaticStrings::isStatic(JSAtom *atom)
}
}
AutoStableStringChars::~AutoStableStringChars()
{
if (ownsChars_) {
MOZ_ASSERT(state_ == Latin1 || state_ == TwoByte);
if (state_ == Latin1)
js_free(const_cast<Latin1Char*>(latin1Chars_));
else
js_free(const_cast<jschar*>(twoByteChars_));
}
}
bool
AutoStableStringChars::init()
{
MOZ_ASSERT(state_ == Uninitialized);
if (s_->hasLatin1Chars()) {
state_ = Latin1;
latin1Chars_ = s_->rawLatin1Chars();
} else {
state_ = TwoByte;
twoByteChars_ = s_->rawTwoByteChars();
}
return true;
}
bool
AutoStableStringChars::initTwoByte(JSContext *cx)
{
MOZ_ASSERT(state_ == Uninitialized);
if (s_->hasTwoByteChars()) {
state_ = TwoByte;
twoByteChars_ = s_->rawTwoByteChars();
return true;
}
jschar *chars = cx->pod_malloc<jschar>(s_->length() + 1);
if (!chars)
return false;
CopyAndInflateChars(chars, s_->rawLatin1Chars(), s_->length());
chars[s_->length()] = 0;
state_ = TwoByte;
ownsChars_ = true;
twoByteChars_ = chars;
return true;
}
#ifdef DEBUG
void
JSAtom::dump()

View File

@ -30,6 +30,7 @@ class JSRope;
namespace js {
class AutoStableStringChars;
class StaticStrings;
class PropertyName;
@ -584,6 +585,7 @@ JS_STATIC_ASSERT(sizeof(JSRope) == sizeof(JSString));
class JSLinearString : public JSString
{
friend class JSString;
friend class js::AutoStableStringChars;
/* Vacuous and therefore unimplemented. */
JSLinearString *ensureLinear(JSContext *cx) MOZ_DELETE;
@ -601,6 +603,9 @@ class JSLinearString : public JSString
return (void *)d.s.u2.nonInlineCharsTwoByte;
}
MOZ_ALWAYS_INLINE const JS::Latin1Char *rawLatin1Chars() const;
MOZ_ALWAYS_INLINE const jschar *rawTwoByteChars() const;
public:
MOZ_ALWAYS_INLINE
const jschar *nonInlineChars() const {
@ -635,10 +640,14 @@ class JSLinearString : public JSString
const CharT *chars(const JS::AutoCheckCannotGC &nogc) const;
MOZ_ALWAYS_INLINE
const JS::Latin1Char *latin1Chars(const JS::AutoCheckCannotGC &nogc) const;
const JS::Latin1Char *latin1Chars(const JS::AutoCheckCannotGC &nogc) const {
return rawLatin1Chars();
}
MOZ_ALWAYS_INLINE
const jschar *twoByteChars(const JS::AutoCheckCannotGC &nogc) const;
const jschar *twoByteChars(const JS::AutoCheckCannotGC &nogc) const {
return rawTwoByteChars();
}
JS::TwoByteChars range() const {
JS_ASSERT(JSString::isLinear());
@ -1042,6 +1051,56 @@ class ScopedThreadSafeStringInspector
}
};
/*
* 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 AutoStableStringChars
{
/* Ensure the string is kept alive while we're using its chars. */
Rooted<JSLinearString*> s_;
union {
const jschar *twoByteChars_;
const JS::Latin1Char *latin1Chars_;
};
enum State { Uninitialized, Latin1, TwoByte };
State state_;
bool ownsChars_;
public:
AutoStableStringChars(JSContext *cx, JSLinearString *s)
: s_(cx, s), state_(Uninitialized), ownsChars_(false)
{};
~AutoStableStringChars();
bool init();
/* Like init(), but Latin1 chars are inflated to TwoByte. */
bool initTwoByte(JSContext *cx);
bool isLatin1() const { return state_ == Latin1; }
bool isTwoByte() const { return state_ == TwoByte; }
const JS::Latin1Char *latin1Chars() const {
MOZ_ASSERT(state_ == Latin1);
return latin1Chars_;
}
const jschar *twoByteChars() const {
MOZ_ASSERT(state_ == TwoByte);
return twoByteChars_;
}
private:
AutoStableStringChars(const AutoStableStringChars &other) MOZ_DELETE;
void operator=(const AutoStableStringChars &other) MOZ_DELETE;
};
class StaticStrings
{
private:
@ -1321,14 +1380,14 @@ template<>
MOZ_ALWAYS_INLINE const jschar *
JSLinearString::chars(const JS::AutoCheckCannotGC &nogc) const
{
return twoByteChars(nogc);
return rawTwoByteChars();
}
template<>
MOZ_ALWAYS_INLINE const JS::Latin1Char *
JSLinearString::chars(const JS::AutoCheckCannotGC &nogc) const
{
return latin1Chars(nogc);
return rawLatin1Chars();
}
template<>
@ -1382,19 +1441,19 @@ JSLinearString::chars() const
}
MOZ_ALWAYS_INLINE const JS::Latin1Char *
JSLinearString::latin1Chars(const JS::AutoCheckCannotGC &nogc) const
JSLinearString::rawLatin1Chars() const
{
JS_ASSERT(JSString::isLinear());
JS_ASSERT(hasLatin1Chars());
return isInline() ? asInline().latin1Chars(nogc) : nonInlineLatin1Chars(nogc);
return isInline() ? d.inlineStorageLatin1 : d.s.u2.nonInlineCharsLatin1;
}
MOZ_ALWAYS_INLINE const jschar *
JSLinearString::twoByteChars(const JS::AutoCheckCannotGC &nogc) const
JSLinearString::rawTwoByteChars() const
{
JS_ASSERT(JSString::isLinear());
JS_ASSERT(hasTwoByteChars());
return isInline() ? asInline().twoByteChars(nogc) : nonInlineTwoByteChars(nogc);
return isInline() ? d.inlineStorageTwoByte : d.s.u2.nonInlineCharsTwoByte;
}
inline js::PropertyName *