Commit aecb020e authored by Camillo Bruni's avatar Camillo Bruni Committed by Commit Bot

[parser] Use shared buffer to create PreparseData

Directly access the std::vector buffer backing store to write bytes. By
reserving enough space upfront we can avoid many superflous bounds checks
that were previously necessary when using push_back.

Change-Id: I9b2fb467809e40743b0d9409c9cccb0c6f36f8c1
Reviewed-on: https://chromium-review.googlesource.com/c/1425910
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#59036}
parent eab3508a
...@@ -92,8 +92,8 @@ class BaseConsumedPreparseData : public ConsumedPreparseData { ...@@ -92,8 +92,8 @@ class BaseConsumedPreparseData : public ConsumedPreparseData {
} }
int32_t ReadVarint32() { int32_t ReadVarint32() {
DCHECK(HasRemainingBytes(kVarintMinSize)); DCHECK(HasRemainingBytes(kVarint32MinSize));
DCHECK_EQ(data_.get(index_++), kVarintMinSize); DCHECK_EQ(data_.get(index_++), kVarint32MinSize);
int32_t value = 0; int32_t value = 0;
bool has_another_byte; bool has_another_byte;
unsigned shift = 0; unsigned shift = 0;
...@@ -103,7 +103,7 @@ class BaseConsumedPreparseData : public ConsumedPreparseData { ...@@ -103,7 +103,7 @@ class BaseConsumedPreparseData : public ConsumedPreparseData {
shift += 7; shift += 7;
has_another_byte = byte & 0x80; has_another_byte = byte & 0x80;
} while (has_another_byte); } while (has_another_byte);
DCHECK_EQ(data_.get(index_++), kVarintEndMarker); DCHECK_EQ(data_.get(index_++), kVarint32EndMarker);
stored_quarters_ = 0; stored_quarters_ = 0;
return value; return value;
} }
......
...@@ -117,41 +117,65 @@ PreparseDataBuilder::DataGatheringScope::~DataGatheringScope() { ...@@ -117,41 +117,65 @@ PreparseDataBuilder::DataGatheringScope::~DataGatheringScope() {
parent->AddChild(builder_); parent->AddChild(builder_);
} }
void PreparseDataBuilder::ByteData::Start(std::vector<uint8_t>* buffer) {
DCHECK(!is_finalized_);
byte_data_ = buffer;
DCHECK_EQ(byte_data_->size(), 0);
DCHECK_EQ(index_, 0);
}
void PreparseDataBuilder::ByteData::Finalize(Zone* zone) {
uint8_t* raw_zone_data =
static_cast<uint8_t*>(ZoneAllocationPolicy(zone).New(index_));
memcpy(raw_zone_data, byte_data_->data(), index_);
byte_data_->resize(0);
zone_byte_data_ = Vector<uint8_t>(raw_zone_data, index_);
#ifdef DEBUG
is_finalized_ = true;
#endif
}
void PreparseDataBuilder::ByteData::Reserve(size_t bytes) {
// Make sure we have at least {bytes} capacity left in the buffer_.
DCHECK_LE(length(), byte_data_->size());
size_t capacity = byte_data_->size() - length();
if (capacity >= bytes) return;
size_t delta = bytes - capacity;
byte_data_->insert(byte_data_->end(), delta, 0);
}
int PreparseDataBuilder::ByteData::length() const { return index_; }
void PreparseDataBuilder::ByteData::Add(uint8_t byte) {
DCHECK_LE(0, index_);
DCHECK_LT(index_, byte_data_->size());
(*byte_data_)[index_++] = byte;
}
#ifdef DEBUG #ifdef DEBUG
void PreparseDataBuilder::ByteData::WriteUint32(uint32_t data) { void PreparseDataBuilder::ByteData::WriteUint32(uint32_t data) {
DCHECK(!is_finalized_); DCHECK(!is_finalized_);
byte_data_->push_back(kUint32Size); Add(kUint32Size);
byte_data_->push_back(data & 0xFF); Add(data & 0xFF);
byte_data_->push_back((data >> 8) & 0xFF); Add((data >> 8) & 0xFF);
byte_data_->push_back((data >> 16) & 0xFF); Add((data >> 16) & 0xFF);
byte_data_->push_back((data >> 24) & 0xFF); Add((data >> 24) & 0xFF);
free_quarters_in_last_byte_ = 0; free_quarters_in_last_byte_ = 0;
} }
void PreparseDataBuilder::ByteData::SaveCurrentSizeAtFirstUint32() { void PreparseDataBuilder::ByteData::SaveCurrentSizeAtFirstUint32() {
CHECK(!is_finalized_); int current_length = length();
uint32_t data = static_cast<uint32_t>(byte_data_->size()); index_ = 0;
uint8_t* start = &byte_data_->front(); CHECK_EQ(byte_data_->at(0), kUint32Size);
int i = 0; WriteUint32(current_length);
// Check that that position already holds an item of the expected size. index_ = current_length;
CHECK_GE(byte_data_->size(), kUint32Size);
CHECK_EQ(start[i++], kUint32Size);
start[i++] = data & 0xFF;
start[i++] = (data >> 8) & 0xFF;
start[i++] = (data >> 16) & 0xFF;
start[i++] = (data >> 24) & 0xFF;
}
int PreparseDataBuilder::ByteData::length() const {
CHECK(!is_finalized_);
return static_cast<int>(byte_data_->size());
} }
#endif #endif
void PreparseDataBuilder::ByteData::WriteVarint32(uint32_t data) { void PreparseDataBuilder::ByteData::WriteVarint32(uint32_t data) {
#ifdef DEBUG #ifdef DEBUG
// Save expected item size in debug mode. // Save expected item size in debug mode.
byte_data_->push_back(kVarintMinSize); Add(kVarint32MinSize);
#endif #endif
// See ValueSerializer::WriteVarint. // See ValueSerializer::WriteVarint.
do { do {
...@@ -159,11 +183,10 @@ void PreparseDataBuilder::ByteData::WriteVarint32(uint32_t data) { ...@@ -159,11 +183,10 @@ void PreparseDataBuilder::ByteData::WriteVarint32(uint32_t data) {
data >>= 7; data >>= 7;
// Add continue bit. // Add continue bit.
if (data) next_byte |= 0x80; if (data) next_byte |= 0x80;
byte_data_->push_back(next_byte & 0xFF); Add(next_byte & 0xFF);
} while (data); } while (data);
#ifdef DEBUG #ifdef DEBUG
// Save a varint marker in debug mode. Add(kVarint32EndMarker);
byte_data_->push_back(kVarintEndMarker);
#endif #endif
free_quarters_in_last_byte_ = 0; free_quarters_in_last_byte_ = 0;
} }
...@@ -172,9 +195,9 @@ void PreparseDataBuilder::ByteData::WriteUint8(uint8_t data) { ...@@ -172,9 +195,9 @@ void PreparseDataBuilder::ByteData::WriteUint8(uint8_t data) {
DCHECK(!is_finalized_); DCHECK(!is_finalized_);
#ifdef DEBUG #ifdef DEBUG
// Save expected item size in debug mode. // Save expected item size in debug mode.
byte_data_->push_back(kUint8Size); Add(kUint8Size);
#endif #endif
byte_data_->push_back(data); Add(data);
free_quarters_in_last_byte_ = 0; free_quarters_in_last_byte_ = 0;
} }
...@@ -184,37 +207,17 @@ void PreparseDataBuilder::ByteData::WriteQuarter(uint8_t data) { ...@@ -184,37 +207,17 @@ void PreparseDataBuilder::ByteData::WriteQuarter(uint8_t data) {
if (free_quarters_in_last_byte_ == 0) { if (free_quarters_in_last_byte_ == 0) {
#ifdef DEBUG #ifdef DEBUG
// Save a marker in debug mode. // Save a marker in debug mode.
byte_data_->push_back(kQuarterMarker); Add(kQuarterMarker);
#endif #endif
byte_data_->push_back(0); Add(0);
free_quarters_in_last_byte_ = 3; free_quarters_in_last_byte_ = 3;
} else { } else {
--free_quarters_in_last_byte_; --free_quarters_in_last_byte_;
} }
uint8_t shift_amount = free_quarters_in_last_byte_ * 2; uint8_t shift_amount = free_quarters_in_last_byte_ * 2;
DCHECK_EQ(byte_data_->back() & (3 << shift_amount), 0); DCHECK_EQ(byte_data_->at(index_ - 1) & (3 << shift_amount), 0);
byte_data_->back() |= (data << shift_amount); (*byte_data_)[index_ - 1] |= (data << shift_amount);
}
void PreparseDataBuilder::ByteData::Start(std::vector<uint8_t>* buffer) {
DCHECK(!is_finalized_);
byte_data_ = buffer;
DCHECK_EQ(byte_data_->size(), 0);
}
void PreparseDataBuilder::ByteData::Finalize(Zone* zone) {
int size = static_cast<int>(byte_data_->size());
uint8_t* raw_zone_data =
static_cast<uint8_t*>(ZoneAllocationPolicy(zone).New(size));
memcpy(raw_zone_data, &byte_data_->front(), size);
byte_data_->resize(0);
zone_byte_data_ = Vector<uint8_t>(raw_zone_data, size);
#ifdef DEBUG
is_finalized_ = true;
#endif
} }
void PreparseDataBuilder::DataGatheringScope::SetSkippableFunction( void PreparseDataBuilder::DataGatheringScope::SetSkippableFunction(
...@@ -301,8 +304,10 @@ void PreparseDataBuilder::SaveScopeAllocationData(DeclarationScope* scope, ...@@ -301,8 +304,10 @@ void PreparseDataBuilder::SaveScopeAllocationData(DeclarationScope* scope,
#ifdef DEBUG #ifdef DEBUG
// Reserve Uint32 for scope_data_start debug info. // Reserve Uint32 for scope_data_start debug info.
byte_data_.Reserve(kUint32Size);
byte_data_.WriteUint32(0); byte_data_.WriteUint32(0);
#endif #endif
byte_data_.Reserve(children_.size() * kSkippableFunctionMaxDataSize);
DCHECK(finalized_children_); DCHECK(finalized_children_);
for (const auto& builder : children_) { for (const auto& builder : children_) {
// Keep track of functions with inner data. {children_} contains also the // Keep track of functions with inner data. {children_} contains also the
...@@ -320,6 +325,7 @@ void PreparseDataBuilder::SaveScopeAllocationData(DeclarationScope* scope, ...@@ -320,6 +325,7 @@ void PreparseDataBuilder::SaveScopeAllocationData(DeclarationScope* scope,
byte_data_.SaveCurrentSizeAtFirstUint32(); byte_data_.SaveCurrentSizeAtFirstUint32();
// For a data integrity check, write a value between data about skipped inner // For a data integrity check, write a value between data about skipped inner
// funcs and data about variables. // funcs and data about variables.
byte_data_.Reserve(kUint32Size * 3);
byte_data_.WriteUint32(kMagicValue); byte_data_.WriteUint32(kMagicValue);
byte_data_.WriteUint32(scope->start_position()); byte_data_.WriteUint32(scope->start_position());
byte_data_.WriteUint32(scope->end_position()); byte_data_.WriteUint32(scope->end_position());
...@@ -335,6 +341,7 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) { ...@@ -335,6 +341,7 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) {
DCHECK(ScopeNeedsData(scope)); DCHECK(ScopeNeedsData(scope));
#ifdef DEBUG #ifdef DEBUG
byte_data_.Reserve(kUint8Size);
byte_data_.WriteUint8(scope->scope_type()); byte_data_.WriteUint8(scope->scope_type());
#endif #endif
...@@ -343,6 +350,7 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) { ...@@ -343,6 +350,7 @@ void PreparseDataBuilder::SaveDataForScope(Scope* scope) {
scope->is_declaration_scope() && scope->is_declaration_scope() &&
scope->AsDeclarationScope()->calls_sloppy_eval()) | scope->AsDeclarationScope()->calls_sloppy_eval()) |
InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval()); InnerScopeCallsEvalField::encode(scope->inner_scope_calls_eval());
byte_data_.Reserve(kUint8Size);
byte_data_.WriteUint8(eval); byte_data_.WriteUint8(eval);
if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) { if (scope->scope_type() == ScopeType::FUNCTION_SCOPE) {
...@@ -362,6 +370,7 @@ void PreparseDataBuilder::SaveDataForVariable(Variable* var) { ...@@ -362,6 +370,7 @@ void PreparseDataBuilder::SaveDataForVariable(Variable* var) {
// Store the variable name in debug mode; this way we can check that we // Store the variable name in debug mode; this way we can check that we
// restore data to the correct variable. // restore data to the correct variable.
const AstRawString* name = var->raw_name(); const AstRawString* name = var->raw_name();
byte_data_.Reserve(kUint32Size + (name->length() + 1) * kUint8Size);
byte_data_.WriteUint8(name->is_one_byte()); byte_data_.WriteUint8(name->is_one_byte());
byte_data_.WriteUint32(name->length()); byte_data_.WriteUint32(name->length());
for (int i = 0; i < name->length(); ++i) { for (int i = 0; i < name->length(); ++i) {
...@@ -373,6 +382,7 @@ void PreparseDataBuilder::SaveDataForVariable(Variable* var) { ...@@ -373,6 +382,7 @@ void PreparseDataBuilder::SaveDataForVariable(Variable* var) {
var->maybe_assigned() == kMaybeAssigned) | var->maybe_assigned() == kMaybeAssigned) |
VariableContextAllocatedField::encode( VariableContextAllocatedField::encode(
var->has_forced_context_allocation()); var->has_forced_context_allocation());
byte_data_.Reserve(kUint8Size);
byte_data_.WriteQuarter(variable_data); byte_data_.WriteQuarter(variable_data);
} }
......
...@@ -68,20 +68,24 @@ struct PreparseByteDataConstants { ...@@ -68,20 +68,24 @@ struct PreparseByteDataConstants {
static constexpr int kMagicValue = 0xC0DE0DE; static constexpr int kMagicValue = 0xC0DE0DE;
static constexpr size_t kUint32Size = 5; static constexpr size_t kUint32Size = 5;
static constexpr size_t kVarintMinSize = 3; static constexpr size_t kVarint32MinSize = 3;
static constexpr size_t kVarintEndMarker = 0xF1; static constexpr size_t kVarint32MaxSize = 7;
static constexpr size_t kVarint32EndMarker = 0xF1;
static constexpr size_t kUint8Size = 2; static constexpr size_t kUint8Size = 2;
static constexpr size_t kQuarterMarker = 0xF2; static constexpr size_t kQuarterMarker = 0xF2;
static constexpr size_t kPlaceholderSize = kUint32Size; static constexpr size_t kPlaceholderSize = kUint32Size;
#else #else
static constexpr size_t kUint32Size = 4; static constexpr size_t kUint32Size = 4;
static constexpr size_t kVarintMinSize = 1; static constexpr size_t kVarint32MinSize = 1;
static constexpr size_t kVarint32MaxSize = 5;
static constexpr size_t kUint8Size = 1; static constexpr size_t kUint8Size = 1;
static constexpr size_t kPlaceholderSize = 0; static constexpr size_t kPlaceholderSize = 0;
#endif #endif
static const size_t kSkippableFunctionMinDataSize = static const size_t kSkippableFunctionMinDataSize =
4 * kVarintMinSize + 1 * kUint8Size; 4 * kVarint32MinSize + 1 * kUint8Size;
static const size_t kSkippableFunctionMaxDataSize =
4 * kVarint32MaxSize + 1 * kUint8Size;
}; };
class PreparseDataBuilder : public ZoneObject, class PreparseDataBuilder : public ZoneObject,
...@@ -117,7 +121,8 @@ class PreparseDataBuilder : public ZoneObject, ...@@ -117,7 +121,8 @@ class PreparseDataBuilder : public ZoneObject,
class ByteData : public ZoneObject, public PreparseByteDataConstants { class ByteData : public ZoneObject, public PreparseByteDataConstants {
public: public:
ByteData() : byte_data_(nullptr), free_quarters_in_last_byte_(0) {} ByteData()
: byte_data_(nullptr), index_(0), free_quarters_in_last_byte_(0) {}
~ByteData() {} ~ByteData() {}
...@@ -127,6 +132,10 @@ class PreparseDataBuilder : public ZoneObject, ...@@ -127,6 +132,10 @@ class PreparseDataBuilder : public ZoneObject,
Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length); Handle<PreparseData> CopyToHeap(Isolate* isolate, int children_length);
ZonePreparseData* CopyToZone(Zone* zone, int children_length); ZonePreparseData* CopyToZone(Zone* zone, int children_length);
void Reserve(size_t bytes);
void Add(uint8_t byte);
int length() const;
void WriteVarint32(uint32_t data); void WriteVarint32(uint32_t data);
void WriteUint8(uint8_t data); void WriteUint8(uint8_t data);
void WriteQuarter(uint8_t data); void WriteQuarter(uint8_t data);
...@@ -135,13 +144,15 @@ class PreparseDataBuilder : public ZoneObject, ...@@ -135,13 +144,15 @@ class PreparseDataBuilder : public ZoneObject,
void WriteUint32(uint32_t data); void WriteUint32(uint32_t data);
// For overwriting previously written data at position 0. // For overwriting previously written data at position 0.
void SaveCurrentSizeAtFirstUint32(); void SaveCurrentSizeAtFirstUint32();
int length() const;
#endif #endif
private: private:
union { union {
// Only used during construction (is_finalized_ == false). struct {
std::vector<uint8_t>* byte_data_; // Only used during construction (is_finalized_ == false).
std::vector<uint8_t>* byte_data_;
int index_;
};
// Once the data is finalized, it lives in a Zone, this implies // Once the data is finalized, it lives in a Zone, this implies
// is_finalized_ == true. // is_finalized_ == true.
Vector<uint8_t> zone_byte_data_; Vector<uint8_t> zone_byte_data_;
......
...@@ -804,6 +804,14 @@ TEST(ProducingAndConsumingByteData) { ...@@ -804,6 +804,14 @@ TEST(ProducingAndConsumingByteData) {
std::vector<uint8_t> buffer; std::vector<uint8_t> buffer;
i::PreparseDataBuilder::ByteData bytes; i::PreparseDataBuilder::ByteData bytes;
bytes.Start(&buffer); bytes.Start(&buffer);
bytes.Reserve(32);
bytes.Reserve(32);
CHECK_EQ(buffer.size(), 32);
const int kBufferSize = 64;
bytes.Reserve(kBufferSize);
CHECK_EQ(buffer.size(), kBufferSize);
// Write some data. // Write some data.
#ifdef DEBUG #ifdef DEBUG
bytes.WriteUint32(1983); // This will be overwritten. bytes.WriteUint32(1983); // This will be overwritten.
...@@ -818,7 +826,8 @@ TEST(ProducingAndConsumingByteData) { ...@@ -818,7 +826,8 @@ TEST(ProducingAndConsumingByteData) {
#ifdef DEBUG #ifdef DEBUG
bytes.SaveCurrentSizeAtFirstUint32(); bytes.SaveCurrentSizeAtFirstUint32();
int saved_size = 21; int saved_size = 21;
CHECK_EQ(buffer.size(), saved_size); CHECK_EQ(buffer.size(), kBufferSize);
CHECK_EQ(bytes.length(), saved_size);
#endif #endif
bytes.WriteUint8(100); bytes.WriteUint8(100);
// Write quarter bytes between uint8s and uint32s to verify they're stored // Write quarter bytes between uint8s and uint32s to verify they're stored
...@@ -845,11 +854,14 @@ TEST(ProducingAndConsumingByteData) { ...@@ -845,11 +854,14 @@ TEST(ProducingAndConsumingByteData) {
// End with a lonely quarter. // End with a lonely quarter.
bytes.WriteQuarter(2); bytes.WriteQuarter(2);
CHECK_EQ(buffer.size(), 64);
#ifdef DEBUG #ifdef DEBUG
CHECK_EQ(buffer.size(), 42); const int kDataSize = 42;
#else #else
CHECK_EQ(buffer.size(), 21); const int kDataSize = 21;
#endif #endif
CHECK_EQ(bytes.length(), kDataSize);
CHECK_EQ(buffer.size(), kBufferSize);
// Copy buffer for sanity checks later-on. // Copy buffer for sanity checks later-on.
std::vector<uint8_t> copied_buffer(buffer); std::vector<uint8_t> copied_buffer(buffer);
...@@ -858,7 +870,7 @@ TEST(ProducingAndConsumingByteData) { ...@@ -858,7 +870,7 @@ TEST(ProducingAndConsumingByteData) {
// serialization. // serialization.
bytes.Finalize(&zone); bytes.Finalize(&zone);
CHECK_EQ(buffer.size(), 0); CHECK_EQ(buffer.size(), 0);
CHECK_LT(0, copied_buffer.size()); CHECK_EQ(copied_buffer.size(), kBufferSize);
{ {
// Serialize as a ZoneConsumedPreparseData, and read back data. // Serialize as a ZoneConsumedPreparseData, and read back data.
...@@ -868,7 +880,9 @@ TEST(ProducingAndConsumingByteData) { ...@@ -868,7 +880,9 @@ TEST(ProducingAndConsumingByteData) {
i::ZoneConsumedPreparseData::ByteData::ReadingScope reading_scope( i::ZoneConsumedPreparseData::ByteData::ReadingScope reading_scope(
&bytes_for_reading, wrapper); &bytes_for_reading, wrapper);
for (int i = 0; i < static_cast<int>(copied_buffer.size()); i++) { CHECK_EQ(wrapper.data_length(), kDataSize);
for (int i = 0; i < kDataSize; i++) {
CHECK_EQ(copied_buffer.at(i), wrapper.get(i)); CHECK_EQ(copied_buffer.at(i), wrapper.get(i));
} }
...@@ -910,13 +924,13 @@ TEST(ProducingAndConsumingByteData) { ...@@ -910,13 +924,13 @@ TEST(ProducingAndConsumingByteData) {
{ {
// Serialize as an OnHeapConsumedPreparseData, and read back data. // Serialize as an OnHeapConsumedPreparseData, and read back data.
i::Handle<i::PreparseData> data_on_heap = bytes.CopyToHeap(isolate, 0); i::Handle<i::PreparseData> data_on_heap = bytes.CopyToHeap(isolate, 0);
CHECK_EQ(copied_buffer.size(), data_on_heap->data_length()); CHECK_EQ(data_on_heap->data_length(), kDataSize);
CHECK_EQ(data_on_heap->children_length(), 0); CHECK_EQ(data_on_heap->children_length(), 0);
i::OnHeapConsumedPreparseData::ByteData bytes_for_reading; i::OnHeapConsumedPreparseData::ByteData bytes_for_reading;
i::OnHeapConsumedPreparseData::ByteData::ReadingScope reading_scope( i::OnHeapConsumedPreparseData::ByteData::ReadingScope reading_scope(
&bytes_for_reading, *data_on_heap); &bytes_for_reading, *data_on_heap);
for (int i = 0; i < static_cast<int>(copied_buffer.size()); i++) { for (int i = 0; i < kDataSize; i++) {
CHECK_EQ(copied_buffer[i], data_on_heap->get(i)); CHECK_EQ(copied_buffer[i], data_on_heap->get(i));
} }
......
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