Bug 1032726 part 4 - Beef up JS friend APIs for strings. r=terrence

This commit is contained in:
Jan de Mooij 2014-07-03 10:03:54 +02:00
parent d372a252c9
commit 469c11bdc2
3 changed files with 110 additions and 40 deletions

View File

@ -674,6 +674,12 @@ js::GetWeakmapKeyDelegate(JSObject *key)
return nullptr;
}
JS_FRIEND_API(JSLinearString *)
js::StringToLinearStringSlow(JSContext *cx, JSString *str)
{
return str->ensureLinear(cx);
}
JS_FRIEND_API(void)
JS_SetAccumulateTelemetryCallback(JSRuntime *rt, JSAccumulateTelemetryDataCallback callback)
{

View File

@ -575,9 +575,12 @@ struct Function {
void *_1;
};
struct Atom {
struct String
{
static const uint32_t INLINE_CHARS_BIT = JS_BIT(2);
static const uint32_t LATIN1_CHARS_BIT = JS_BIT(6);
static const uint32_t ROPE_FLAGS = 0;
static const uint32_t TYPE_FLAGS_MASK = JS_BIT(6) - 1;
uint32_t flags;
uint32_t length;
union {
@ -761,48 +764,105 @@ GetObjectSlot(JSObject *obj, size_t slot)
return reinterpret_cast<const shadow::Object *>(obj)->slotRef(slot);
}
inline size_t
MOZ_ALWAYS_INLINE size_t
GetAtomLength(JSAtom *atom)
{
return reinterpret_cast<shadow::Atom*>(atom)->length;
return reinterpret_cast<shadow::String*>(atom)->length;
}
inline bool
MOZ_ALWAYS_INLINE size_t
GetStringLength(JSString *s)
{
return reinterpret_cast<shadow::String*>(s)->length;
}
MOZ_ALWAYS_INLINE bool
LinearStringHasLatin1Chars(JSLinearString *s)
{
return reinterpret_cast<shadow::String *>(s)->flags & shadow::String::LATIN1_CHARS_BIT;
}
MOZ_ALWAYS_INLINE bool
AtomHasLatin1Chars(JSAtom *atom)
{
return reinterpret_cast<shadow::Atom *>(atom)->flags & shadow::Atom::LATIN1_CHARS_BIT;
return reinterpret_cast<shadow::String *>(atom)->flags & shadow::String::LATIN1_CHARS_BIT;
}
inline const JS::Latin1Char *
GetLatin1AtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
MOZ_ALWAYS_INLINE const JS::Latin1Char *
GetLatin1LinearStringChars(const JS::AutoCheckCannotGC &nogc, JSLinearString *linear)
{
MOZ_ASSERT(AtomHasLatin1Chars(atom));
MOZ_ASSERT(LinearStringHasLatin1Chars(linear));
using shadow::Atom;
Atom *atom_ = reinterpret_cast<Atom *>(atom);
if (atom_->flags & Atom::INLINE_CHARS_BIT)
return atom_->inlineStorageLatin1;
return atom_->nonInlineCharsLatin1;
using shadow::String;
String *s = reinterpret_cast<String *>(linear);
if (s->flags & String::INLINE_CHARS_BIT)
return s->inlineStorageLatin1;
return s->nonInlineCharsLatin1;
}
inline const jschar *
GetTwoByteAtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
MOZ_ALWAYS_INLINE const jschar *
GetTwoByteLinearStringChars(const JS::AutoCheckCannotGC &nogc, JSLinearString *linear)
{
MOZ_ASSERT(!AtomHasLatin1Chars(atom));
MOZ_ASSERT(!LinearStringHasLatin1Chars(linear));
using shadow::Atom;
Atom *atom_ = reinterpret_cast<Atom *>(atom);
if (atom_->flags & Atom::INLINE_CHARS_BIT)
return atom_->inlineStorageTwoByte;
return atom_->nonInlineCharsTwoByte;
using shadow::String;
String *s = reinterpret_cast<String *>(linear);
if (s->flags & String::INLINE_CHARS_BIT)
return s->inlineStorageTwoByte;
return s->nonInlineCharsTwoByte;
}
inline JSLinearString *
MOZ_ALWAYS_INLINE JSLinearString *
AtomToLinearString(JSAtom *atom)
{
return reinterpret_cast<JSLinearString *>(atom);
}
MOZ_ALWAYS_INLINE const JS::Latin1Char *
GetLatin1AtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
{
return GetLatin1LinearStringChars(nogc, AtomToLinearString(atom));
}
MOZ_ALWAYS_INLINE const jschar *
GetTwoByteAtomChars(const JS::AutoCheckCannotGC &nogc, JSAtom *atom)
{
return GetTwoByteLinearStringChars(nogc, AtomToLinearString(atom));
}
JS_FRIEND_API(JSLinearString *)
StringToLinearStringSlow(JSContext *cx, JSString *str);
MOZ_ALWAYS_INLINE JSLinearString *
StringToLinearString(JSContext *cx, JSString *str)
{
using shadow::String;
String *s = reinterpret_cast<String *>(str);
if (MOZ_UNLIKELY((s->flags & String::TYPE_FLAGS_MASK) == String::ROPE_FLAGS))
return StringToLinearStringSlow(cx, str);
return reinterpret_cast<JSLinearString *>(str);
}
inline bool
CopyStringChars(JSContext *cx, jschar *dest, JSString *s, size_t len)
{
JSLinearString *linear = StringToLinearString(cx, s);
if (!linear)
return false;
JS::AutoCheckCannotGC nogc;
if (LinearStringHasLatin1Chars(linear)) {
const JS::Latin1Char *src = GetLatin1LinearStringChars(nogc, linear);
for (size_t i = 0; i < len; i++)
dest[i] = src[i];
} else {
const jschar *src = GetTwoByteLinearStringChars(nogc, linear);
mozilla::PodCopy(dest, src, len);
}
return true;
}
JS_FRIEND_API(bool)
GetPropertyNames(JSContext *cx, JSObject *obj, unsigned flags, JS::AutoIdVector *props);

View File

@ -278,24 +278,28 @@ class JSString : public js::gc::BarrieredCell<JSString>
NUM_INLINE_CHARS_TWO_BYTE * sizeof(jschar)),
"Inline chars must fit in a JSString");
/* Ensure js::shadow::Atom has the same layout. */
using js::shadow::Atom;
static_assert(offsetof(JSString, d.u1.length) == offsetof(Atom, length),
"shadow::Atom length offset must match JSString");
static_assert(offsetof(JSString, d.u1.flags) == offsetof(Atom, flags),
"shadow::Atom flags offset must match JSString");
static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(Atom, nonInlineCharsLatin1),
"shadow::Atom nonInlineChars offset must match JSString");
static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(Atom, nonInlineCharsTwoByte),
"shadow::Atom nonInlineChars offset must match JSString");
static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(Atom, inlineStorageLatin1),
"shadow::Atom inlineStorage offset must match JSString");
static_assert(offsetof(JSString, d.inlineStorageTwoByte) == offsetof(Atom, inlineStorageTwoByte),
"shadow::Atom inlineStorage offset must match JSString");
static_assert(INLINE_CHARS_BIT == Atom::INLINE_CHARS_BIT,
"shadow::Atom::INLINE_CHARS_BIT must match JSString::INLINE_CHARS_BIT");
static_assert(LATIN1_CHARS_BIT == Atom::LATIN1_CHARS_BIT,
"shadow::Atom::LATIN1_CHARS_BIT must match JSString::LATIN1_CHARS_BIT");
/* Ensure js::shadow::String has the same layout. */
using js::shadow::String;
static_assert(offsetof(JSString, d.u1.length) == offsetof(String, length),
"shadow::String length offset must match JSString");
static_assert(offsetof(JSString, d.u1.flags) == offsetof(String, flags),
"shadow::String flags offset must match JSString");
static_assert(offsetof(JSString, d.s.u2.nonInlineCharsLatin1) == offsetof(String, nonInlineCharsLatin1),
"shadow::String nonInlineChars offset must match JSString");
static_assert(offsetof(JSString, d.s.u2.nonInlineCharsTwoByte) == offsetof(String, nonInlineCharsTwoByte),
"shadow::String nonInlineChars offset must match JSString");
static_assert(offsetof(JSString, d.inlineStorageLatin1) == offsetof(String, inlineStorageLatin1),
"shadow::String inlineStorage offset must match JSString");
static_assert(offsetof(JSString, d.inlineStorageTwoByte) == offsetof(String, inlineStorageTwoByte),
"shadow::String inlineStorage offset must match JSString");
static_assert(INLINE_CHARS_BIT == String::INLINE_CHARS_BIT,
"shadow::String::INLINE_CHARS_BIT must match JSString::INLINE_CHARS_BIT");
static_assert(LATIN1_CHARS_BIT == String::LATIN1_CHARS_BIT,
"shadow::String::LATIN1_CHARS_BIT must match JSString::LATIN1_CHARS_BIT");
static_assert(TYPE_FLAGS_MASK == String::TYPE_FLAGS_MASK,
"shadow::String::TYPE_FLAGS_MASK must match JSString::TYPE_FLAGS_MASK");
static_assert(ROPE_FLAGS == String::ROPE_FLAGS,
"shadow::String::ROPE_FLAGS must match JSString::ROPE_FLAGS");
}
/* Avoid lame compile errors in JSRope::flatten */