Commit c4874b2f authored by jbroman's avatar jbroman Committed by Commit bot

Blink-compatible serialization of RegExp objects.

BUG=chromium:148757

Review-Url: https://codereview.chromium.org/2262013002
Cr-Commit-Position: refs/heads/master@{#38835}
parent 7695642e
......@@ -79,6 +79,9 @@ enum class SerializationTag : uint8_t {
kNumberObject = 'n',
// String object, UTF-8 encoding. byteLength:uint32_t, then raw data.
kStringObject = 's',
// Regular expression, UTF-8 encoding. byteLength:uint32_t, raw data,
// flags:uint32_t.
kRegExp = 'R',
};
ValueSerializer::ValueSerializer(Isolate* isolate)
......@@ -283,6 +286,9 @@ Maybe<bool> ValueSerializer::WriteJSReceiver(Handle<JSReceiver> receiver) {
return Just(true);
case JS_VALUE_TYPE:
return WriteJSValue(Handle<JSValue>::cast(receiver));
case JS_REGEXP_TYPE:
WriteJSRegExp(JSRegExp::cast(*receiver));
return Just(true);
default:
UNIMPLEMENTED();
break;
......@@ -400,6 +406,17 @@ Maybe<bool> ValueSerializer::WriteJSValue(Handle<JSValue> value) {
return Just(true);
}
void ValueSerializer::WriteJSRegExp(JSRegExp* regexp) {
WriteTag(SerializationTag::kRegExp);
v8::Local<v8::String> api_string =
Utils::ToLocal(handle(regexp->Pattern(), isolate_));
uint32_t utf8_length = api_string->Utf8Length();
WriteVarint(utf8_length);
api_string->WriteUtf8(reinterpret_cast<char*>(ReserveRawBytes(utf8_length)),
utf8_length, nullptr, v8::String::NO_NULL_TERMINATION);
WriteVarint(static_cast<uint32_t>(regexp->GetFlags()));
}
Maybe<uint32_t> ValueSerializer::WriteJSObjectProperties(
Handle<JSObject> object, Handle<FixedArray> keys) {
uint32_t properties_written = 0;
......@@ -587,6 +604,8 @@ MaybeHandle<Object> ValueDeserializer::ReadObject() {
case SerializationTag::kNumberObject:
case SerializationTag::kStringObject:
return ReadJSValue(tag);
case SerializationTag::kRegExp:
return ReadJSRegExp();
default:
return MaybeHandle<Object>();
}
......@@ -767,6 +786,21 @@ MaybeHandle<JSValue> ValueDeserializer::ReadJSValue(SerializationTag tag) {
return value;
}
MaybeHandle<JSRegExp> ValueDeserializer::ReadJSRegExp() {
uint32_t id = next_id_++;
Handle<String> pattern;
uint32_t raw_flags;
Handle<JSRegExp> regexp;
if (!ReadUtf8String().ToHandle(&pattern) ||
!ReadVarint<uint32_t>().To(&raw_flags) ||
!JSRegExp::New(pattern, static_cast<JSRegExp::Flags>(raw_flags))
.ToHandle(&regexp)) {
return MaybeHandle<JSRegExp>();
}
AddObjectWithID(id, regexp);
return regexp;
}
Maybe<uint32_t> ValueDeserializer::ReadJSObjectProperties(
Handle<JSObject> object, SerializationTag end_tag) {
for (uint32_t num_properties = 0;; num_properties++) {
......
......@@ -21,6 +21,7 @@ namespace internal {
class HeapNumber;
class Isolate;
class JSDate;
class JSRegExp;
class JSValue;
class Object;
class Oddball;
......@@ -77,6 +78,7 @@ class ValueSerializer {
Maybe<bool> WriteJSArray(Handle<JSArray> array) WARN_UNUSED_RESULT;
void WriteJSDate(JSDate* date);
Maybe<bool> WriteJSValue(Handle<JSValue> value) WARN_UNUSED_RESULT;
void WriteJSRegExp(JSRegExp* regexp);
/*
* Reads the specified keys from the object and writes key-value pairs to the
......@@ -149,6 +151,7 @@ class ValueDeserializer {
MaybeHandle<JSArray> ReadDenseJSArray() WARN_UNUSED_RESULT;
MaybeHandle<JSDate> ReadJSDate() WARN_UNUSED_RESULT;
MaybeHandle<JSValue> ReadJSValue(SerializationTag tag) WARN_UNUSED_RESULT;
MaybeHandle<JSRegExp> ReadJSRegExp() WARN_UNUSED_RESULT;
/*
* Reads key-value pairs into the object until the specified end tag is
......
......@@ -1263,5 +1263,64 @@ TEST_F(ValueSerializerTest, DecodeValueObjects) {
});
}
TEST_F(ValueSerializerTest, RoundTripRegExp) {
RoundTripTest("/foo/g", [this](Local<Value> value) {
ASSERT_TRUE(value->IsRegExp());
EXPECT_TRUE(EvaluateScriptForResultBool(
"Object.getPrototypeOf(result) === RegExp.prototype"));
EXPECT_TRUE(EvaluateScriptForResultBool("result.toString() === '/foo/g'"));
});
RoundTripTest("new RegExp('Qu\\xe9bec', 'i')", [this](Local<Value> value) {
ASSERT_TRUE(value->IsRegExp());
EXPECT_TRUE(
EvaluateScriptForResultBool("result.toString() === '/Qu\\xe9bec/i'"));
});
RoundTripTest("new RegExp('\\ud83d\\udc4a', 'ug')",
[this](Local<Value> value) {
ASSERT_TRUE(value->IsRegExp());
EXPECT_TRUE(EvaluateScriptForResultBool(
"result.toString() === '/\\ud83d\\udc4a/gu'"));
});
RoundTripTest(
"({ a: /foo/gi, get b() { return this.a; }})",
[this](Local<Value> value) {
EXPECT_TRUE(EvaluateScriptForResultBool("result.a instanceof RegExp"));
EXPECT_TRUE(EvaluateScriptForResultBool("result.a === result.b"));
});
}
TEST_F(ValueSerializerTest, DecodeRegExp) {
DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x01},
[this](Local<Value> value) {
ASSERT_TRUE(value->IsRegExp());
EXPECT_TRUE(EvaluateScriptForResultBool(
"Object.getPrototypeOf(result) === RegExp.prototype"));
EXPECT_TRUE(EvaluateScriptForResultBool(
"result.toString() === '/foo/g'"));
});
DecodeTest({0xff, 0x09, 0x3f, 0x00, 0x52, 0x07, 0x51, 0x75, 0xc3, 0xa9, 0x62,
0x65, 0x63, 0x02},
[this](Local<Value> value) {
ASSERT_TRUE(value->IsRegExp());
EXPECT_TRUE(EvaluateScriptForResultBool(
"result.toString() === '/Qu\\xe9bec/i'"));
});
DecodeTest(
{0xff, 0x09, 0x3f, 0x00, 0x52, 0x04, 0xf0, 0x9f, 0x91, 0x8a, 0x11, 0x00},
[this](Local<Value> value) {
ASSERT_TRUE(value->IsRegExp());
EXPECT_TRUE(EvaluateScriptForResultBool(
"result.toString() === '/\\ud83d\\udc4a/gu'"));
});
DecodeTest(
{0xff, 0x09, 0x3f, 0x00, 0x6f, 0x3f, 0x01, 0x53, 0x01, 0x61,
0x3f, 0x01, 0x52, 0x03, 0x66, 0x6f, 0x6f, 0x03, 0x3f, 0x02,
0x53, 0x01, 0x62, 0x3f, 0x02, 0x5e, 0x01, 0x7b, 0x02, 0x00},
[this](Local<Value> value) {
EXPECT_TRUE(EvaluateScriptForResultBool("result.a instanceof RegExp"));
EXPECT_TRUE(EvaluateScriptForResultBool("result.a === result.b"));
});
}
} // namespace
} // namespace v8
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment