[parser] Split AstRawString and Parser zones
This allows us to reuse AstValueFactory's string table across multiple parsers, while still releasing memory after each individual parse. This is mild overkill for all the single parses that don't reuse AstValueFactories, but there at least the AstRawStrings now end up grouped together in memory, so that might have mild cache benefits. Change-Id: I0b378760b601fa4ec6559a0dca5d7ed6f895e992 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3322764 Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Leszek Swirski <leszeks@chromium.org> Auto-Submit: Leszek Swirski <leszeks@chromium.org> Cr-Commit-Position: refs/heads/main@{#78338}
This commit is contained in:
parent
4fae8b1680
commit
ef0b2aabd9
@ -353,16 +353,18 @@ const AstRawString* AstValueFactory::GetString(
|
|||||||
}
|
}
|
||||||
|
|
||||||
AstConsString* AstValueFactory::NewConsString() {
|
AstConsString* AstValueFactory::NewConsString() {
|
||||||
return zone()->New<AstConsString>();
|
return single_parse_zone()->New<AstConsString>();
|
||||||
}
|
}
|
||||||
|
|
||||||
AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
|
AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
|
||||||
return NewConsString()->AddString(zone(), str);
|
return NewConsString()->AddString(single_parse_zone(), str);
|
||||||
}
|
}
|
||||||
|
|
||||||
AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
|
AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
|
||||||
const AstRawString* str2) {
|
const AstRawString* str2) {
|
||||||
return NewConsString()->AddString(zone(), str1)->AddString(zone(), str2);
|
return NewConsString()
|
||||||
|
->AddString(single_parse_zone(), str1)
|
||||||
|
->AddString(single_parse_zone(), str2);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename IsolateT>
|
template <typename IsolateT>
|
||||||
@ -395,9 +397,9 @@ const AstRawString* AstValueFactory::GetString(
|
|||||||
[&]() {
|
[&]() {
|
||||||
// Copy literal contents for later comparison.
|
// Copy literal contents for later comparison.
|
||||||
int length = literal_bytes.length();
|
int length = literal_bytes.length();
|
||||||
byte* new_literal_bytes = zone()->NewArray<byte>(length);
|
byte* new_literal_bytes = ast_raw_string_zone()->NewArray<byte>(length);
|
||||||
memcpy(new_literal_bytes, literal_bytes.begin(), length);
|
memcpy(new_literal_bytes, literal_bytes.begin(), length);
|
||||||
AstRawString* new_string = zone()->New<AstRawString>(
|
AstRawString* new_string = ast_raw_string_zone()->New<AstRawString>(
|
||||||
is_one_byte, base::Vector<const byte>(new_literal_bytes, length),
|
is_one_byte, base::Vector<const byte>(new_literal_bytes, length),
|
||||||
raw_hash_field);
|
raw_hash_field);
|
||||||
CHECK_NOT_NULL(new_string);
|
CHECK_NOT_NULL(new_string);
|
||||||
|
@ -311,24 +311,40 @@ class AstValueFactory {
|
|||||||
public:
|
public:
|
||||||
AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
|
AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
|
||||||
uint64_t hash_seed)
|
uint64_t hash_seed)
|
||||||
|
: AstValueFactory(zone, zone, string_constants, hash_seed) {}
|
||||||
|
|
||||||
|
AstValueFactory(Zone* ast_raw_string_zone, Zone* single_parse_zone,
|
||||||
|
const AstStringConstants* string_constants,
|
||||||
|
uint64_t hash_seed)
|
||||||
: string_table_(string_constants->string_table()),
|
: string_table_(string_constants->string_table()),
|
||||||
strings_(nullptr),
|
strings_(nullptr),
|
||||||
strings_end_(&strings_),
|
strings_end_(&strings_),
|
||||||
string_constants_(string_constants),
|
string_constants_(string_constants),
|
||||||
empty_cons_string_(nullptr),
|
empty_cons_string_(nullptr),
|
||||||
zone_(zone),
|
ast_raw_string_zone_(ast_raw_string_zone),
|
||||||
|
single_parse_zone_(single_parse_zone),
|
||||||
hash_seed_(hash_seed) {
|
hash_seed_(hash_seed) {
|
||||||
DCHECK_NOT_NULL(zone_);
|
DCHECK_NOT_NULL(ast_raw_string_zone_);
|
||||||
|
DCHECK_NOT_NULL(single_parse_zone_);
|
||||||
DCHECK_EQ(hash_seed, string_constants->hash_seed());
|
DCHECK_EQ(hash_seed, string_constants->hash_seed());
|
||||||
std::fill(one_character_strings_,
|
std::fill(one_character_strings_,
|
||||||
one_character_strings_ + arraysize(one_character_strings_),
|
one_character_strings_ + arraysize(one_character_strings_),
|
||||||
nullptr);
|
nullptr);
|
||||||
empty_cons_string_ = NewConsString();
|
|
||||||
|
// Allocate the empty ConsString in the AstRawString Zone instead of the
|
||||||
|
// single parse Zone like other ConsStrings, because unlike those it can be
|
||||||
|
// reused across parses.
|
||||||
|
empty_cons_string_ = ast_raw_string_zone_->New<AstConsString>();
|
||||||
}
|
}
|
||||||
|
|
||||||
Zone* zone() const {
|
Zone* ast_raw_string_zone() const {
|
||||||
DCHECK_NOT_NULL(zone_);
|
DCHECK_NOT_NULL(ast_raw_string_zone_);
|
||||||
return zone_;
|
return ast_raw_string_zone_;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zone* single_parse_zone() const {
|
||||||
|
DCHECK_NOT_NULL(single_parse_zone_);
|
||||||
|
return single_parse_zone_;
|
||||||
}
|
}
|
||||||
|
|
||||||
const AstRawString* GetOneByteString(base::Vector<const uint8_t> literal) {
|
const AstRawString* GetOneByteString(base::Vector<const uint8_t> literal) {
|
||||||
@ -394,7 +410,8 @@ class AstValueFactory {
|
|||||||
static const int kMaxOneCharStringValue = 128;
|
static const int kMaxOneCharStringValue = 128;
|
||||||
const AstRawString* one_character_strings_[kMaxOneCharStringValue];
|
const AstRawString* one_character_strings_[kMaxOneCharStringValue];
|
||||||
|
|
||||||
Zone* zone_;
|
Zone* ast_raw_string_zone_;
|
||||||
|
Zone* single_parse_zone_;
|
||||||
|
|
||||||
uint64_t hash_seed_;
|
uint64_t hash_seed_;
|
||||||
};
|
};
|
||||||
|
@ -166,17 +166,19 @@ DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
|
|||||||
|
|
||||||
ModuleScope::ModuleScope(DeclarationScope* script_scope,
|
ModuleScope::ModuleScope(DeclarationScope* script_scope,
|
||||||
AstValueFactory* avfactory)
|
AstValueFactory* avfactory)
|
||||||
: DeclarationScope(avfactory->zone(), script_scope, MODULE_SCOPE,
|
: DeclarationScope(avfactory->single_parse_zone(), script_scope,
|
||||||
FunctionKind::kModule),
|
MODULE_SCOPE, FunctionKind::kModule),
|
||||||
module_descriptor_(avfactory->zone()->New<SourceTextModuleDescriptor>(
|
module_descriptor_(
|
||||||
avfactory->zone())) {
|
avfactory->single_parse_zone()->New<SourceTextModuleDescriptor>(
|
||||||
|
avfactory->single_parse_zone())) {
|
||||||
set_language_mode(LanguageMode::kStrict);
|
set_language_mode(LanguageMode::kStrict);
|
||||||
DeclareThis(avfactory);
|
DeclareThis(avfactory);
|
||||||
}
|
}
|
||||||
|
|
||||||
ModuleScope::ModuleScope(Handle<ScopeInfo> scope_info,
|
ModuleScope::ModuleScope(Handle<ScopeInfo> scope_info,
|
||||||
AstValueFactory* avfactory)
|
AstValueFactory* avfactory)
|
||||||
: DeclarationScope(avfactory->zone(), MODULE_SCOPE, avfactory, scope_info),
|
: DeclarationScope(avfactory->single_parse_zone(), MODULE_SCOPE, avfactory,
|
||||||
|
scope_info),
|
||||||
module_descriptor_(nullptr) {
|
module_descriptor_(nullptr) {
|
||||||
set_language_mode(LanguageMode::kStrict);
|
set_language_mode(LanguageMode::kStrict);
|
||||||
}
|
}
|
||||||
@ -1623,7 +1625,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
|
|||||||
has_rest_ = false;
|
has_rest_ = false;
|
||||||
function_ = nullptr;
|
function_ = nullptr;
|
||||||
|
|
||||||
DCHECK_NE(zone(), ast_value_factory->zone());
|
DCHECK_NE(zone(), ast_value_factory->single_parse_zone());
|
||||||
// Make sure this scope and zone aren't used for allocation anymore.
|
// Make sure this scope and zone aren't used for allocation anymore.
|
||||||
{
|
{
|
||||||
// Get the zone, while variables_ is still valid
|
// Get the zone, while variables_ is still valid
|
||||||
@ -1634,7 +1636,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
|
|||||||
|
|
||||||
if (aborted) {
|
if (aborted) {
|
||||||
// Prepare scope for use in the outer zone.
|
// Prepare scope for use in the outer zone.
|
||||||
variables_ = VariableMap(ast_value_factory->zone());
|
variables_ = VariableMap(ast_value_factory->single_parse_zone());
|
||||||
if (!IsArrowFunction(function_kind_)) {
|
if (!IsArrowFunction(function_kind_)) {
|
||||||
has_simple_parameters_ = true;
|
has_simple_parameters_ = true;
|
||||||
DeclareDefaultFunctionVariables(ast_value_factory);
|
DeclareDefaultFunctionVariables(ast_value_factory);
|
||||||
|
@ -60,7 +60,7 @@ AstConsString* FuncNameInferrer::MakeNameFromStack() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Add name. Separate names with ".".
|
// Add name. Separate names with ".".
|
||||||
Zone* zone = ast_value_factory_->zone();
|
Zone* zone = ast_value_factory_->single_parse_zone();
|
||||||
if (!result->IsEmpty()) {
|
if (!result->IsEmpty()) {
|
||||||
result->AddString(zone, ast_value_factory_->dot_string());
|
result->AddString(zone, ast_value_factory_->dot_string());
|
||||||
}
|
}
|
||||||
|
@ -176,9 +176,12 @@ ReusableUnoptimizedCompileState::ReusableUnoptimizedCompileState(
|
|||||||
logger_(isolate->logger()),
|
logger_(isolate->logger()),
|
||||||
dispatcher_(isolate->lazy_compile_dispatcher()),
|
dispatcher_(isolate->lazy_compile_dispatcher()),
|
||||||
ast_string_constants_(isolate->ast_string_constants()),
|
ast_string_constants_(isolate->ast_string_constants()),
|
||||||
zone_(allocator_, "unoptimized-compile-zone"),
|
ast_raw_string_zone_(allocator_,
|
||||||
|
"unoptimized-compile-ast-raw-string-zone"),
|
||||||
|
single_parse_zone_(allocator_, "unoptimized-compile-parse-zone"),
|
||||||
ast_value_factory_(
|
ast_value_factory_(
|
||||||
new AstValueFactory(zone(), ast_string_constants(), hash_seed())) {}
|
new AstValueFactory(ast_raw_string_zone(), single_parse_zone(),
|
||||||
|
ast_string_constants(), hash_seed())) {}
|
||||||
|
|
||||||
ReusableUnoptimizedCompileState::ReusableUnoptimizedCompileState(
|
ReusableUnoptimizedCompileState::ReusableUnoptimizedCompileState(
|
||||||
LocalIsolate* isolate)
|
LocalIsolate* isolate)
|
||||||
@ -187,9 +190,12 @@ ReusableUnoptimizedCompileState::ReusableUnoptimizedCompileState(
|
|||||||
logger_(isolate->main_thread_logger()),
|
logger_(isolate->main_thread_logger()),
|
||||||
dispatcher_(isolate->lazy_compile_dispatcher()),
|
dispatcher_(isolate->lazy_compile_dispatcher()),
|
||||||
ast_string_constants_(isolate->ast_string_constants()),
|
ast_string_constants_(isolate->ast_string_constants()),
|
||||||
zone_(allocator_, "unoptimized-compile-zone"),
|
ast_raw_string_zone_(allocator_,
|
||||||
|
"unoptimized-compile-ast-raw-string-zone"),
|
||||||
|
single_parse_zone_(allocator_, "unoptimized-compile-parse-zone"),
|
||||||
ast_value_factory_(
|
ast_value_factory_(
|
||||||
new AstValueFactory(zone(), ast_string_constants(), hash_seed())) {}
|
new AstValueFactory(ast_raw_string_zone(), single_parse_zone(),
|
||||||
|
ast_string_constants(), hash_seed())) {}
|
||||||
|
|
||||||
ReusableUnoptimizedCompileState::~ReusableUnoptimizedCompileState() = default;
|
ReusableUnoptimizedCompileState::~ReusableUnoptimizedCompileState() = default;
|
||||||
|
|
||||||
@ -235,7 +241,7 @@ ParseInfo::ParseInfo(LocalIsolate* isolate, const UnoptimizedCompileFlags flags,
|
|||||||
: ParseInfo(flags, state, reusable_state, stack_limit,
|
: ParseInfo(flags, state, reusable_state, stack_limit,
|
||||||
isolate->runtime_call_stats()) {}
|
isolate->runtime_call_stats()) {}
|
||||||
|
|
||||||
ParseInfo::~ParseInfo() = default;
|
ParseInfo::~ParseInfo() { reusable_state_->NotifySingleParseCompleted(); }
|
||||||
|
|
||||||
DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
|
DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
|
||||||
|
|
||||||
|
@ -184,7 +184,21 @@ class V8_EXPORT_PRIVATE ReusableUnoptimizedCompileState {
|
|||||||
explicit ReusableUnoptimizedCompileState(LocalIsolate* isolate);
|
explicit ReusableUnoptimizedCompileState(LocalIsolate* isolate);
|
||||||
~ReusableUnoptimizedCompileState();
|
~ReusableUnoptimizedCompileState();
|
||||||
|
|
||||||
Zone* zone() { return &zone_; }
|
// The AstRawString Zone stores the AstRawStrings in the AstValueFactory that
|
||||||
|
// can be reused across parses, and thereforce should stay alive between
|
||||||
|
// parses that reuse this reusable state and its AstValueFactory.
|
||||||
|
Zone* ast_raw_string_zone() { return &ast_raw_string_zone_; }
|
||||||
|
|
||||||
|
// The single parse Zone stores the data of a single parse, and can be cleared
|
||||||
|
// when that parse completes.
|
||||||
|
//
|
||||||
|
// This is in "reusable" state despite being wiped per-parse, because it
|
||||||
|
// allows us to reuse the Zone itself, and e.g. keep the same single parse
|
||||||
|
// Zone pointer in the AstValueFactory.
|
||||||
|
Zone* single_parse_zone() { return &single_parse_zone_; }
|
||||||
|
|
||||||
|
void NotifySingleParseCompleted() { single_parse_zone_.ReleaseMemory(); }
|
||||||
|
|
||||||
AstValueFactory* ast_value_factory() const {
|
AstValueFactory* ast_value_factory() const {
|
||||||
return ast_value_factory_.get();
|
return ast_value_factory_.get();
|
||||||
}
|
}
|
||||||
@ -202,7 +216,8 @@ class V8_EXPORT_PRIVATE ReusableUnoptimizedCompileState {
|
|||||||
Logger* logger_;
|
Logger* logger_;
|
||||||
LazyCompileDispatcher* dispatcher_;
|
LazyCompileDispatcher* dispatcher_;
|
||||||
const AstStringConstants* ast_string_constants_;
|
const AstStringConstants* ast_string_constants_;
|
||||||
Zone zone_;
|
Zone ast_raw_string_zone_;
|
||||||
|
Zone single_parse_zone_;
|
||||||
std::unique_ptr<AstValueFactory> ast_value_factory_;
|
std::unique_ptr<AstValueFactory> ast_value_factory_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -226,7 +241,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
|
|||||||
ScriptOriginOptions origin_options,
|
ScriptOriginOptions origin_options,
|
||||||
NativesFlag natives = NOT_NATIVES_CODE);
|
NativesFlag natives = NOT_NATIVES_CODE);
|
||||||
|
|
||||||
Zone* zone() const { return reusable_state_->zone(); }
|
Zone* zone() const { return reusable_state_->single_parse_zone(); }
|
||||||
|
|
||||||
const UnoptimizedCompileFlags& flags() const { return flags_; }
|
const UnoptimizedCompileFlags& flags() const { return flags_; }
|
||||||
|
|
||||||
|
@ -300,7 +300,7 @@ class ParserBase {
|
|||||||
void ResetFunctionLiteralId() { function_literal_id_ = 0; }
|
void ResetFunctionLiteralId() { function_literal_id_ = 0; }
|
||||||
|
|
||||||
// The Zone where the parsing outputs are stored.
|
// The Zone where the parsing outputs are stored.
|
||||||
Zone* main_zone() const { return ast_value_factory()->zone(); }
|
Zone* main_zone() const { return ast_value_factory()->single_parse_zone(); }
|
||||||
|
|
||||||
// The current Zone, which might be the main zone or a temporary Zone.
|
// The current Zone, which might be the main zone or a temporary Zone.
|
||||||
Zone* zone() const { return zone_; }
|
Zone* zone() const { return zone_; }
|
||||||
|
@ -3657,7 +3657,6 @@ TEST(MaybeAssignedParameters) {
|
|||||||
base::ScopedVector<char> program(Utf8LengthHelper(source) +
|
base::ScopedVector<char> program(Utf8LengthHelper(source) +
|
||||||
Utf8LengthHelper(suffix) + 1);
|
Utf8LengthHelper(suffix) + 1);
|
||||||
base::SNPrintF(program, "%s%s", source, suffix);
|
base::SNPrintF(program, "%s%s", source, suffix);
|
||||||
std::unique_ptr<i::ParseInfo> info;
|
|
||||||
printf("%s\n", program.begin());
|
printf("%s\n", program.begin());
|
||||||
v8::Local<v8::Value> v = CompileRun(program.begin());
|
v8::Local<v8::Value> v = CompileRun(program.begin());
|
||||||
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
|
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
|
||||||
@ -3668,16 +3667,15 @@ TEST(MaybeAssignedParameters) {
|
|||||||
i::UnoptimizedCompileFlags flags =
|
i::UnoptimizedCompileFlags flags =
|
||||||
i::UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared);
|
i::UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared);
|
||||||
flags.set_allow_lazy_parsing(allow_lazy);
|
flags.set_allow_lazy_parsing(allow_lazy);
|
||||||
info = std::make_unique<i::ParseInfo>(isolate, flags, &state,
|
i::ParseInfo info(isolate, flags, &state, &reusable_state);
|
||||||
&reusable_state);
|
CHECK_PARSE_FUNCTION(&info, shared, isolate);
|
||||||
CHECK_PARSE_FUNCTION(info.get(), shared, isolate);
|
|
||||||
|
|
||||||
i::Scope* scope = info->literal()->scope();
|
i::Scope* scope = info.literal()->scope();
|
||||||
CHECK(!scope->AsDeclarationScope()->was_lazily_parsed());
|
CHECK(!scope->AsDeclarationScope()->was_lazily_parsed());
|
||||||
CHECK_NULL(scope->sibling());
|
CHECK_NULL(scope->sibling());
|
||||||
CHECK(scope->is_function_scope());
|
CHECK(scope->is_function_scope());
|
||||||
const i::AstRawString* var_name =
|
const i::AstRawString* var_name =
|
||||||
info->ast_value_factory()->GetOneByteString("arg");
|
info.ast_value_factory()->GetOneByteString("arg");
|
||||||
i::Variable* var = scope->LookupForTesting(var_name);
|
i::Variable* var = scope->LookupForTesting(var_name);
|
||||||
CHECK(var->is_used() || !assigned);
|
CHECK(var->is_used() || !assigned);
|
||||||
bool is_maybe_assigned = var->maybe_assigned() == i::kMaybeAssigned;
|
bool is_maybe_assigned = var->maybe_assigned() == i::kMaybeAssigned;
|
||||||
@ -3708,12 +3706,11 @@ static void TestMaybeAssigned(Input input, const char* variable, bool module,
|
|||||||
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
|
i::UnoptimizedCompileFlags::ForScriptCompile(isolate, *script);
|
||||||
flags.set_is_module(module);
|
flags.set_is_module(module);
|
||||||
flags.set_allow_lazy_parsing(allow_lazy_parsing);
|
flags.set_allow_lazy_parsing(allow_lazy_parsing);
|
||||||
std::unique_ptr<i::ParseInfo> info =
|
i::ParseInfo info(isolate, flags, &state, &reusable_state);
|
||||||
std::make_unique<i::ParseInfo>(isolate, flags, &state, &reusable_state);
|
|
||||||
|
|
||||||
CHECK_PARSE_PROGRAM(info.get(), script, isolate);
|
CHECK_PARSE_PROGRAM(&info, script, isolate);
|
||||||
|
|
||||||
i::Scope* scope = info->literal()->scope();
|
i::Scope* scope = info.literal()->scope();
|
||||||
CHECK(!scope->AsDeclarationScope()->was_lazily_parsed());
|
CHECK(!scope->AsDeclarationScope()->was_lazily_parsed());
|
||||||
CHECK_NULL(scope->sibling());
|
CHECK_NULL(scope->sibling());
|
||||||
CHECK(module ? scope->is_module_scope() : scope->is_script_scope());
|
CHECK(module ? scope->is_module_scope() : scope->is_script_scope());
|
||||||
@ -3723,7 +3720,7 @@ static void TestMaybeAssigned(Input input, const char* variable, bool module,
|
|||||||
// Find the variable.
|
// Find the variable.
|
||||||
scope = i::ScopeTestHelper::FindScope(scope, input.location);
|
scope = i::ScopeTestHelper::FindScope(scope, input.location);
|
||||||
const i::AstRawString* var_name =
|
const i::AstRawString* var_name =
|
||||||
info->ast_value_factory()->GetOneByteString(variable);
|
info.ast_value_factory()->GetOneByteString(variable);
|
||||||
var = scope->LookupForTesting(var_name);
|
var = scope->LookupForTesting(var_name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user