mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-13 19:41:49 +00:00
Bug 1027528 part 15 - Make structured clone work with Latin1 strings. r=jorendorff,bent
This commit is contained in:
parent
d36e64fdcd
commit
21cfe56f5f
@ -35,11 +35,11 @@ namespace {
|
||||
|
||||
// If JS_STRUCTURED_CLONE_VERSION changes then we need to update our major
|
||||
// schema version.
|
||||
static_assert(JS_STRUCTURED_CLONE_VERSION == 2,
|
||||
static_assert(JS_STRUCTURED_CLONE_VERSION == 3,
|
||||
"Need to update the major schema version.");
|
||||
|
||||
// Major schema version. Bump for almost everything.
|
||||
const uint32_t kMajorSchemaVersion = 14;
|
||||
const uint32_t kMajorSchemaVersion = 15;
|
||||
|
||||
// Minor schema version. Should almost always be 0 (maybe bump on release
|
||||
// branches if we have to).
|
||||
@ -1460,6 +1460,17 @@ UpgradeSchemaFrom13_0To14_0(mozIStorageConnection* aConnection)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
UpgradeSchemaFrom14_0To15_0(mozIStorageConnection* aConnection)
|
||||
{
|
||||
// The only change between 14 and 15 was a different structured
|
||||
// clone format, but it's backwards-compatible.
|
||||
nsresult rv = aConnection->SetSchemaVersion(MakeSchemaVersion(15, 0));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
class VersionChangeEventsRunnable;
|
||||
|
||||
class SetVersionHelper : public AsyncConnectionHelper,
|
||||
@ -2073,7 +2084,7 @@ OpenDatabaseHelper::CreateDatabaseConnection(
|
||||
}
|
||||
else {
|
||||
// This logic needs to change next time we change the schema!
|
||||
static_assert(kSQLiteSchemaVersion == int32_t((14 << 4) + 0),
|
||||
static_assert(kSQLiteSchemaVersion == int32_t((15 << 4) + 0),
|
||||
"Need upgrade code from schema version increase.");
|
||||
|
||||
while (schemaVersion != kSQLiteSchemaVersion) {
|
||||
@ -2108,6 +2119,9 @@ OpenDatabaseHelper::CreateDatabaseConnection(
|
||||
else if (schemaVersion == MakeSchemaVersion(13, 0)) {
|
||||
rv = UpgradeSchemaFrom13_0To14_0(connection);
|
||||
}
|
||||
else if (schemaVersion == MakeSchemaVersion(14, 0)) {
|
||||
rv = UpgradeSchemaFrom14_0To15_0(connection);
|
||||
}
|
||||
else {
|
||||
NS_WARNING("Unable to open IndexedDB database, no upgrade path is "
|
||||
"available!");
|
||||
|
@ -121,7 +121,7 @@ typedef void (*FreeTransferStructuredCloneOp)(uint32_t tag, JS::TransferableOwne
|
||||
// The maximum supported structured-clone serialization format version. Note
|
||||
// that this does not need to be bumped for Transferable-only changes, since
|
||||
// they are never saved to persistent storage.
|
||||
#define JS_STRUCTURED_CLONE_VERSION 2
|
||||
#define JS_STRUCTURED_CLONE_VERSION 3
|
||||
|
||||
struct JSStructuredCloneCallbacks {
|
||||
ReadStructuredCloneOp read;
|
||||
|
19
js/src/jit-test/tests/latin1/structured-clone.js
Normal file
19
js/src/jit-test/tests/latin1/structured-clone.js
Normal file
@ -0,0 +1,19 @@
|
||||
// Latin1
|
||||
var s = deserialize(serialize(toLatin1("foo123\u00EE")));
|
||||
assertEq(s, "foo123\u00EE");
|
||||
assertEq(isLatin1(s), true);
|
||||
|
||||
var o = deserialize(serialize(new String(toLatin1("foo\u00EE"))));
|
||||
assertEq(typeof o, "object");
|
||||
assertEq(o.valueOf(), "foo\u00EE");
|
||||
assertEq(isLatin1(o.valueOf()), true);
|
||||
|
||||
// TwoByte
|
||||
var s = deserialize(serialize("foo123\u00FF\u1234"));
|
||||
assertEq(s, "foo123\u00FF\u1234");
|
||||
assertEq(isLatin1(s), false);
|
||||
|
||||
var o = deserialize(serialize(new String("foo\uEEEE")));
|
||||
assertEq(typeof o, "object");
|
||||
assertEq(o.valueOf(), "foo\uEEEE");
|
||||
assertEq(isLatin1(o.valueOf()), false);
|
@ -135,6 +135,7 @@ struct SCOutput {
|
||||
bool writePair(uint32_t tag, uint32_t data);
|
||||
bool writeDouble(double d);
|
||||
bool writeBytes(const void *p, size_t nbytes);
|
||||
bool writeChars(const Latin1Char *p, size_t nchars);
|
||||
bool writeChars(const jschar *p, size_t nchars);
|
||||
bool writePtr(const void *);
|
||||
|
||||
@ -165,6 +166,7 @@ class SCInput {
|
||||
bool readPair(uint32_t *tagp, uint32_t *datap);
|
||||
bool readDouble(double *p);
|
||||
bool readBytes(void *p, size_t nbytes);
|
||||
bool readChars(Latin1Char *p, size_t nchars);
|
||||
bool readChars(jschar *p, size_t nchars);
|
||||
bool readPtr(void **);
|
||||
|
||||
@ -212,8 +214,11 @@ struct JSStructuredCloneReader {
|
||||
|
||||
bool readTransferMap();
|
||||
|
||||
template <typename CharT>
|
||||
JSString *readStringImpl(uint32_t nchars);
|
||||
JSString *readString(uint32_t data);
|
||||
|
||||
bool checkDouble(double d);
|
||||
JSString *readString(uint32_t nchars);
|
||||
bool readTypedArray(uint32_t arrayType, uint32_t nelems, Value *vp, bool v1Read = false);
|
||||
bool readArrayBuffer(uint32_t nbytes, Value *vp);
|
||||
bool readV1ArrayBuffer(uint32_t arrayType, uint32_t nelems, Value *vp);
|
||||
@ -553,6 +558,13 @@ SCInput::readBytes(void *p, size_t nbytes)
|
||||
return readArray((uint8_t *) p, nbytes);
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::readChars(Latin1Char *p, size_t nchars)
|
||||
{
|
||||
static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte");
|
||||
return readBytes(p, nchars);
|
||||
}
|
||||
|
||||
bool
|
||||
SCInput::readChars(jschar *p, size_t nchars)
|
||||
{
|
||||
@ -689,6 +701,13 @@ SCOutput::writeChars(const jschar *p, size_t nchars)
|
||||
return writeArray((const uint16_t *) p, nchars);
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::writeChars(const Latin1Char *p, size_t nchars)
|
||||
{
|
||||
static_assert(sizeof(Latin1Char) == sizeof(uint8_t), "Latin1Char must fit in 1 byte");
|
||||
return writeBytes(p, nchars);
|
||||
}
|
||||
|
||||
bool
|
||||
SCOutput::writePtr(const void *p)
|
||||
{
|
||||
@ -775,11 +794,21 @@ JSStructuredCloneWriter::reportErrorTransferable()
|
||||
bool
|
||||
JSStructuredCloneWriter::writeString(uint32_t tag, JSString *str)
|
||||
{
|
||||
size_t length = str->length();
|
||||
const jschar *chars = str->getChars(context());
|
||||
if (!chars)
|
||||
JSLinearString *linear = str->ensureLinear(context());
|
||||
if (!linear)
|
||||
return false;
|
||||
return out.writePair(tag, uint32_t(length)) && out.writeChars(chars, length);
|
||||
|
||||
static_assert(JSString::MAX_LENGTH <= INT32_MAX, "String length must fit in 31 bits");
|
||||
|
||||
uint32_t length = linear->length();
|
||||
uint32_t lengthAndEncoding = length | (uint32_t(linear->hasLatin1Chars()) << 31);
|
||||
if (!out.writePair(tag, lengthAndEncoding))
|
||||
return false;
|
||||
|
||||
JS::AutoCheckCannotGC nogc;
|
||||
return linear->hasLatin1Chars()
|
||||
? out.writeChars(linear->latin1Chars(nogc), length)
|
||||
: out.writeChars(linear->twoByteChars(nogc), length);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -1134,9 +1163,10 @@ JSStructuredCloneReader::checkDouble(double d)
|
||||
|
||||
namespace {
|
||||
|
||||
template <typename CharT>
|
||||
class Chars {
|
||||
JSContext *cx;
|
||||
jschar *p;
|
||||
CharT *p;
|
||||
public:
|
||||
explicit Chars(JSContext *cx) : cx(cx), p(nullptr) {}
|
||||
~Chars() { js_free(p); }
|
||||
@ -1144,28 +1174,29 @@ class Chars {
|
||||
bool allocate(size_t len) {
|
||||
JS_ASSERT(!p);
|
||||
// We're going to null-terminate!
|
||||
p = cx->pod_malloc<jschar>(len + 1);
|
||||
p = cx->pod_malloc<CharT>(len + 1);
|
||||
if (p) {
|
||||
p[len] = jschar(0);
|
||||
p[len] = CharT(0);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
jschar *get() { return p; }
|
||||
CharT *get() { return p; }
|
||||
void forget() { p = nullptr; }
|
||||
};
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
template <typename CharT>
|
||||
JSString *
|
||||
JSStructuredCloneReader::readString(uint32_t nchars)
|
||||
JSStructuredCloneReader::readStringImpl(uint32_t nchars)
|
||||
{
|
||||
if (nchars > JSString::MAX_LENGTH) {
|
||||
JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr,
|
||||
JSMSG_SC_BAD_SERIALIZED_DATA, "string length");
|
||||
return nullptr;
|
||||
}
|
||||
Chars chars(context());
|
||||
Chars<CharT> chars(context());
|
||||
if (!chars.allocate(nchars) || !in.readChars(chars.get(), nchars))
|
||||
return nullptr;
|
||||
JSString *str = NewString<CanGC>(context(), chars.get(), nchars);
|
||||
@ -1174,6 +1205,14 @@ JSStructuredCloneReader::readString(uint32_t nchars)
|
||||
return str;
|
||||
}
|
||||
|
||||
JSString *
|
||||
JSStructuredCloneReader::readString(uint32_t data)
|
||||
{
|
||||
uint32_t nchars = data & JS_BITMASK(31);
|
||||
bool latin1 = data & (1 << 31);
|
||||
return latin1 ? readStringImpl<Latin1Char>(nchars) : readStringImpl<jschar>(nchars);
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
TagToV1ArrayType(uint32_t tag)
|
||||
{
|
||||
@ -1388,15 +1427,15 @@ JSStructuredCloneReader::startRead(Value *vp)
|
||||
|
||||
case SCTAG_REGEXP_OBJECT: {
|
||||
RegExpFlag flags = RegExpFlag(data);
|
||||
uint32_t tag2, nchars;
|
||||
if (!in.readPair(&tag2, &nchars))
|
||||
uint32_t tag2, stringData;
|
||||
if (!in.readPair(&tag2, &stringData))
|
||||
return false;
|
||||
if (tag2 != SCTAG_STRING) {
|
||||
JS_ReportErrorNumber(context(), js_GetErrorMessage, nullptr,
|
||||
JSMSG_SC_BAD_SERIALIZED_DATA, "regexp");
|
||||
return false;
|
||||
}
|
||||
JSString *str = readString(nchars);
|
||||
JSString *str = readString(stringData);
|
||||
if (!str)
|
||||
return false;
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user