[parser] Skipping inner functions: produce more data needed for FunctionLiterals.
Previously we didn't produce all data that we need for creating sensemaking FunctionLiterals for the skipped functions. Test in https://chromium-review.googlesource.com/c/457037 . BUG=v8:5516 Change-Id: I1fd02c1109ef6e07e93da131062fd5101a8c8de9 Reviewed-on: https://chromium-review.googlesource.com/469767 Commit-Queue: Marja Hölttä <marja@chromium.org> Reviewed-by: Daniel Vogelheim <vogelheim@chromium.org> Cr-Commit-Position: refs/heads/master@{#44515}
This commit is contained in:
parent
df80cf0cb0
commit
da2a3b0c90
@ -2834,12 +2834,12 @@ Parser::LazyParsingResult Parser::SkipFunction(
|
||||
// functions are already created. Use data gathered during the preparse step
|
||||
// to skip the function.
|
||||
PreParseData::FunctionData data =
|
||||
reusable_preparser()->preparse_data()->GetTopLevelFunctionData(
|
||||
reusable_preparser()->preparse_data()->GetFunctionData(
|
||||
function_scope->start_position());
|
||||
if (data.is_valid()) {
|
||||
if (FLAG_trace_parse_tasks) {
|
||||
PrintF("Skipping top level func @ %d : %d using preparse data\n",
|
||||
data.start, data.end);
|
||||
function_scope->start_position(), data.end);
|
||||
}
|
||||
function_scope->set_end_position(data.end);
|
||||
scanner()->SeekForward(data.end - 1);
|
||||
@ -2861,15 +2861,25 @@ Parser::LazyParsingResult Parser::SkipFunction(
|
||||
// FIXME(marja): There are 3 ways to skip functions now. Unify them.
|
||||
if (preparsed_scope_data_->Consuming()) {
|
||||
DCHECK(FLAG_preparser_scope_analysis);
|
||||
int end_pos = kNoSourcePosition;
|
||||
if (preparsed_scope_data_->FindFunctionEnd(function_scope->start_position(),
|
||||
&end_pos)) {
|
||||
function_scope->set_end_position(end_pos);
|
||||
const PreParseData::FunctionData& data =
|
||||
preparsed_scope_data_->FindFunction(function_scope->start_position());
|
||||
if (data.is_valid()) {
|
||||
function_scope->set_is_skipped_function(true);
|
||||
function_scope->outer_scope()->SetMustUsePreParsedScopeData();
|
||||
scanner()->SeekForward(end_pos - 1);
|
||||
|
||||
function_scope->set_end_position(data.end);
|
||||
scanner()->SeekForward(data.end - 1);
|
||||
Expect(Token::RBRACE, CHECK_OK_VALUE(kLazyParsingComplete));
|
||||
// FIXME(marja): SkipFunctionLiterals still needed.
|
||||
*num_parameters = data.num_parameters;
|
||||
*function_length = data.function_length;
|
||||
SetLanguageMode(function_scope, data.language_mode);
|
||||
if (data.uses_super_property) {
|
||||
function_scope->RecordSuperPropertyUsage();
|
||||
}
|
||||
if (data.calls_eval) {
|
||||
function_scope->RecordEvalCall();
|
||||
}
|
||||
SkipFunctionLiterals(data.num_inner_functions);
|
||||
return kLazyParsingComplete;
|
||||
}
|
||||
}
|
||||
|
@ -56,23 +56,32 @@ ScriptData* ParserLogger::GetScriptData() {
|
||||
return result;
|
||||
}
|
||||
|
||||
PreParseData::FunctionData PreParseData::GetTopLevelFunctionData(
|
||||
int start) const {
|
||||
auto it = top_level_functions_data_.find(start);
|
||||
if (it != top_level_functions_data_.end()) {
|
||||
PreParseData::FunctionData PreParseData::GetFunctionData(int start) const {
|
||||
auto it = functions_.find(start);
|
||||
if (it != functions_.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return FunctionData();
|
||||
}
|
||||
|
||||
void PreParseData::AddTopLevelFunctionData(FunctionData&& data) {
|
||||
void PreParseData::AddFunctionData(int start, FunctionData&& data) {
|
||||
DCHECK(data.is_valid());
|
||||
top_level_functions_data_[data.start] = std::move(data);
|
||||
functions_[start] = std::move(data);
|
||||
}
|
||||
|
||||
void PreParseData::AddTopLevelFunctionData(const FunctionData& data) {
|
||||
void PreParseData::AddFunctionData(int start, const FunctionData& data) {
|
||||
DCHECK(data.is_valid());
|
||||
top_level_functions_data_[data.start] = data;
|
||||
functions_[start] = data;
|
||||
}
|
||||
|
||||
size_t PreParseData::size() const { return functions_.size(); }
|
||||
|
||||
PreParseData::const_iterator PreParseData::begin() const {
|
||||
return functions_.begin();
|
||||
}
|
||||
|
||||
PreParseData::const_iterator PreParseData::end() const {
|
||||
return functions_.end();
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
@ -103,22 +103,20 @@ class ParserLogger final {
|
||||
class PreParseData final {
|
||||
public:
|
||||
struct FunctionData {
|
||||
int start;
|
||||
int end;
|
||||
int num_parameters;
|
||||
int function_length;
|
||||
int num_inner_functions;
|
||||
LanguageMode language_mode;
|
||||
bool uses_super_property;
|
||||
bool calls_eval;
|
||||
bool uses_super_property : 1;
|
||||
bool calls_eval : 1;
|
||||
|
||||
FunctionData() : start(-1), end(-1) {}
|
||||
FunctionData() : end(-1) {}
|
||||
|
||||
FunctionData(int start, int end, int num_parameters, int function_length,
|
||||
FunctionData(int end, int num_parameters, int function_length,
|
||||
int num_inner_functions, LanguageMode language_mode,
|
||||
bool uses_super_property, bool calls_eval)
|
||||
: start(start),
|
||||
end(end),
|
||||
: end(end),
|
||||
num_parameters(num_parameters),
|
||||
function_length(function_length),
|
||||
num_inner_functions(num_inner_functions),
|
||||
@ -126,15 +124,20 @@ class PreParseData final {
|
||||
uses_super_property(uses_super_property),
|
||||
calls_eval(calls_eval) {}
|
||||
|
||||
bool is_valid() const { return start < end; }
|
||||
bool is_valid() const { return end > 0; }
|
||||
};
|
||||
|
||||
FunctionData GetTopLevelFunctionData(int start) const;
|
||||
void AddTopLevelFunctionData(FunctionData&& data);
|
||||
void AddTopLevelFunctionData(const FunctionData& data);
|
||||
FunctionData GetFunctionData(int start) const;
|
||||
void AddFunctionData(int start, FunctionData&& data);
|
||||
void AddFunctionData(int start, const FunctionData& data);
|
||||
size_t size() const;
|
||||
|
||||
typedef std::unordered_map<int, FunctionData>::const_iterator const_iterator;
|
||||
const_iterator begin() const;
|
||||
const_iterator end() const;
|
||||
|
||||
private:
|
||||
std::unordered_map<int, FunctionData> top_level_functions_data_;
|
||||
std::unordered_map<int, FunctionData> functions_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
|
@ -20,7 +20,7 @@ class VariableMaybeAssignedField
|
||||
class VariableContextAllocatedField
|
||||
: public BitField16<bool, VariableMaybeAssignedField::kNext, 1> {};
|
||||
|
||||
const int kFunctionDataSize = 3;
|
||||
const int kFunctionDataSize = 9;
|
||||
|
||||
} // namespace
|
||||
|
||||
@ -53,8 +53,19 @@ void PreParsedScopeData::SaveData(Scope* scope) {
|
||||
DCHECK(!has_data_);
|
||||
|
||||
if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
|
||||
function_index_[scope->start_position()] =
|
||||
std::make_pair(scope->end_position(), backing_store_.size());
|
||||
// This cast is OK since we're not going to have more than 2^32 elements in
|
||||
// the data. FIXME(marja): Implement limits for the data size.
|
||||
function_data_positions_[scope->start_position()] =
|
||||
static_cast<uint32_t>(backing_store_.size());
|
||||
// FIXME(marja): Fill in the missing fields: function_length +
|
||||
// num_inner_functions.
|
||||
function_index_.AddFunctionData(
|
||||
scope->start_position(),
|
||||
PreParseData::FunctionData(
|
||||
scope->end_position(), scope->num_parameters(), -1, -1,
|
||||
scope->language_mode(),
|
||||
scope->AsDeclarationScope()->uses_super_property(),
|
||||
scope->calls_eval()));
|
||||
}
|
||||
|
||||
if (!ScopeNeedsData(scope)) {
|
||||
@ -109,9 +120,16 @@ void PreParsedScopeData::RestoreData(Scope* scope, int* index_ptr) const {
|
||||
#ifdef DEBUG
|
||||
// Data integrity check.
|
||||
if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
|
||||
int end_position_from_data = -1;
|
||||
FindFunctionEnd(scope->start_position(), &end_position_from_data);
|
||||
DCHECK_EQ(end_position_from_data, scope->end_position());
|
||||
// FIXME(marja): Compare the missing fields too (function length,
|
||||
// num_inner_functions).
|
||||
const PreParseData::FunctionData& data =
|
||||
FindFunction(scope->start_position());
|
||||
DCHECK_EQ(data.end, scope->end_position());
|
||||
// FIXME(marja): unify num_parameters too and DCHECK here.
|
||||
DCHECK_EQ(data.language_mode, scope->language_mode());
|
||||
DCHECK_EQ(data.uses_super_property,
|
||||
scope->AsDeclarationScope()->uses_super_property());
|
||||
DCHECK_EQ(data.calls_eval, scope->calls_eval());
|
||||
int index_from_data = -1;
|
||||
FindFunctionData(scope->start_position(), &index_from_data);
|
||||
DCHECK_EQ(index_from_data, index);
|
||||
@ -158,9 +176,18 @@ FixedUint32Array* PreParsedScopeData::Serialize(Isolate* isolate) const {
|
||||
array->set(0, static_cast<uint32_t>(function_index_.size()));
|
||||
int i = 1;
|
||||
for (const auto& item : function_index_) {
|
||||
array->set(i++, item.first);
|
||||
array->set(i++, item.second.first);
|
||||
array->set(i++, item.second.second);
|
||||
const auto& it = function_data_positions_.find(item.first);
|
||||
DCHECK(it != function_data_positions_.end());
|
||||
const PreParseData::FunctionData& function_data = item.second;
|
||||
array->set(i++, item.first); // start position
|
||||
array->set(i++, it->second); // position in data
|
||||
array->set(i++, function_data.end);
|
||||
array->set(i++, function_data.num_parameters);
|
||||
array->set(i++, function_data.function_length);
|
||||
array->set(i++, function_data.num_inner_functions);
|
||||
array->set(i++, function_data.language_mode);
|
||||
array->set(i++, function_data.uses_super_property);
|
||||
array->set(i++, function_data.calls_eval);
|
||||
}
|
||||
|
||||
for (size_t j = 0; j < backing_store_.size(); ++j) {
|
||||
@ -182,8 +209,14 @@ void PreParsedScopeData::Deserialize(Handle<FixedUint32Array> array) {
|
||||
}
|
||||
int i = 1;
|
||||
for (; i < function_count * kFunctionDataSize + 1; i += kFunctionDataSize) {
|
||||
function_index_[array->get_scalar(i)] =
|
||||
std::make_pair(array->get_scalar(i + 1), array->get_scalar(i + 2));
|
||||
int start = array->get_scalar(i);
|
||||
function_data_positions_[start] = array->get_scalar(i + 1);
|
||||
function_index_.AddFunctionData(
|
||||
start, PreParseData::FunctionData(
|
||||
array->get_scalar(i + 2), array->get_scalar(i + 3),
|
||||
array->get_scalar(i + 4), array->get_scalar(i + 5),
|
||||
LanguageMode(array->get_scalar(i + 6)),
|
||||
array->get_scalar(i + 7), array->get_scalar(i + 8)));
|
||||
}
|
||||
CHECK_EQ(function_index_.size(), function_count);
|
||||
|
||||
@ -193,13 +226,9 @@ void PreParsedScopeData::Deserialize(Handle<FixedUint32Array> array) {
|
||||
}
|
||||
}
|
||||
|
||||
bool PreParsedScopeData::FindFunctionEnd(int start_pos, int* end_pos) const {
|
||||
auto it = function_index_.find(start_pos);
|
||||
if (it == function_index_.end()) {
|
||||
return false;
|
||||
}
|
||||
*end_pos = it->second.first;
|
||||
return true;
|
||||
PreParseData::FunctionData PreParsedScopeData::FindFunction(
|
||||
int start_pos) const {
|
||||
return function_index_.GetFunctionData(start_pos);
|
||||
}
|
||||
|
||||
void PreParsedScopeData::SaveDataForVariable(Variable* var) {
|
||||
@ -271,11 +300,11 @@ void PreParsedScopeData::RestoreDataForInnerScopes(Scope* scope,
|
||||
}
|
||||
|
||||
bool PreParsedScopeData::FindFunctionData(int start_pos, int* index) const {
|
||||
auto it = function_index_.find(start_pos);
|
||||
if (it == function_index_.end()) {
|
||||
auto it = function_data_positions_.find(start_pos);
|
||||
if (it == function_data_positions_.end()) {
|
||||
return false;
|
||||
}
|
||||
*index = it->second.second;
|
||||
*index = it->second;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "src/globals.h"
|
||||
#include "src/objects.h"
|
||||
#include "src/parsing/preparse-data.h"
|
||||
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
@ -76,7 +77,7 @@ class PreParsedScopeData {
|
||||
|
||||
bool Producing() const { return !has_data_; }
|
||||
|
||||
bool FindFunctionEnd(int start_pos, int* end_pos) const;
|
||||
PreParseData::FunctionData FindFunction(int start_pos) const;
|
||||
|
||||
private:
|
||||
friend class ScopeTestHelper;
|
||||
@ -93,8 +94,11 @@ class PreParsedScopeData {
|
||||
// TODO(marja): Make the backing store more efficient once we know exactly
|
||||
// what data is needed.
|
||||
std::vector<byte> backing_store_;
|
||||
// Start pos -> (end pos, index in data)
|
||||
std::unordered_map<uint32_t, std::pair<uint32_t, uint32_t>> function_index_;
|
||||
|
||||
// Start pos -> FunctionData.
|
||||
PreParseData function_index_;
|
||||
// Start pos -> position in backing_store_.
|
||||
std::unordered_map<uint32_t, uint32_t> function_data_positions_;
|
||||
|
||||
bool has_data_ = false;
|
||||
|
||||
|
@ -327,11 +327,13 @@ PreParser::Expression PreParser::ParseFunctionLiteral(
|
||||
}
|
||||
|
||||
if (FLAG_use_parse_tasks && is_top_level && preparse_data_) {
|
||||
preparse_data_->AddTopLevelFunctionData(PreParseData::FunctionData(
|
||||
start_position, end_position, formals.num_parameters(),
|
||||
formals.function_length, GetLastFunctionLiteralId() - func_id,
|
||||
language_mode, function_scope->uses_super_property(),
|
||||
function_scope->calls_eval()));
|
||||
preparse_data_->AddFunctionData(
|
||||
start_position,
|
||||
PreParseData::FunctionData(
|
||||
end_position, formals.num_parameters(), formals.function_length,
|
||||
GetLastFunctionLiteralId() - func_id, language_mode,
|
||||
function_scope->uses_super_property(),
|
||||
function_scope->calls_eval()));
|
||||
// TODO(wiktorg) spin-off a parse task
|
||||
if (FLAG_trace_parse_tasks) {
|
||||
PrintF("Saved function at %d to %d with:\n", start_position,
|
||||
|
Loading…
Reference in New Issue
Block a user