Commit 69bc22e7 authored by Jakob Gruber's avatar Jakob Gruber Committed by Commit Bot

Extend two-byte-in-one-byte string test

This CL makes the test stricter by requiring specific string shapes;
before it was possible to skip verification if strings were
short-circuited, which I believe is no longer possible due to thin
strings.

I also added a regression test for the linked bug, which requires
a String.p.split call on a two-byte-in-one-byte string with an empty
string separator argument.

Bug: chromium:1088179
Change-Id: Ibb3180afe612a64fcf6a506d18bbc415840526a8
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2228609Reviewed-by: 's avatarLeszek Swirski <leszeks@chromium.org>
Commit-Queue: Jakob Gruber <jgruber@chromium.org>
Cr-Commit-Position: refs/heads/master@{#68128}
parent 49951673
...@@ -17866,6 +17866,20 @@ TEST(GCCallbacks) { ...@@ -17866,6 +17866,20 @@ TEST(GCCallbacks) {
isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc); isolate->RemoveGCEpilogueCallback(EpilogueCallbackAlloc);
} }
namespace {
void AssertOneByteConsContainsTwoByteExternal(i::Handle<i::String> maybe_cons,
i::Handle<i::String> external) {
CHECK(maybe_cons->IsOneByteRepresentation());
CHECK(maybe_cons->IsConsString());
i::ConsString cons = i::ConsString::cast(*maybe_cons);
CHECK(cons.IsFlat());
CHECK(cons.first() == *external);
CHECK(cons.first().IsTwoByteRepresentation());
CHECK(cons.first().IsExternalString());
}
} // namespace
THREADED_TEST(TwoByteStringInOneByteCons) { THREADED_TEST(TwoByteStringInOneByteCons) {
// See Chromium issue 47824. // See Chromium issue 47824.
...@@ -17880,10 +17894,12 @@ THREADED_TEST(TwoByteStringInOneByteCons) { ...@@ -17880,10 +17894,12 @@ THREADED_TEST(TwoByteStringInOneByteCons) {
Local<Value> indexof = CompileRun("str2.indexOf('els')"); Local<Value> indexof = CompileRun("str2.indexOf('els')");
Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')"); Local<Value> lastindexof = CompileRun("str2.lastIndexOf('dab')");
Local<Value> second_char = CompileRun("str2[1]");
CHECK(result->IsString()); CHECK(result->IsString());
i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result)); i::Handle<i::String> string = v8::Utils::OpenHandle(String::Cast(*result));
int length = string->length(); int length = string->length();
CHECK(string->IsConsString());
CHECK(string->IsOneByteRepresentation()); CHECK(string->IsOneByteRepresentation());
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate()); i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(context->GetIsolate());
...@@ -17904,57 +17920,74 @@ THREADED_TEST(TwoByteStringInOneByteCons) { ...@@ -17904,57 +17920,74 @@ THREADED_TEST(TwoByteStringInOneByteCons) {
CHECK(flat_string->IsTwoByteRepresentation()); CHECK(flat_string->IsTwoByteRepresentation());
// If the cons string has been short-circuited, skip the following checks.
if (!string.is_identical_to(flat_string)) {
// At this point, we should have a Cons string which is flat and one-byte, // At this point, we should have a Cons string which is flat and one-byte,
// with a first half that is a two-byte string (although it only contains // with a first half that is a two-byte string (although it only contains
// one-byte characters). This is a valid sequence of steps, and it can // one-byte characters). This is a valid sequence of steps, and it can
// happen in real pages. // happen in real pages.
CHECK(string->IsOneByteRepresentation()); AssertOneByteConsContainsTwoByteExternal(string, flat_string);
i::ConsString cons = i::ConsString::cast(*string);
CHECK_EQ(0, cons.second().length());
CHECK(cons.first().IsTwoByteRepresentation());
}
// Check that some string operations work. // Check that some string operations work.
// Atom RegExp. // Atom RegExp.
Local<Value> reresult = CompileRun("str2.match(/abel/g).length;"); Local<Value> reresult = CompileRun("str2.match(/abel/g).length;");
CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust()); CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
// Nonatom RegExp. // Nonatom RegExp.
reresult = CompileRun("str2.match(/abe./g).length;"); reresult = CompileRun("str2.match(/abe./g).length;");
CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust()); CHECK_EQ(6, reresult->Int32Value(context.local()).FromJust());
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
reresult = CompileRun("str2.search(/bel/g);"); reresult = CompileRun("str2.search(/bel/g);");
CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust()); CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
reresult = CompileRun("str2.search(/be./g);"); reresult = CompileRun("str2.search(/be./g);");
CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust()); CHECK_EQ(1, reresult->Int32Value(context.local()).FromJust());
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
ExpectTrue("/bel/g.test(str2);"); ExpectTrue("/bel/g.test(str2);");
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
ExpectTrue("/be./g.test(str2);"); ExpectTrue("/be./g.test(str2);");
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
reresult = CompileRun("/bel/g.exec(str2);"); reresult = CompileRun("/bel/g.exec(str2);");
CHECK(!reresult->IsNull()); CHECK(!reresult->IsNull());
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
reresult = CompileRun("/be./g.exec(str2);"); reresult = CompileRun("/be./g.exec(str2);");
CHECK(!reresult->IsNull()); CHECK(!reresult->IsNull());
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
ExpectString("str2.substring(2, 10);", "elspenda"); ExpectString("str2.substring(2, 10);", "elspenda");
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
ExpectString("str2.substring(2, 20);", "elspendabelabelspe"); ExpectString("str2.substring(2, 20);", "elspendabelabelspe");
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
ExpectString("str2.charAt(2);", "e"); ExpectString("str2.charAt(2);", "e");
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
ExpectObject("str2.indexOf('els');", indexof); ExpectObject("str2.indexOf('els');", indexof);
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
ExpectObject("str2.lastIndexOf('dab');", lastindexof); ExpectObject("str2.lastIndexOf('dab');", lastindexof);
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
// crbug.com/1088179. Fill the single character string cache, then run split.
i_isolate->factory()->LookupSingleCharacterStringFromCode(0);
for (size_t i = 0; i < std::strlen(init_code); i++) {
i_isolate->factory()->LookupSingleCharacterStringFromCode(init_code[i]);
}
ExpectObject("str2.split('')[1]", second_char);
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
reresult = CompileRun("str2.charCodeAt(2);"); reresult = CompileRun("str2.charCodeAt(2);");
CHECK_EQ(static_cast<int32_t>('e'), CHECK_EQ(static_cast<int32_t>('e'),
reresult->Int32Value(context.local()).FromJust()); reresult->Int32Value(context.local()).FromJust());
AssertOneByteConsContainsTwoByteExternal(string, flat_string);
// This avoids the GC from trying to free stack allocated resources. // This avoids the GC from trying to free stack allocated resources.
i::Handle<i::ExternalTwoByteString>::cast(flat_string) i::Handle<i::ExternalTwoByteString>::cast(flat_string)
->SetResource(i_isolate, nullptr); ->SetResource(i_isolate, nullptr);
......
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