Commit d553c943 authored by Marja Hölttä's avatar Marja Hölttä Committed by Commit Bot

[reland] [parser] Skipping inner funcs: Use less memory for variables.

- Make it possible to store quarter-bytes instead of full bytes.

- Don't store is_used; it can be recovered correctly based on the actual full
  parse (when a lazy function is eventually called) and
  has_forced_scope_allocation.

- With the is_used change, the old testing approach (which compared a scope for
  which we didn't do scope allocation to the baseline) no longer made
  sense. Replaced it with a new testing approach, which is also closer to the
  actual usage.

- First version (reverted): https://chromium-review.googlesource.com/725422

BUG=v8:5516

Change-Id: I1468af6670b689a104bd867377caa1d236070820
Reviewed-on: https://chromium-review.googlesource.com/733123Reviewed-by: 's avatarAdam Klein <adamk@chromium.org>
Commit-Queue: Marja Hölttä <marja@chromium.org>
Cr-Commit-Position: refs/heads/master@{#48903}
parent eeaffa9f
...@@ -20,17 +20,16 @@ class ScopeCallsSloppyEvalField : public BitField<bool, 0, 1> {}; ...@@ -20,17 +20,16 @@ class ScopeCallsSloppyEvalField : public BitField<bool, 0, 1> {};
class InnerScopeCallsEvalField class InnerScopeCallsEvalField
: public BitField<bool, ScopeCallsSloppyEvalField::kNext, 1> {}; : public BitField<bool, ScopeCallsSloppyEvalField::kNext, 1> {};
class VariableIsUsedField : public BitField16<bool, 0, 1> {}; class VariableMaybeAssignedField : public BitField8<bool, 0, 1> {};
class VariableMaybeAssignedField
: public BitField16<bool, VariableIsUsedField::kNext, 1> {};
class VariableContextAllocatedField class VariableContextAllocatedField
: public BitField16<bool, VariableMaybeAssignedField::kNext, 1> {}; : public BitField8<bool, VariableMaybeAssignedField::kNext, 1> {};
const int kMagicValue = 0xc0de0de; const int kMagicValue = 0xc0de0de;
#ifdef DEBUG #ifdef DEBUG
const size_t kUint32Size = 5; const size_t kUint32Size = 5;
const size_t kUint8Size = 2; const size_t kUint8Size = 2;
const size_t kQuarterMarker = 0;
#else #else
const size_t kUint32Size = 4; const size_t kUint32Size = 4;
const size_t kUint8Size = 1; const size_t kUint8Size = 1;
...@@ -39,8 +38,8 @@ const size_t kUint8Size = 1; ...@@ -39,8 +38,8 @@ const size_t kUint8Size = 1;
const int kPlaceholderSize = kUint32Size; const int kPlaceholderSize = kUint32Size;
const int kSkippableFunctionDataSize = 4 * kUint32Size + 1 * kUint8Size; const int kSkippableFunctionDataSize = 4 * kUint32Size + 1 * kUint8Size;
class LanguageField : public BitField<LanguageMode, 0, 1> {}; class LanguageField : public BitField8<LanguageMode, 0, 1> {};
class UsesSuperField : public BitField<bool, LanguageField::kNext, 1> {}; class UsesSuperField : public BitField8<bool, LanguageField::kNext, 1> {};
STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues); STATIC_ASSERT(LanguageModeSize <= LanguageField::kNumValues);
} // namespace } // namespace
...@@ -99,6 +98,7 @@ void ProducedPreParsedScopeData::ByteData::WriteUint32(uint32_t data) { ...@@ -99,6 +98,7 @@ void ProducedPreParsedScopeData::ByteData::WriteUint32(uint32_t data) {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
backing_store_.push_back(*d++); backing_store_.push_back(*d++);
} }
free_quarters_in_last_byte_ = 0;
} }
void ProducedPreParsedScopeData::ByteData::OverwriteFirstUint32(uint32_t data) { void ProducedPreParsedScopeData::ByteData::OverwriteFirstUint32(uint32_t data) {
...@@ -121,6 +121,25 @@ void ProducedPreParsedScopeData::ByteData::WriteUint8(uint8_t data) { ...@@ -121,6 +121,25 @@ void ProducedPreParsedScopeData::ByteData::WriteUint8(uint8_t data) {
backing_store_.push_back(kUint8Size); backing_store_.push_back(kUint8Size);
#endif #endif
backing_store_.push_back(data); backing_store_.push_back(data);
free_quarters_in_last_byte_ = 0;
}
void ProducedPreParsedScopeData::ByteData::WriteQuarter(uint8_t data) {
DCHECK_LE(data, 3);
if (free_quarters_in_last_byte_ == 0) {
#ifdef DEBUG
// Save a marker in debug mode.
backing_store_.push_back(kQuarterMarker);
#endif
backing_store_.push_back(0);
free_quarters_in_last_byte_ = 3;
} else {
--free_quarters_in_last_byte_;
}
uint8_t shift_amount = free_quarters_in_last_byte_ * 2;
DCHECK_EQ(backing_store_.back() & (3 << shift_amount), 0);
backing_store_.back() |= (data << shift_amount);
} }
Handle<PodArray<uint8_t>> ProducedPreParsedScopeData::ByteData::Serialize( Handle<PodArray<uint8_t>> ProducedPreParsedScopeData::ByteData::Serialize(
...@@ -216,7 +235,7 @@ void ProducedPreParsedScopeData::AddSkippableFunction( ...@@ -216,7 +235,7 @@ void ProducedPreParsedScopeData::AddSkippableFunction(
uint8_t language_and_super = LanguageField::encode(language_mode) | uint8_t language_and_super = LanguageField::encode(language_mode) |
UsesSuperField::encode(uses_super_property); UsesSuperField::encode(uses_super_property);
byte_data_->WriteUint8(language_and_super); byte_data_->WriteQuarter(language_and_super);
} }
void ProducedPreParsedScopeData::SaveScopeAllocationData( void ProducedPreParsedScopeData::SaveScopeAllocationData(
...@@ -382,14 +401,11 @@ void ProducedPreParsedScopeData::SaveDataForVariable(Variable* var) { ...@@ -382,14 +401,11 @@ void ProducedPreParsedScopeData::SaveDataForVariable(Variable* var) {
byte_data_->WriteUint8(name->raw_data()[i]); byte_data_->WriteUint8(name->raw_data()[i]);
} }
#endif #endif
// FIXME(marja): Only 3 bits needed, not a full byte. byte variable_data = VariableMaybeAssignedField::encode(
byte variable_data = VariableIsUsedField::encode(var->is_used()) |
VariableMaybeAssignedField::encode(
var->maybe_assigned() == kMaybeAssigned) | var->maybe_assigned() == kMaybeAssigned) |
VariableContextAllocatedField::encode( VariableContextAllocatedField::encode(
var->has_forced_context_allocation()); var->has_forced_context_allocation());
byte_data_->WriteQuarter(variable_data);
byte_data_->WriteUint8(variable_data);
} }
void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) { void ProducedPreParsedScopeData::SaveDataForInnerScopes(Scope* scope) {
...@@ -429,6 +445,7 @@ int32_t ConsumedPreParsedScopeData::ByteData::ReadUint32() { ...@@ -429,6 +445,7 @@ int32_t ConsumedPreParsedScopeData::ByteData::ReadUint32() {
for (int i = 0; i < 4; ++i) { for (int i = 0; i < 4; ++i) {
*p++ = data_->get(index_++); *p++ = data_->get(index_++);
} }
stored_quarters_ = 0;
return result; return result;
} }
...@@ -439,9 +456,29 @@ uint8_t ConsumedPreParsedScopeData::ByteData::ReadUint8() { ...@@ -439,9 +456,29 @@ uint8_t ConsumedPreParsedScopeData::ByteData::ReadUint8() {
// Check that there indeed is a byte following. // Check that there indeed is a byte following.
DCHECK_EQ(data_->get(index_++), kUint8Size); DCHECK_EQ(data_->get(index_++), kUint8Size);
#endif #endif
stored_quarters_ = 0;
return data_->get(index_++); return data_->get(index_++);
} }
uint8_t ConsumedPreParsedScopeData::ByteData::ReadQuarter() {
DCHECK_NOT_NULL(data_);
if (stored_quarters_ == 0) {
DCHECK_GE(RemainingBytes(), kUint8Size);
#ifdef DEBUG
// Check that there indeed are quarters following.
DCHECK_EQ(data_->get(index_++), kQuarterMarker);
#endif
stored_byte_ = data_->get(index_++);
stored_quarters_ = 4;
}
// Read the first 2 bits from stored_byte_.
uint8_t result = (stored_byte_ >> 6) & 3;
DCHECK_LE(result, 3);
--stored_quarters_;
stored_byte_ <<= 2;
return result;
}
ConsumedPreParsedScopeData::ConsumedPreParsedScopeData() ConsumedPreParsedScopeData::ConsumedPreParsedScopeData()
: scope_data_(new ByteData()), child_index_(0) {} : scope_data_(new ByteData()), child_index_(0) {}
...@@ -477,7 +514,7 @@ ConsumedPreParsedScopeData::GetDataForSkippableFunction( ...@@ -477,7 +514,7 @@ ConsumedPreParsedScopeData::GetDataForSkippableFunction(
*num_parameters = scope_data_->ReadUint32(); *num_parameters = scope_data_->ReadUint32();
*num_inner_functions = scope_data_->ReadUint32(); *num_inner_functions = scope_data_->ReadUint32();
uint8_t language_and_super = scope_data_->ReadUint8(); uint8_t language_and_super = scope_data_->ReadQuarter();
*language_mode = LanguageMode(LanguageField::decode(language_and_super)); *language_mode = LanguageMode(LanguageField::decode(language_and_super));
*uses_super_property = UsesSuperField::decode(language_and_super); *uses_super_property = UsesSuperField::decode(language_and_super);
...@@ -518,13 +555,6 @@ void ConsumedPreParsedScopeData::RestoreScopeAllocationData( ...@@ -518,13 +555,6 @@ void ConsumedPreParsedScopeData::RestoreScopeAllocationData(
DCHECK_EQ(scope_data_->RemainingBytes(), 0); DCHECK_EQ(scope_data_->RemainingBytes(), 0);
} }
void ConsumedPreParsedScopeData::SkipFunctionDataForTesting() {
ByteData::ReadingScope reading_scope(this);
scope_data_->SetPosition(0);
uint32_t scope_data_start = scope_data_->ReadUint32();
scope_data_->SetPosition(scope_data_start);
}
void ConsumedPreParsedScopeData::RestoreData(Scope* scope) { void ConsumedPreParsedScopeData::RestoreData(Scope* scope) {
if (scope->is_declaration_scope() && if (scope->is_declaration_scope() &&
scope->AsDeclarationScope()->is_skipped_function()) { scope->AsDeclarationScope()->is_skipped_function()) {
...@@ -581,15 +611,12 @@ void ConsumedPreParsedScopeData::RestoreDataForVariable(Variable* var) { ...@@ -581,15 +611,12 @@ void ConsumedPreParsedScopeData::RestoreDataForVariable(Variable* var) {
DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]); DCHECK_EQ(scope_data_->ReadUint8(), name->raw_data()[i]);
} }
#endif #endif
CHECK_GE(scope_data_->RemainingBytes(), kUint8Size); uint8_t variable_data = scope_data_->ReadQuarter();
uint8_t variable_data = scope_data_->ReadUint8();
if (VariableIsUsedField::decode(variable_data)) {
var->set_is_used();
}
if (VariableMaybeAssignedField::decode(variable_data)) { if (VariableMaybeAssignedField::decode(variable_data)) {
var->set_maybe_assigned(); var->set_maybe_assigned();
} }
if (VariableContextAllocatedField::decode(variable_data)) { if (VariableContextAllocatedField::decode(variable_data)) {
var->set_is_used();
var->ForceContextAllocation(); var->ForceContextAllocation();
} }
} }
......
...@@ -69,10 +69,12 @@ class ProducedPreParsedScopeData : public ZoneObject { ...@@ -69,10 +69,12 @@ class ProducedPreParsedScopeData : public ZoneObject {
public: public:
class ByteData : public ZoneObject { class ByteData : public ZoneObject {
public: public:
explicit ByteData(Zone* zone) : backing_store_(zone) {} explicit ByteData(Zone* zone)
: backing_store_(zone), free_quarters_in_last_byte_(0) {}
void WriteUint32(uint32_t data); void WriteUint32(uint32_t data);
void WriteUint8(uint8_t data); void WriteUint8(uint8_t data);
void WriteQuarter(uint8_t data);
// For overwriting previously written data at position 0. // For overwriting previously written data at position 0.
void OverwriteFirstUint32(uint32_t data); void OverwriteFirstUint32(uint32_t data);
...@@ -83,6 +85,7 @@ class ProducedPreParsedScopeData : public ZoneObject { ...@@ -83,6 +85,7 @@ class ProducedPreParsedScopeData : public ZoneObject {
private: private:
ZoneDeque<uint8_t> backing_store_; ZoneDeque<uint8_t> backing_store_;
uint8_t free_quarters_in_last_byte_;
}; };
// Create a ProducedPreParsedScopeData object which will collect data as we // Create a ProducedPreParsedScopeData object which will collect data as we
...@@ -181,7 +184,8 @@ class ConsumedPreParsedScopeData { ...@@ -181,7 +184,8 @@ class ConsumedPreParsedScopeData {
public: public:
class ByteData { class ByteData {
public: public:
ByteData() : data_(nullptr), index_(0) {} ByteData()
: data_(nullptr), index_(0), stored_quarters_(0), stored_byte_(0) {}
// Reading from the ByteData is only allowed when a ReadingScope is on the // Reading from the ByteData is only allowed when a ReadingScope is on the
// stack. This ensures that we have a DisallowHeapAllocation in place // stack. This ensures that we have a DisallowHeapAllocation in place
...@@ -204,6 +208,7 @@ class ConsumedPreParsedScopeData { ...@@ -204,6 +208,7 @@ class ConsumedPreParsedScopeData {
int32_t ReadUint32(); int32_t ReadUint32();
uint8_t ReadUint8(); uint8_t ReadUint8();
uint8_t ReadQuarter();
size_t RemainingBytes() const { size_t RemainingBytes() const {
DCHECK_NOT_NULL(data_); DCHECK_NOT_NULL(data_);
...@@ -213,6 +218,8 @@ class ConsumedPreParsedScopeData { ...@@ -213,6 +218,8 @@ class ConsumedPreParsedScopeData {
// private: // private:
PodArray<uint8_t>* data_; PodArray<uint8_t>* data_;
int index_; int index_;
uint8_t stored_quarters_;
uint8_t stored_byte_;
}; };
ConsumedPreParsedScopeData(); ConsumedPreParsedScopeData();
...@@ -231,11 +238,6 @@ class ConsumedPreParsedScopeData { ...@@ -231,11 +238,6 @@ class ConsumedPreParsedScopeData {
// subscopes') variables. // subscopes') variables.
void RestoreScopeAllocationData(DeclarationScope* scope); void RestoreScopeAllocationData(DeclarationScope* scope);
// Skips the data about skippable functions, moves straight to the scope
// allocation data. Useful for tests which don't want to verify only the scope
// allocation data.
void SkipFunctionDataForTesting();
private: private:
void RestoreData(Scope* scope); void RestoreData(Scope* scope);
void RestoreDataForVariable(Variable* var); void RestoreDataForVariable(Variable* var);
......
This diff is collapsed.
...@@ -17,10 +17,6 @@ class ScopeTestHelper { ...@@ -17,10 +17,6 @@ class ScopeTestHelper {
return var->scope()->MustAllocateInContext(var); return var->scope()->MustAllocateInContext(var);
} }
static void AllocateWithoutVariableResolution(Scope* scope) {
scope->AllocateVariablesRecursively();
}
static void CompareScopes(Scope* baseline, Scope* scope, static void CompareScopes(Scope* baseline, Scope* scope,
bool precise_maybe_assigned) { bool precise_maybe_assigned) {
CHECK_EQ(baseline->scope_type(), scope->scope_type()); CHECK_EQ(baseline->scope_type(), scope->scope_type());
...@@ -109,6 +105,20 @@ class ScopeTestHelper { ...@@ -109,6 +105,20 @@ class ScopeTestHelper {
MarkInnerFunctionsAsSkipped(inner); MarkInnerFunctionsAsSkipped(inner);
} }
} }
static bool HasSkippedFunctionInside(Scope* scope) {
if (scope->scope_type() == ScopeType::FUNCTION_SCOPE &&
scope->AsDeclarationScope()->is_skipped_function()) {
return true;
}
for (Scope* inner = scope->inner_scope(); inner != nullptr;
inner = inner->sibling()) {
if (HasSkippedFunctionInside(inner)) {
return true;
}
}
return false;
}
}; };
} // namespace internal } // namespace internal
} // namespace v8 } // namespace v8
......
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