Bug 1027528 part 19 - Make XDR work with Latin1 strings. r=luke

This commit is contained in:
Jan de Mooij 2014-06-24 12:01:39 +02:00
parent 485c960644
commit d8235f40b3
6 changed files with 78 additions and 38 deletions

View File

@ -23,3 +23,15 @@ var ff = function() { return 10; };
ff.toSource = function() { return "((11))"; }
Object.defineProperty(o, "prop", {get: ff, set: ff, enumerable: true});
assertEq(o.toSource(), "({prop:((11)), prop:((11))})");
// XDR
load(libdir + 'bytecode-cache.js');
// Latin1 string constant
toLatin1("string123");
test = "'string123';";
evalWithCache(test, { assertEqBytecode: true, assertEqResult : true });
// TwoByte string constant
test = "'string\u1234';";
evalWithCache(test, { assertEqBytecode: true, assertEqResult : true });

View File

@ -1,7 +1,6 @@
var s = "Foo123";
assertEq(isLatin1(s), false);
assertEq(isLatin1("Foo123\u1200"), false);
s = toLatin1(s);
s = toLatin1("Foo123");
assertEq(isLatin1(s), true);
function testEq(s) {

View File

@ -42,8 +42,10 @@ function testSearchRope() {
// Latin1 + Latin1
s1 = "foobarbaz0123456789".repeat(10);
s1.indexOf("333"); // flatten
s1 = toLatin1(s1);
var ropeLatin1 = s1 + toLatin1("abcdef\u00AA");
assertEq(isLatin1(ropeLatin1), false);
assertEq(isLatin1(ropeLatin1), true);
assertEq(ropeLatin1.search(abc), 190);
// Latin1 + TwoByte

View File

@ -589,53 +589,62 @@ bool
js::XDRAtom(XDRState<mode> *xdr, MutableHandleAtom atomp)
{
if (mode == XDR_ENCODE) {
uint32_t nchars = atomp->length();
if (!xdr->codeUint32(&nchars))
static_assert(JSString::MAX_LENGTH <= INT32_MAX, "String length must fit in 31 bits");
uint32_t length = atomp->length();
uint32_t lengthAndEncoding = (length << 1) | uint32_t(atomp->hasLatin1Chars());
if (!xdr->codeUint32(&lengthAndEncoding))
return false;
jschar *chars = const_cast<jschar *>(atomp->getChars(xdr->cx()));
if (!chars)
return false;
return xdr->codeChars(chars, nchars);
JS::AutoCheckCannotGC nogc;
return atomp->hasLatin1Chars()
? xdr->codeChars(atomp->latin1Chars(nogc), length)
: xdr->codeChars(const_cast<jschar*>(atomp->twoByteChars(nogc)), length);
}
/* Avoid JSString allocation for already existing atoms. See bug 321985. */
uint32_t nchars;
if (!xdr->codeUint32(&nchars))
uint32_t lengthAndEncoding;
if (!xdr->codeUint32(&lengthAndEncoding))
return false;
uint32_t length = lengthAndEncoding >> 1;
bool latin1 = lengthAndEncoding & 0x1;
JSContext *cx = xdr->cx();
JSAtom *atom;
#if IS_LITTLE_ENDIAN
/* Directly access the little endian chars in the XDR buffer. */
const jschar *chars = reinterpret_cast<const jschar *>(xdr->buf.read(nchars * sizeof(jschar)));
atom = AtomizeChars(cx, chars, nchars);
#else
/*
* We must copy chars to a temporary buffer to convert between little and
* big endian data.
*/
jschar *chars;
jschar stackChars[256];
if (nchars <= ArrayLength(stackChars)) {
chars = stackChars;
if (latin1) {
const Latin1Char *chars = reinterpret_cast<const Latin1Char *>(xdr->buf.read(length));
atom = AtomizeChars(cx, chars, length);
} else {
#if IS_LITTLE_ENDIAN
/* Directly access the little endian chars in the XDR buffer. */
const jschar *chars = reinterpret_cast<const jschar *>(xdr->buf.read(length * sizeof(jschar)));
atom = AtomizeChars(cx, chars, length);
#else
/*
* This is very uncommon. Don't use the tempLifoAlloc arena for this as
* most allocations here will be bigger than tempLifoAlloc's default
* chunk size.
* We must copy chars to a temporary buffer to convert between little and
* big endian data.
*/
chars = cx->runtime()->pod_malloc<jschar>(nchars);
if (!chars)
return false;
}
jschar *chars;
jschar stackChars[256];
if (length <= ArrayLength(stackChars)) {
chars = stackChars;
} else {
/*
* This is very uncommon. Don't use the tempLifoAlloc arena for this as
* most allocations here will be bigger than tempLifoAlloc's default
* chunk size.
*/
chars = cx->runtime()->pod_malloc<jschar>(length);
if (!chars)
return false;
}
JS_ALWAYS_TRUE(xdr->codeChars(chars, nchars));
atom = AtomizeChars(cx, chars, nchars);
if (chars != stackChars)
js_free(chars);
JS_ALWAYS_TRUE(xdr->codeChars(chars, length));
atom = AtomizeChars(cx, chars, length);
if (chars != stackChars)
js_free(chars);
#endif /* !IS_LITTLE_ENDIAN */
}
if (!atom)
return false;

View File

@ -33,6 +33,7 @@ XDRBuffer::grow(size_t n)
size_t offset = cursor - base;
size_t newCapacity = JS_ROUNDUP(offset + n, MEM_BLOCK);
if (isUint32Overflow(newCapacity)) {
js::gc::AutoSuppressGC suppressGC(cx());
JS_ReportErrorNumber(cx(), js_GetErrorMessage, nullptr, JSMSG_TOO_BIG_TO_ENCODE);
return false;
}
@ -48,6 +49,22 @@ XDRBuffer::grow(size_t n)
return true;
}
template<XDRMode mode>
bool
XDRState<mode>::codeChars(const Latin1Char *chars, size_t nchars)
{
static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte");
MOZ_ASSERT(mode == XDR_ENCODE);
uint8_t *ptr = buf.write(nchars);
if (!ptr)
return false;
mozilla::PodCopy(ptr, chars, nchars);
return true;
}
template<XDRMode mode>
bool
XDRState<mode>::codeChars(jschar *chars, size_t nchars)

View File

@ -28,7 +28,7 @@ namespace js {
*
* https://developer.mozilla.org/en-US/docs/SpiderMonkey/Internals/Bytecode
*/
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 173);
static const uint32_t XDR_BYTECODE_VERSION = uint32_t(0xb973c0de - 174);
class XDRBuffer {
public:
@ -229,6 +229,7 @@ class XDRState {
return true;
}
bool codeChars(const JS::Latin1Char *chars, size_t nchars);
bool codeChars(jschar *chars, size_t nchars);
bool codeFunction(JS::MutableHandleObject objp);