[heap] Fix ThinString promotion counters.
From the promotion code point of view, a ThinString being forwarded to an ExternalString is exactly the same as an actual ExternalString being forwarded to its promoted copy. These changes provide a way to disambiguate both scenarios since they are different for external memory accounting. Bug: chromium:867902 Change-Id: I6fd56ee5e0f8900318466108273ab26e936eb439 Reviewed-on: https://chromium-review.googlesource.com/1152975 Commit-Queue: Rodrigo Bruno <rfbpb@google.com> Reviewed-by: Michael Lippautz <mlippautz@chromium.org> Cr-Commit-Position: refs/heads/master@{#54790}
This commit is contained in:
parent
c47e612806
commit
0640fd58dd
@ -2286,7 +2286,6 @@ bool Heap::ExternalStringTable::Contains(HeapObject* obj) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Heap::ProcessMovedExternalString(Page* old_page, Page* new_page,
|
void Heap::ProcessMovedExternalString(Page* old_page, Page* new_page,
|
||||||
ExternalString* string) {
|
ExternalString* string) {
|
||||||
size_t size = string->ExternalPayloadSize();
|
size_t size = string->ExternalPayloadSize();
|
||||||
@ -2314,7 +2313,12 @@ String* Heap::UpdateNewSpaceReferenceInExternalStringTableEntry(Heap* heap,
|
|||||||
|
|
||||||
// String is still reachable.
|
// String is still reachable.
|
||||||
String* new_string = String::cast(first_word.ToForwardingAddress());
|
String* new_string = String::cast(first_word.ToForwardingAddress());
|
||||||
if (new_string->IsThinString()) {
|
String* original_string = reinterpret_cast<String*>(*p);
|
||||||
|
// The length of the original string is used to disambiguate the scenario
|
||||||
|
// of a ThingString being forwarded to an ExternalString (which already exists
|
||||||
|
// in the OLD space), and an ExternalString being forwarded to its promoted
|
||||||
|
// copy. See Scavenger::EvacuateThinString.
|
||||||
|
if (new_string->IsThinString() || original_string->length() == 0) {
|
||||||
// Filtering Thin strings out of the external string table.
|
// Filtering Thin strings out of the external string table.
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (new_string->IsExternalString()) {
|
} else if (new_string->IsExternalString()) {
|
||||||
|
@ -148,7 +148,8 @@ void Scavenger::EvacuateThinString(Map* map, HeapObject** slot,
|
|||||||
ThinString* object, int object_size) {
|
ThinString* object, int object_size) {
|
||||||
if (!is_incremental_marking_) {
|
if (!is_incremental_marking_) {
|
||||||
// Loading actual is fine in a parallel setting is there is no write.
|
// Loading actual is fine in a parallel setting is there is no write.
|
||||||
HeapObject* actual = object->actual();
|
String* actual = object->actual();
|
||||||
|
object->set_length(0);
|
||||||
*slot = actual;
|
*slot = actual;
|
||||||
// ThinStrings always refer to internalized strings, which are
|
// ThinStrings always refer to internalized strings, which are
|
||||||
// always in old space.
|
// always in old space.
|
||||||
|
@ -170,6 +170,55 @@ TEST(ExternalString_ExternalBackingStoreSizeIncreasesAfterExternalization) {
|
|||||||
old_backing_store_before);
|
old_backing_store_before);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(ExternalString_PromotedThinString) {
|
||||||
|
ManualGCScope manual_gc_scope;
|
||||||
|
CcTest::InitializeVM();
|
||||||
|
LocalContext env;
|
||||||
|
v8::Isolate* isolate = env->GetIsolate();
|
||||||
|
i::Isolate* i_isolate = CcTest::i_isolate();
|
||||||
|
i::Factory* factory = i_isolate->factory();
|
||||||
|
Heap* heap = i_isolate->heap();
|
||||||
|
|
||||||
|
{
|
||||||
|
v8::HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
|
// New external string in the old space.
|
||||||
|
v8::internal::Handle<v8::internal::String> string1 =
|
||||||
|
factory
|
||||||
|
->NewExternalStringFromOneByte(
|
||||||
|
new TestOneByteResource(i::StrDup(TEST_STR)))
|
||||||
|
.ToHandleChecked();
|
||||||
|
|
||||||
|
// Internalize external string.
|
||||||
|
i::Handle<i::String> isymbol1 = factory->InternalizeString(string1);
|
||||||
|
CHECK(isymbol1->IsInternalizedString());
|
||||||
|
CHECK(string1->IsExternalString());
|
||||||
|
CHECK(!heap->InNewSpace(*isymbol1));
|
||||||
|
|
||||||
|
// New external string in the young space. This string has the same content
|
||||||
|
// as the previous one (that was already internalized).
|
||||||
|
v8::Local<v8::String> string2 =
|
||||||
|
v8::String::NewFromUtf8(isolate, TEST_STR, v8::NewStringType::kNormal)
|
||||||
|
.ToLocalChecked();
|
||||||
|
bool success =
|
||||||
|
string2->MakeExternal(new TestOneByteResource(i::StrDup(TEST_STR)));
|
||||||
|
CHECK(success);
|
||||||
|
|
||||||
|
// Internalize (it will create a thin string in the new space).
|
||||||
|
i::Handle<i::String> istring = v8::Utils::OpenHandle(*string2);
|
||||||
|
i::Handle<i::String> isymbol2 = factory->InternalizeString(istring);
|
||||||
|
CHECK(isymbol2->IsInternalizedString());
|
||||||
|
CHECK(istring->IsThinString());
|
||||||
|
CHECK(heap->InNewSpace(*istring));
|
||||||
|
|
||||||
|
// Collect thin string. References to the thin string will be updated to
|
||||||
|
// point to the actual external string in the old space.
|
||||||
|
heap::GcAndSweep(heap, NEW_SPACE);
|
||||||
|
|
||||||
|
USE(isymbol1);
|
||||||
|
USE(isymbol2);
|
||||||
|
}
|
||||||
|
}
|
||||||
} // namespace heap
|
} // namespace heap
|
||||||
} // namespace internal
|
} // namespace internal
|
||||||
} // namespace v8
|
} // namespace v8
|
||||||
|
Loading…
Reference in New Issue
Block a user