[parser/ast] Reduce memory consumption for AstConsString.

The past re-factoring inadvertently increased memory consumption for
AstConsString. This implements a micro-optimization to revert and slightly
improve beyond the original state.

Example, Zone size for parsing closure.js:
  - 20,999,848 B (before refactoring)
  - 21,651,056 B (after refactoring patch; 3.1% regression)
  - 20,641,320 B (after this CL; 1.7% improvement over original)

(Reason: ZoneLinkedList requires 4 pointers to support
the std::list functionality (Zone*, head/tail ptr, payload ptr).
But since we only append and iterate in order and have the Zone*
available in the context, a super simple linked list (value + next ptr)
saves a bit of memory, especially for the common case of having 0 or 1
string segments.)

BUG=v8:6902, chromium:706935

Review-Url: https://codereview.chromium.org/2792353002
Cr-Commit-Position: refs/heads/master@{#44385}
This commit is contained in:
vogelheim 2017-04-04 08:38:17 -07:00 committed by Commit bot
parent 2db1f598c5
commit 1769c7034b
3 changed files with 36 additions and 15 deletions

View File

@ -156,12 +156,17 @@ bool AstRawString::Compare(void* a, void* b) {
}
void AstConsString::Internalize(Isolate* isolate) {
Handle<String> tmp(isolate->factory()->empty_string());
for (const AstRawString* current : strings_) {
// AstRawStrings are internalized before AstConsStrings, so *current is
// already internalized.
if (IsEmpty()) {
set_string(isolate->factory()->empty_string());
return;
}
// AstRawStrings are internalized before AstConsStrings, so
// AstRawString::string() will just work.
Handle<String> tmp(segment_.string->string());
for (AstConsString::Segment* current = segment_.next; current != nullptr;
current = current->next) {
tmp = isolate->factory()
->NewConsString(tmp, current->string())
->NewConsString(current->string->string(), tmp)
.ToHandleChecked();
}
set_string(tmp);
@ -285,19 +290,19 @@ const AstRawString* AstValueFactory::GetString(Handle<String> literal) {
}
AstConsString* AstValueFactory::NewConsString() {
AstConsString* new_string = new (zone_) AstConsString(zone_);
AstConsString* new_string = new (zone_) AstConsString;
DCHECK_NOT_NULL(new_string);
AddConsString(new_string);
return new_string;
}
AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
return NewConsString()->AddString(str);
return NewConsString()->AddString(zone_, str);
}
AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
const AstRawString* str2) {
return NewConsString()->AddString(str1)->AddString(str2);
return NewConsString()->AddString(zone_, str1)->AddString(zone_, str2);
}
void AstValueFactory::Internalize(Isolate* isolate) {

View File

@ -126,12 +126,24 @@ class AstRawString final : public ZoneObject {
class AstConsString final : public ZoneObject {
public:
AstConsString* AddString(const AstRawString* s) {
if (s && !s->IsEmpty()) strings_.push_back(s);
AstConsString* AddString(Zone* zone, const AstRawString* s) {
if (s->IsEmpty()) return this;
if (!IsEmpty()) {
// We're putting the new string to the head of the list, meaning
// the string segments will be in reverse order.
Segment* tmp = new (zone->New(sizeof(Segment))) Segment;
*tmp = segment_;
segment_.next = tmp;
}
segment_.string = s;
return this;
}
bool IsEmpty() const { return strings_.empty(); }
bool IsEmpty() const {
DCHECK_IMPLIES(segment_.string == nullptr, segment_.next == nullptr);
DCHECK_IMPLIES(segment_.string != nullptr, !segment_.string->IsEmpty());
return segment_.string == nullptr;
}
void Internalize(Isolate* isolate);
@ -143,7 +155,7 @@ class AstConsString final : public ZoneObject {
private:
friend class AstValueFactory;
explicit AstConsString(Zone* zone) : next_(nullptr), strings_(zone) {}
AstConsString() : next_(nullptr), segment_({nullptr, nullptr}) {}
AstConsString* next() const { return next_; }
AstConsString** next_location() { return &next_; }
@ -156,7 +168,11 @@ class AstConsString final : public ZoneObject {
String** string_;
};
ZoneLinkedList<const AstRawString*> strings_;
struct Segment {
const AstRawString* string;
AstConsString::Segment* next;
};
Segment segment_;
};
enum class AstSymbol : uint8_t { kHomeObjectSymbol };

View File

@ -64,9 +64,9 @@ const AstConsString* FuncNameInferrer::MakeNameFromStack() {
}
// Add name. Separate names with ".".
if (!result->IsEmpty()) {
result->AddString(ast_value_factory_->dot_string());
result->AddString(zone(), ast_value_factory_->dot_string());
}
result->AddString(names_stack_.at(pos).name);
result->AddString(zone(), names_stack_.at(pos).name);
}
return result;
}