[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:
Marja Hölttä 2017-04-10 13:27:00 +02:00 committed by Commit Bot
parent df80cf0cb0
commit da2a3b0c90
6 changed files with 114 additions and 57 deletions

View File

@ -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;
}
}

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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;

View File

@ -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,