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