Commit ef0b2aab authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[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/+/3322764Reviewed-by: 's avatarToon 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}
parent 4fae8b16
......@@ -353,16 +353,18 @@ const AstRawString* AstValueFactory::GetString(
}
AstConsString* AstValueFactory::NewConsString() {
return zone()->New<AstConsString>();
return single_parse_zone()->New<AstConsString>();
}
AstConsString* AstValueFactory::NewConsString(const AstRawString* str) {
return NewConsString()->AddString(zone(), str);
return NewConsString()->AddString(single_parse_zone(), str);
}
AstConsString* AstValueFactory::NewConsString(const AstRawString* str1,
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>
......@@ -395,9 +397,9 @@ const AstRawString* AstValueFactory::GetString(
[&]() {
// Copy literal contents for later comparison.
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);
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),
raw_hash_field);
CHECK_NOT_NULL(new_string);
......
......@@ -311,24 +311,40 @@ class AstValueFactory {
public:
AstValueFactory(Zone* zone, const AstStringConstants* string_constants,
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()),
strings_(nullptr),
strings_end_(&strings_),
string_constants_(string_constants),
empty_cons_string_(nullptr),
zone_(zone),
ast_raw_string_zone_(ast_raw_string_zone),
single_parse_zone_(single_parse_zone),
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());
std::fill(one_character_strings_,
one_character_strings_ + arraysize(one_character_strings_),
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* ast_raw_string_zone() const {
DCHECK_NOT_NULL(ast_raw_string_zone_);
return ast_raw_string_zone_;
}
Zone* zone() const {
DCHECK_NOT_NULL(zone_);
return 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) {
......@@ -394,7 +410,8 @@ class AstValueFactory {
static const int kMaxOneCharStringValue = 128;
const AstRawString* one_character_strings_[kMaxOneCharStringValue];
Zone* zone_;
Zone* ast_raw_string_zone_;
Zone* single_parse_zone_;
uint64_t hash_seed_;
};
......
......@@ -166,17 +166,19 @@ DeclarationScope::DeclarationScope(Zone* zone, Scope* outer_scope,
ModuleScope::ModuleScope(DeclarationScope* script_scope,
AstValueFactory* avfactory)
: DeclarationScope(avfactory->zone(), script_scope, MODULE_SCOPE,
FunctionKind::kModule),
module_descriptor_(avfactory->zone()->New<SourceTextModuleDescriptor>(
avfactory->zone())) {
: DeclarationScope(avfactory->single_parse_zone(), script_scope,
MODULE_SCOPE, FunctionKind::kModule),
module_descriptor_(
avfactory->single_parse_zone()->New<SourceTextModuleDescriptor>(
avfactory->single_parse_zone())) {
set_language_mode(LanguageMode::kStrict);
DeclareThis(avfactory);
}
ModuleScope::ModuleScope(Handle<ScopeInfo> scope_info,
AstValueFactory* avfactory)
: DeclarationScope(avfactory->zone(), MODULE_SCOPE, avfactory, scope_info),
: DeclarationScope(avfactory->single_parse_zone(), MODULE_SCOPE, avfactory,
scope_info),
module_descriptor_(nullptr) {
set_language_mode(LanguageMode::kStrict);
}
......@@ -1623,7 +1625,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
has_rest_ = false;
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.
{
// Get the zone, while variables_ is still valid
......@@ -1634,7 +1636,7 @@ void DeclarationScope::ResetAfterPreparsing(AstValueFactory* ast_value_factory,
if (aborted) {
// 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_)) {
has_simple_parameters_ = true;
DeclareDefaultFunctionVariables(ast_value_factory);
......
......@@ -60,7 +60,7 @@ AstConsString* FuncNameInferrer::MakeNameFromStack() {
continue;
}
// Add name. Separate names with ".".
Zone* zone = ast_value_factory_->zone();
Zone* zone = ast_value_factory_->single_parse_zone();
if (!result->IsEmpty()) {
result->AddString(zone, ast_value_factory_->dot_string());
}
......
......@@ -176,9 +176,12 @@ ReusableUnoptimizedCompileState::ReusableUnoptimizedCompileState(
logger_(isolate->logger()),
dispatcher_(isolate->lazy_compile_dispatcher()),
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_(
new AstValueFactory(zone(), ast_string_constants(), hash_seed())) {}
new AstValueFactory(ast_raw_string_zone(), single_parse_zone(),
ast_string_constants(), hash_seed())) {}
ReusableUnoptimizedCompileState::ReusableUnoptimizedCompileState(
LocalIsolate* isolate)
......@@ -187,9 +190,12 @@ ReusableUnoptimizedCompileState::ReusableUnoptimizedCompileState(
logger_(isolate->main_thread_logger()),
dispatcher_(isolate->lazy_compile_dispatcher()),
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_(
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;
......@@ -235,7 +241,7 @@ ParseInfo::ParseInfo(LocalIsolate* isolate, const UnoptimizedCompileFlags flags,
: ParseInfo(flags, state, reusable_state, stack_limit,
isolate->runtime_call_stats()) {}
ParseInfo::~ParseInfo() = default;
ParseInfo::~ParseInfo() { reusable_state_->NotifySingleParseCompleted(); }
DeclarationScope* ParseInfo::scope() const { return literal()->scope(); }
......
......@@ -184,7 +184,21 @@ class V8_EXPORT_PRIVATE ReusableUnoptimizedCompileState {
explicit ReusableUnoptimizedCompileState(LocalIsolate* isolate);
~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 {
return ast_value_factory_.get();
}
......@@ -202,7 +216,8 @@ class V8_EXPORT_PRIVATE ReusableUnoptimizedCompileState {
Logger* logger_;
LazyCompileDispatcher* dispatcher_;
const AstStringConstants* ast_string_constants_;
Zone zone_;
Zone ast_raw_string_zone_;
Zone single_parse_zone_;
std::unique_ptr<AstValueFactory> ast_value_factory_;
};
......@@ -226,7 +241,7 @@ class V8_EXPORT_PRIVATE ParseInfo {
ScriptOriginOptions origin_options,
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_; }
......
......@@ -300,7 +300,7 @@ class ParserBase {
void ResetFunctionLiteralId() { function_literal_id_ = 0; }
// 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.
Zone* zone() const { return zone_; }
......
......@@ -3657,7 +3657,6 @@ TEST(MaybeAssignedParameters) {
base::ScopedVector<char> program(Utf8LengthHelper(source) +
Utf8LengthHelper(suffix) + 1);
base::SNPrintF(program, "%s%s", source, suffix);
std::unique_ptr<i::ParseInfo> info;
printf("%s\n", program.begin());
v8::Local<v8::Value> v = CompileRun(program.begin());
i::Handle<i::Object> o = v8::Utils::OpenHandle(*v);
......@@ -3668,16 +3667,15 @@ TEST(MaybeAssignedParameters) {
i::UnoptimizedCompileFlags flags =
i::UnoptimizedCompileFlags::ForFunctionCompile(isolate, *shared);
flags.set_allow_lazy_parsing(allow_lazy);
info = std::make_unique<i::ParseInfo>(isolate, flags, &state,
&reusable_state);
CHECK_PARSE_FUNCTION(info.get(), shared, isolate);
i::ParseInfo info(isolate, flags, &state, &reusable_state);
CHECK_PARSE_FUNCTION(&info, shared, isolate);
i::Scope* scope = info->literal()->scope();
i::Scope* scope = info.literal()->scope();
CHECK(!scope->AsDeclarationScope()->was_lazily_parsed());
CHECK_NULL(scope->sibling());
CHECK(scope->is_function_scope());
const i::AstRawString* var_name =
info->ast_value_factory()->GetOneByteString("arg");
info.ast_value_factory()->GetOneByteString("arg");
i::Variable* var = scope->LookupForTesting(var_name);
CHECK(var->is_used() || !assigned);
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);
flags.set_is_module(module);
flags.set_allow_lazy_parsing(allow_lazy_parsing);
std::unique_ptr<i::ParseInfo> info =
std::make_unique<i::ParseInfo>(isolate, flags, &state, &reusable_state);
i::ParseInfo info(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_NULL(scope->sibling());
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.
scope = i::ScopeTestHelper::FindScope(scope, input.location);
const i::AstRawString* var_name =
info->ast_value_factory()->GetOneByteString(variable);
info.ast_value_factory()->GetOneByteString(variable);
var = scope->LookupForTesting(var_name);
}
......
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