Bug 1015917 part 1 - Support string concatenation for Latin1 strings. r=luke

This commit is contained in:
Jan de Mooij 2014-05-31 10:44:32 +02:00
Родитель 35aee7a28a
Коммит b90f317a8c
17 изменённых файлов: 284 добавлений и 116 удалений

Просмотреть файл

@ -137,7 +137,7 @@ class gcstats::StatisticsSerializer
return nullptr;
}
InflateStringToBuffer(buf, nchars, out);
CopyAndInflateChars(out, buf, nchars);
js_free(buf);
out[nchars] = 0;

Просмотреть файл

@ -5154,7 +5154,8 @@ CodeGenerator::visitConcatPar(LConcatPar *lir)
}
static void
CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, Register scratch)
CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len, Register scratch,
size_t fromWidth, size_t toWidth)
{
// Copy |len| jschars from |from| to |to|. Assumes len > 0 (checked below in
// debug builds), and when done |to| must point to the next available char.
@ -5166,17 +5167,125 @@ CopyStringChars(MacroAssembler &masm, Register to, Register from, Register len,
masm.bind(&ok);
#endif
JS_STATIC_ASSERT(sizeof(jschar) == 2);
MOZ_ASSERT(fromWidth == 1 || fromWidth == 2);
MOZ_ASSERT(toWidth == 1 || toWidth == 2);
MOZ_ASSERT_IF(toWidth == 1, fromWidth == 1);
Label start;
masm.bind(&start);
masm.load16ZeroExtend(Address(from, 0), scratch);
masm.store16(scratch, Address(to, 0));
masm.addPtr(Imm32(2), from);
masm.addPtr(Imm32(2), to);
if (fromWidth == 2)
masm.load16ZeroExtend(Address(from, 0), scratch);
else
masm.load8ZeroExtend(Address(from, 0), scratch);
if (toWidth == 2)
masm.store16(scratch, Address(to, 0));
else
masm.store8(scratch, Address(to, 0));
masm.addPtr(Imm32(fromWidth), from);
masm.addPtr(Imm32(toWidth), to);
masm.branchSub32(Assembler::NonZero, Imm32(1), len, &start);
}
static void
CopyStringCharsMaybeInflate(MacroAssembler &masm, Register input, Register destChars,
Register temp1, Register temp2)
{
// destChars is TwoByte and input is a Latin1 or TwoByte string, so we may
// have to inflate.
Label isLatin1, done;
masm.loadStringLength(input, temp1);
masm.branchTest32(Assembler::NonZero, Address(input, JSString::offsetOfFlags()),
Imm32(JSString::LATIN1_CHARS_BIT), &isLatin1);
{
masm.loadStringChars(input, input);
CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(jschar), sizeof(jschar));
masm.jump(&done);
}
masm.bind(&isLatin1);
{
masm.loadStringChars(input, input);
CopyStringChars(masm, destChars, input, temp1, temp2, sizeof(char), sizeof(jschar));
}
masm.bind(&done);
}
static void
ConcatFatInlineString(MacroAssembler &masm, Register lhs, Register rhs, Register output,
Register temp1, Register temp2, Register temp3, Register forkJoinContext,
ExecutionMode mode, Label *failure, Label *failurePopTemps, bool isTwoByte)
{
// State: result length in temp2.
// Ensure both strings are linear.
masm.branchIfRope(lhs, failure);
masm.branchIfRope(rhs, failure);
// Allocate a JSFatInlineString.
switch (mode) {
case SequentialExecution:
masm.newGCFatInlineString(output, temp1, failure);
break;
case ParallelExecution:
masm.push(temp1);
masm.push(temp2);
masm.newGCFatInlineStringPar(output, forkJoinContext, temp1, temp2, failurePopTemps);
masm.pop(temp2);
masm.pop(temp1);
break;
default:
MOZ_ASSUME_UNREACHABLE("No such execution mode");
}
// Store length and flags.
uint32_t flags = JSString::INIT_FAT_INLINE_FLAGS;
if (!isTwoByte)
flags |= JSString::LATIN1_CHARS_BIT;
masm.store32(Imm32(flags), Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
// Load chars pointer in temp2.
masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()), temp2);
{
// We use temp3 in this block, which in parallel execution also holds
// a live ForkJoinContext pointer. If we are compiling for parallel
// execution, be sure to save and restore the ForkJoinContext.
if (mode == ParallelExecution)
masm.push(temp3);
// Copy lhs chars. Note that this advances temp2 to point to the next
// char. This also clobbers the lhs register.
if (isTwoByte) {
CopyStringCharsMaybeInflate(masm, lhs, temp2, temp1, temp3);
} else {
masm.loadStringLength(lhs, temp3);
masm.loadStringChars(lhs, lhs);
CopyStringChars(masm, temp2, lhs, temp3, temp1, sizeof(char), sizeof(char));
}
// Copy rhs chars. Clobbers the rhs register.
if (isTwoByte) {
CopyStringCharsMaybeInflate(masm, rhs, temp2, temp1, temp3);
} else {
masm.loadStringLength(rhs, temp3);
masm.loadStringChars(rhs, rhs);
CopyStringChars(masm, temp2, rhs, temp3, temp1, sizeof(char), sizeof(char));
}
// Null-terminate.
if (isTwoByte)
masm.store16(Imm32(0), Address(temp2, 0));
else
masm.store8(Imm32(0), Address(temp2, 0));
if (mode == ParallelExecution)
masm.pop(temp3);
}
masm.ret();
}
JitCode *
JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
{
@ -5208,10 +5317,27 @@ JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
masm.add32(temp1, temp2);
// Check if we can use a JSFatInlineString.
Label isFatInline;
masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_LENGTH_TWO_BYTE),
&isFatInline);
// Check if we can use a JSFatInlineString. The result is a Latin1 string if
// lhs and rhs are both Latin1, so we AND the flags.
Label isFatInlineTwoByte, isFatInlineLatin1;
masm.load32(Address(lhs, JSString::offsetOfFlags()), temp1);
masm.and32(Address(rhs, JSString::offsetOfFlags()), temp1);
Label isLatin1, notInline;
masm.branchTest32(Assembler::NonZero, temp1, Imm32(JSString::LATIN1_CHARS_BIT), &isLatin1);
{
masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_LENGTH_TWO_BYTE),
&isFatInlineTwoByte);
masm.jump(&notInline);
}
masm.bind(&isLatin1);
{
masm.branch32(Assembler::BelowOrEqual, temp2, Imm32(JSFatInlineString::MAX_LENGTH_LATIN1),
&isFatInlineLatin1);
}
masm.bind(&notInline);
// Keep AND'ed flags in temp1.
// Ensure result length <= JSString::MAX_LENGTH.
masm.branch32(Assembler::Above, temp2, Imm32(JSString::MAX_LENGTH), &failure);
@ -5232,8 +5358,12 @@ JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
MOZ_ASSUME_UNREACHABLE("No such execution mode");
}
// Store lengthAndFlags.
masm.store32(Imm32(JSString::ROPE_FLAGS), Address(output, JSString::offsetOfFlags()));
// Store rope length and flags. temp1 still holds the result of AND'ing the
// lhs and rhs flags, so we just have to clear the other flags to get our
// rope flags (Latin1 if both lhs and rhs are Latin1).
static_assert(JSString::ROPE_FLAGS == 0, "Rope flags must be 0");
masm.and32(Imm32(JSString::LATIN1_CHARS_BIT), temp1);
masm.store32(temp1, Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
// Store left and right nodes.
@ -5249,62 +5379,13 @@ JitCompartment::generateStringConcatStub(JSContext *cx, ExecutionMode mode)
masm.mov(lhs, output);
masm.ret();
masm.bind(&isFatInline);
masm.bind(&isFatInlineTwoByte);
ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3, forkJoinContext,
mode, &failure, &failurePopTemps, true);
// State: lhs length in temp1, result length in temp2.
// Ensure both strings are linear.
masm.branchIfRope(lhs, &failure);
masm.branchIfRope(rhs, &failure);
// Allocate a JSFatInlineString.
switch (mode) {
case SequentialExecution:
masm.newGCFatInlineString(output, temp3, &failure);
break;
case ParallelExecution:
masm.push(temp1);
masm.push(temp2);
masm.newGCFatInlineStringPar(output, forkJoinContext, temp1, temp2, &failurePopTemps);
masm.pop(temp2);
masm.pop(temp1);
break;
default:
MOZ_ASSUME_UNREACHABLE("No such execution mode");
}
// Set length and flags.
masm.store32(Imm32(JSString::INIT_FAT_INLINE_FLAGS), Address(output, JSString::offsetOfFlags()));
masm.store32(temp2, Address(output, JSString::offsetOfLength()));
// Load chars pointer in temp2.
masm.computeEffectiveAddress(Address(output, JSInlineString::offsetOfInlineStorage()), temp2);
{
// We use temp3 in this block, which in parallel execution also holds
// a live ForkJoinContext pointer. If we are compiling for parallel
// execution, be sure to save and restore the ForkJoinContext.
if (mode == ParallelExecution)
masm.push(temp3);
// Copy lhs chars. Temp1 still holds the lhs length. Note that this
// advances temp2 to point to the next char. Note that this also
// repurposes the lhs register.
masm.loadStringChars(lhs, lhs);
CopyStringChars(masm, temp2, lhs, temp1, temp3);
// Copy rhs chars.
masm.loadStringLength(rhs, temp1);
masm.loadStringChars(rhs, rhs);
CopyStringChars(masm, temp2, rhs, temp1, temp3);
if (mode == ParallelExecution)
masm.pop(temp3);
}
// Null-terminate.
masm.store16(Imm32(0), Address(temp2, 0));
masm.ret();
masm.bind(&isFatInlineLatin1);
ConcatFatInlineString(masm, lhs, rhs, output, temp1, temp2, temp3, forkJoinContext,
mode, &failure, &failurePopTemps, false);
masm.bind(&failurePopTemps);
masm.pop(temp2);

Просмотреть файл

@ -357,11 +357,12 @@ CompareStringsPar(ForkJoinContext *cx, JSString *left, JSString *right, int32_t
{
ScopedThreadSafeStringInspector leftInspector(left);
ScopedThreadSafeStringInspector rightInspector(right);
if (!leftInspector.ensureChars(cx) || !rightInspector.ensureChars(cx))
AutoCheckCannotGC nogc;
if (!leftInspector.ensureChars(cx, nogc) || !rightInspector.ensureChars(cx, nogc))
return false;
*res = CompareChars(leftInspector.chars(), left->length(),
rightInspector.chars(), right->length());
*res = CompareChars(leftInspector.twoByteChars(), left->length(),
rightInspector.twoByteChars(), right->length());
return true;
}

Просмотреть файл

@ -1936,6 +1936,13 @@ MacroAssemblerARMCompat::and32(Imm32 imm, Register dest)
ma_and(imm, dest, SetCond);
}
void
MacroAssemblerARMCompat::and32(const Address &src, Register dest)
{
load32(src, ScratchRegister);
ma_and(ScratchRegister, dest, SetCond);
}
void
MacroAssemblerARMCompat::addPtr(Register src, Register dest)
{

Просмотреть файл

@ -1299,6 +1299,7 @@ class MacroAssemblerARMCompat : public MacroAssemblerARM
void and32(Register src, Register dest);
void and32(Imm32 imm, Register dest);
void and32(Imm32 imm, const Address &dest);
void and32(const Address &src, Register dest);
void or32(Imm32 imm, const Address &dest);
void xorPtr(Imm32 imm, Register dest);
void xorPtr(Register src, Register dest);

Просмотреть файл

@ -111,6 +111,9 @@ class MacroAssemblerX86Shared : public Assembler
void and32(Register src, Register dest) {
andl(src, dest);
}
void and32(const Address &src, Register dest) {
andl(Operand(src), dest);
}
void and32(Imm32 imm, Register dest) {
andl(imm, dest);
}

Просмотреть файл

@ -5597,14 +5597,14 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_
size_t dstlen = *dstlenp;
if (srclen > dstlen) {
InflateStringToBuffer(src, dstlen, dst);
CopyAndInflateChars(dst, src, dstlen);
AutoSuppressGC suppress(cx);
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_BUFFER_TOO_SMALL);
return false;
}
InflateStringToBuffer(src, srclen, dst);
CopyAndInflateChars(dst, src, srclen);
*dstlenp = srclen;
return true;
}

Просмотреть файл

@ -452,7 +452,7 @@ js::Atomize(ExclusiveContext *cx, const char *bytes, size_t length, InternBehavi
* js::AtomizeString rarely has to copy the temp string we make.
*/
jschar inflated[ATOMIZE_BUF_MAX];
InflateStringToBuffer(bytes, length, inflated);
CopyAndInflateChars(inflated, bytes, length);
return AtomizeAndCopyChars(cx, inflated, length, ib);
}

Просмотреть файл

@ -605,7 +605,7 @@ js::Int32ToString(ThreadSafeContext *cx, int32_t si)
jschar *start = BackfillInt32InBuffer(si, buffer,
JSFatInlineString::MAX_LENGTH_TWO_BYTE + 1, &length);
PodCopy(str->init(length), start, length + 1);
PodCopy(str->initTwoByte(length), start, length + 1);
CacheNumber(cx, si, str);
return str;
@ -1437,7 +1437,7 @@ js::IndexToString(JSContext *cx, uint32_t index)
*end = '\0';
RangedPtr<jschar> start = BackfillIndexInCharBuffer(index, end);
jschar *dst = str->init(end - start);
jschar *dst = str->initTwoByte(end - start);
PodCopy(dst, start.get(), end - start + 1);
c->dtoaCache.cache(10, index, str);
@ -1533,11 +1533,12 @@ CharsToNumber(ThreadSafeContext *cx, const jschar *chars, size_t length, double
bool
js::StringToNumber(ThreadSafeContext *cx, JSString *str, double *result)
{
AutoCheckCannotGC nogc;
ScopedThreadSafeStringInspector inspector(str);
if (!inspector.ensureChars(cx))
if (!inspector.ensureChars(cx, nogc))
return false;
return CharsToNumber(cx, inspector.chars(), str->length(), result);
return CharsToNumber(cx, inspector.twoByteChars(), str->length(), result);
}
bool

Просмотреть файл

@ -2780,8 +2780,8 @@ FlattenSubstrings(JSContext *cx, const jschar *chars,
JSFatInlineString *str = js_NewGCFatInlineString<CanGC>(cx);
if (!str)
return nullptr;
jschar *buf = str->init(outputLen);
jschar *buf = str->initTwoByte(outputLen);
size_t pos = 0;
for (size_t i = 0; i < rangesLen; i++) {
PodCopy(buf + pos, chars + ranges[i].start, ranges[i].length);

Просмотреть файл

@ -256,7 +256,7 @@ InflateString(ThreadSafeContext *cx, const char *bytes, size_t *length);
* enough for 'srclen' jschars. The buffer is NOT null-terminated.
*/
inline void
InflateStringToBuffer(const char *src, size_t srclen, jschar *dst)
CopyAndInflateChars(jschar *dst, const char *src, size_t srclen)
{
for (size_t i = 0; i < srclen; i++)
dst[i] = (unsigned char) src[i];

Просмотреть файл

@ -132,9 +132,11 @@ DeflateStringToUTF8Buffer(js::ThreadSafeContext *cx, const jschar *src, size_t s
bufferTooSmall:
*dstlenp = (origDstlen - dstlen);
if (cx->isJSContext())
if (cx->isJSContext()) {
js::gc::AutoSuppressGC suppress(cx->asJSContext());
JS_ReportErrorNumber(cx->asJSContext(), js_GetErrorMessage, nullptr,
JSMSG_BUFFER_TOO_SMALL);
}
return false;
}

Просмотреть файл

@ -279,11 +279,12 @@ intrinsic_ParallelSpew(ThreadSafeContext *cx, unsigned argc, Value *vp)
JS_ASSERT(args.length() == 1);
JS_ASSERT(args[0].isString());
AutoCheckCannotGC nogc;
ScopedThreadSafeStringInspector inspector(args[0].toString());
if (!inspector.ensureChars(cx))
if (!inspector.ensureChars(cx, nogc))
return false;
ScopedJSFreePtr<char> bytes(TwoByteCharsToNewUTF8CharsZ(cx, inspector.range()).c_str());
ScopedJSFreePtr<char> bytes(TwoByteCharsToNewUTF8CharsZ(cx, inspector.twoByteRange()).c_str());
parallel::Spew(parallel::SpewOps, bytes);
args.rval().setUndefined();

Просмотреть файл

@ -32,12 +32,12 @@ NewFatInlineString(ThreadSafeContext *cx, JS::Latin1Chars chars)
str = JSInlineString::new_<allowGC>(cx);
if (!str)
return nullptr;
p = str->init(len);
p = str->initTwoByte(len);
} else {
JSFatInlineString *fatstr = JSFatInlineString::new_<allowGC>(cx);
if (!fatstr)
return nullptr;
p = fatstr->init(len);
p = fatstr->initTwoByte(len);
str = fatstr;
}
@ -65,12 +65,12 @@ NewFatInlineString(ExclusiveContext *cx, JS::TwoByteChars chars)
str = JSInlineString::new_<allowGC>(cx);
if (!str)
return nullptr;
storage = str->init(len);
storage = str->initTwoByte(len);
} else {
JSFatInlineString *fatstr = JSFatInlineString::new_<allowGC>(cx);
if (!fatstr)
return nullptr;
storage = fatstr->init(len);
storage = fatstr->initTwoByte(len);
str = fatstr;
}
@ -107,6 +107,8 @@ JSRope::init(js::ThreadSafeContext *cx, JSString *left, JSString *right, size_t
{
d.u1.length = length;
d.u1.flags = ROPE_FLAGS;
if (left->hasLatin1Chars() && right->hasLatin1Chars())
d.u1.flags |= LATIN1_CHARS_BIT;
d.s.u2.left = left;
d.s.u3.right = right;
js::StringWriteBarrierPost(cx, &d.s.u2.left);
@ -248,7 +250,7 @@ JSInlineString::new_(js::ThreadSafeContext *cx)
}
MOZ_ALWAYS_INLINE jschar *
JSInlineString::init(size_t length)
JSInlineString::initTwoByte(size_t length)
{
JS_ASSERT(twoByteLengthFits(length));
d.u1.length = length;
@ -256,8 +258,17 @@ JSInlineString::init(size_t length)
return d.inlineStorageTwoByte;
}
MOZ_ALWAYS_INLINE char *
JSInlineString::initLatin1(size_t length)
{
JS_ASSERT(latin1LengthFits(length));
d.u1.length = length;
d.u1.flags = INIT_INLINE_FLAGS | LATIN1_CHARS_BIT;
return d.inlineStorageLatin1;
}
MOZ_ALWAYS_INLINE jschar *
JSFatInlineString::init(size_t length)
JSFatInlineString::initTwoByte(size_t length)
{
JS_ASSERT(twoByteLengthFits(length));
d.u1.length = length;
@ -265,6 +276,15 @@ JSFatInlineString::init(size_t length)
return d.inlineStorageTwoByte;
}
MOZ_ALWAYS_INLINE char *
JSFatInlineString::initLatin1(size_t length)
{
JS_ASSERT(latin1LengthFits(length));
d.u1.length = length;
d.u1.flags = INIT_FAT_INLINE_FLAGS | LATIN1_CHARS_BIT;
return d.inlineStorageLatin1;
}
template <js::AllowGC allowGC>
MOZ_ALWAYS_INLINE JSFatInlineString *
JSFatInlineString::new_(js::ThreadSafeContext *cx)
@ -339,7 +359,7 @@ JSFlatString::finalize(js::FreeOp *fop)
JS_ASSERT(getAllocKind() != js::gc::FINALIZE_FAT_INLINE_STRING);
if (!isInline())
fop->free_(const_cast<jschar *>(nonInlineChars()));
fop->free_(nonInlineCharsRaw());
}
inline void
@ -348,7 +368,7 @@ JSFatInlineString::finalize(js::FreeOp *fop)
JS_ASSERT(getAllocKind() == js::gc::FINALIZE_FAT_INLINE_STRING);
if (!isInline())
fop->free_(const_cast<jschar *>(nonInlineChars()));
fop->free_(nonInlineCharsRaw());
}
inline void
@ -358,7 +378,7 @@ JSAtom::finalize(js::FreeOp *fop)
JS_ASSERT(JSString::isFlat());
if (!isInline())
fop->free_(const_cast<jschar *>(nonInlineChars()));
fop->free_(nonInlineCharsRaw());
}
inline void

Просмотреть файл

@ -405,21 +405,39 @@ js::ConcatStrings(ThreadSafeContext *cx,
if (!JSString::validateLength(cx, wholeLength))
return nullptr;
if (JSFatInlineString::twoByteLengthFits(wholeLength) && cx->isJSContext()) {
bool isLatin1 = left->hasLatin1Chars() && right->hasLatin1Chars();
bool canUseFatInline = isLatin1
? JSFatInlineString::latin1LengthFits(wholeLength)
: JSFatInlineString::twoByteLengthFits(wholeLength);
if (canUseFatInline && cx->isJSContext()) {
JSFatInlineString *str = js_NewGCFatInlineString<allowGC>(cx);
if (!str)
return nullptr;
AutoCheckCannotGC nogc;
ScopedThreadSafeStringInspector leftInspector(left);
ScopedThreadSafeStringInspector rightInspector(right);
if (!leftInspector.ensureChars(cx) || !rightInspector.ensureChars(cx))
if (!leftInspector.ensureChars(cx, nogc) || !rightInspector.ensureChars(cx, nogc))
return nullptr;
jschar *buf = str->init(wholeLength);
PodCopy(buf, leftInspector.chars(), leftLen);
PodCopy(buf + leftLen, rightInspector.chars(), rightLen);
if (isLatin1) {
char *buf = str->initLatin1(wholeLength);
PodCopy(buf, leftInspector.latin1Chars(), leftLen);
PodCopy(buf + leftLen, rightInspector.latin1Chars(), rightLen);
buf[wholeLength] = 0;
} else {
jschar *buf = str->initTwoByte(wholeLength);
if (leftInspector.hasTwoByteChars())
PodCopy(buf, leftInspector.twoByteChars(), leftLen);
else
CopyAndInflateChars(buf, leftInspector.latin1Chars(), leftLen);
if (rightInspector.hasTwoByteChars())
PodCopy(buf + leftLen, rightInspector.twoByteChars(), rightLen);
else
CopyAndInflateChars(buf + leftLen, rightInspector.latin1Chars(), rightLen);
buf[wholeLength] = 0;
}
buf[wholeLength] = 0;
return str;
}
@ -530,27 +548,35 @@ JSFlatString::isIndexSlow(uint32_t *indexp) const
}
bool
ScopedThreadSafeStringInspector::ensureChars(ThreadSafeContext *cx)
ScopedThreadSafeStringInspector::ensureChars(ThreadSafeContext *cx, const AutoCheckCannotGC &nogc)
{
if (chars_)
if (state_ != Uninitialized)
return true;
if (cx->isExclusiveContext()) {
JSLinearString *linear = str_->ensureLinear(cx->asExclusiveContext());
if (!linear)
return false;
chars_ = linear->chars();
if (linear->hasTwoByteChars()) {
state_ = TwoByte;
twoByteChars_ = linear->twoByteChars(nogc);
} else {
state_ = Latin1;
latin1Chars_ = linear->latin1Chars(nogc);
}
} else {
if (str_->hasPureChars()) {
chars_ = str_->pureChars();
state_ = TwoByte;
twoByteChars_ = str_->pureChars();
} else {
if (!str_->copyNonPureChars(cx, scopedChars_))
return false;
chars_ = scopedChars_;
state_ = TwoByte;
twoByteChars_ = scopedChars_;
}
}
JS_ASSERT(chars_);
MOZ_ASSERT(state_ != Uninitialized);
return true;
}

Просмотреть файл

@ -577,6 +577,17 @@ class JSLinearString : public JSString
bool isLinear() const MOZ_DELETE;
JSLinearString &asLinear() const MOZ_DELETE;
protected:
/* Returns void pointer to latin1/twoByte chars, for finalizers. */
MOZ_ALWAYS_INLINE
void *nonInlineCharsRaw() const {
JS_ASSERT(!isInline());
static_assert(offsetof(JSLinearString, d.s.u2.nonInlineCharsTwoByte) ==
offsetof(JSLinearString, d.s.u2.nonInlineCharsLatin1),
"nonInlineCharsTwoByte and nonInlineCharsLatin1 must have same offset");
return (void *)d.s.u2.nonInlineCharsTwoByte;
}
public:
MOZ_ALWAYS_INLINE
const jschar *nonInlineChars() const {
@ -734,7 +745,8 @@ class JSInlineString : public JSFlatString
template <js::AllowGC allowGC>
static inline JSInlineString *new_(js::ThreadSafeContext *cx);
inline jschar *init(size_t length);
inline jschar *initTwoByte(size_t length);
inline char *initLatin1(size_t length);
inline void resetLength(size_t length);
@ -822,7 +834,8 @@ class JSFatInlineString : public JSInlineString
INLINE_EXTENSION_CHARS_TWO_BYTE
-1 /* null terminator */;
inline jschar *init(size_t length);
inline jschar *initTwoByte(size_t length);
inline char *initLatin1(size_t length);
static bool latin1LengthFits(size_t length) {
return length <= MAX_LENGTH_LATIN1;
@ -924,24 +937,36 @@ class ScopedThreadSafeStringInspector
private:
JSString *str_;
ScopedJSFreePtr<jschar> scopedChars_;
const jschar *chars_;
union {
const jschar *twoByteChars_;
const char *latin1Chars_;
};
enum State { Uninitialized, Latin1, TwoByte };
State state_;
public:
explicit ScopedThreadSafeStringInspector(JSString *str)
: str_(str),
chars_(nullptr)
state_(Uninitialized)
{ }
bool ensureChars(ThreadSafeContext *cx);
bool ensureChars(ThreadSafeContext *cx, const JS::AutoCheckCannotGC &nogc);
const jschar *chars() {
JS_ASSERT(chars_);
return chars_;
bool hasTwoByteChars() const { return state_ == TwoByte; }
bool hasLatin1Chars() const { return state_ == Latin1; }
const jschar *twoByteChars() const {
MOZ_ASSERT(state_ == TwoByte);
return twoByteChars_;
}
const char *latin1Chars() const {
MOZ_ASSERT(state_ == Latin1);
return latin1Chars_;
}
JS::TwoByteChars range() {
JS_ASSERT(chars_);
return JS::TwoByteChars(chars_, str_->length());
JS::TwoByteChars twoByteRange() const {
MOZ_ASSERT(state_ == TwoByte);
return JS::TwoByteChars(twoByteChars_, str_->length());
}
};

Просмотреть файл

@ -120,7 +120,7 @@ StringBuffer::appendInflated(const char *cstr, size_t cstrlen)
size_t lengthBefore = length();
if (!cb.growByUninitialized(cstrlen))
return false;
InflateStringToBuffer(cstr, cstrlen, begin() + lengthBefore);
CopyAndInflateChars(begin() + lengthBefore, cstr, cstrlen);
return true;
}