Reland "[parser] Inline byte scope data into PreparseData object"

This is a reland of e2d44ede95

Original change's description:
> [parser] Inline byte scope data into PreparseData object
> 
> Each PreparseData object had at least one pointer to a PodArray for its
> serialized scope data. These objects usually have only tens of bytes of
> payload. By inlining the byte data we save 3 words per PreparseData object.
> This optimization saves 140KB of data on cnn.com.
> 
> 
> - Store data_length and inner_length as int32 saving a words on 64bit
> - Inline store byte data into PreparseData
> - OnHeapConsumedPreparseData directly uses the PreparseData object
> - get_inner, set_inner no longer allow Null sentinels
> 
> Change-Id: I1f62154d05ea2f98a6574efa738b32a8a84319d5
> Reviewed-on: https://chromium-review.googlesource.com/c/1406673
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
> Commit-Queue: Camillo Bruni <cbruni@chromium.org>
> Cr-Commit-Position: refs/heads/master@{#58751}

Change-Id: I1f0a22c641d0d67f435b01c82daf8da7f144bff4
Reviewed-on: https://chromium-review.googlesource.com/c/1407066
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Reviewed-by: Ulan Degenbaev <ulan@chromium.org>
Commit-Queue: Camillo Bruni <cbruni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#58785}
This commit is contained in:
Camillo Bruni 2019-01-14 14:34:42 +01:00 committed by Commit Bot
parent c8567109f5
commit a6f4462987
15 changed files with 170 additions and 145 deletions

View File

@ -111,8 +111,6 @@ const unsigned kRegCodeMask = 0x1f;
const unsigned kShiftAmountWRegMask = 0x1f;
const unsigned kShiftAmountXRegMask = 0x3f;
// Standard machine types defined by AAPCS64.
const unsigned kByteSize = 8;
const unsigned kByteSizeInBytes = kByteSize >> 3;
const unsigned kHalfWordSize = 16;
const unsigned kHalfWordSizeLog2 = 4;
const unsigned kHalfWordSizeInBytes = kHalfWordSize >> 3;

View File

@ -119,6 +119,7 @@ constexpr uint32_t kMaxUInt32 = 0xFFFFFFFFu;
constexpr int kMinUInt32 = 0;
constexpr int kUInt8Size = sizeof(uint8_t);
constexpr int kByteSize = sizeof(byte);
constexpr int kCharSize = sizeof(char);
constexpr int kShortSize = sizeof(short); // NOLINT
constexpr int kUInt16Size = sizeof(uint16_t);

View File

@ -2638,15 +2638,15 @@ Handle<ModuleInfo> Factory::NewModuleInfo() {
ModuleInfo::kLength, TENURED);
}
Handle<PreparseData> Factory::NewPreparseData(int length) {
int size = PreparseData::SizeFor(length);
Handle<PreparseData> Factory::NewPreparseData(int data_length,
int children_length) {
int size = PreparseData::SizeFor(data_length, children_length);
Handle<PreparseData> result(PreparseData::cast(AllocateRawWithImmortalMap(
size, TENURED, *preparse_data_map())),
isolate());
result->set_scope_data(PodArray<uint8_t>::cast(*empty_byte_array()));
result->set_length(length);
MemsetTagged(result->child_data_start(), *null_value(), length);
result->set_data_length(data_length);
result->set_children_length(children_length);
MemsetTagged(result->inner_data_start(), *null_value(), children_length);
result->clear_padding();
return result;
}

View File

@ -750,7 +750,7 @@ class V8_EXPORT_PRIVATE Factory {
Handle<ModuleInfo> NewModuleInfo();
Handle<PreparseData> NewPreparseData(int length);
Handle<PreparseData> NewPreparseData(int data_length, int children_length);
Handle<UncompiledDataWithoutPreparseData>
NewUncompiledDataWithoutPreparseData(Handle<String> inferred_name,

View File

@ -401,7 +401,6 @@ class ObjectStatsCollectorImpl {
void RecordVirtualExternalStringDetails(ExternalString script);
void RecordVirtualSharedFunctionInfoDetails(SharedFunctionInfo info);
void RecordVirtualJSFunctionDetails(JSFunction function);
void RecordVirtualPreparseDataDetails(PreparseData data);
void RecordVirtualArrayBoilerplateDescription(
ArrayBoilerplateDescription description);
@ -650,18 +649,6 @@ void ObjectStatsCollectorImpl::RecordVirtualFeedbackVectorDetails(
CHECK_EQ(calculated_size, vector->Size());
}
void ObjectStatsCollectorImpl::RecordVirtualPreparseDataDetails(
PreparseData data) {
if (virtual_objects_.find(data) != virtual_objects_.end()) return;
// Manually insert the PreparseData since we're combining the size with it's
// byte_data size.
virtual_objects_.insert(data);
virtual_objects_.insert(data->scope_data());
size_t size = data->Size() + data->scope_data()->Size();
DCHECK_LE(0, data->scope_data()->length());
stats_->RecordObjectStats(PREPARSE_DATA_TYPE, size);
}
void ObjectStatsCollectorImpl::RecordVirtualFixedArrayDetails(
FixedArray array) {
if (IsCowArray(array)) {
@ -706,8 +693,6 @@ void ObjectStatsCollectorImpl::CollectStatistics(
} else if (obj->IsArrayBoilerplateDescription()) {
RecordVirtualArrayBoilerplateDescription(
ArrayBoilerplateDescription::cast(obj));
} else if (obj->IsPreparseData()) {
RecordVirtualPreparseDataDetails(PreparseData::cast(obj));
} else if (obj->IsFixedArrayExact()) {
// Has to go last as it triggers too eagerly.
RecordVirtualFixedArrayDetails(FixedArray::cast(obj));

View File

@ -505,18 +505,21 @@ class FeedbackVector::BodyDescriptor final : public BodyDescriptorBase {
class PreparseData::BodyDescriptor final : public BodyDescriptorBase {
public:
static bool IsValidSlot(Map map, HeapObject obj, int offset) {
return offset == kScopeDataOffset || offset >= kChildDataStartOffset;
return offset >= PreparseData::cast(obj)->inner_start_offset();
}
template <typename ObjectVisitor>
static inline void IterateBody(Map map, HeapObject obj, int object_size,
ObjectVisitor* v) {
IteratePointer(obj, kScopeDataOffset, v);
IteratePointers(obj, kChildDataStartOffset, object_size, v);
PreparseData data = PreparseData::cast(obj);
int start_offset = data->inner_start_offset();
int end_offset = start_offset + data->children_length() * kTaggedSize;
IteratePointers(obj, start_offset, end_offset, v);
}
static inline int SizeOf(Map map, HeapObject obj) {
return PreparseData::SizeFor(PreparseData::cast(obj)->length());
PreparseData data = PreparseData::cast(obj);
return PreparseData::SizeFor(data->data_length(), data->children_length());
}
};

View File

@ -2033,12 +2033,12 @@ void StackFrameInfo::StackFrameInfoVerify(Isolate* isolate) {
void PreparseData::PreparseDataVerify(Isolate* isolate) {
CHECK(IsPreparseData());
CHECK(scope_data()->IsByteArray());
CHECK_GE(length(), 0);
CHECK_LE(0, data_length());
CHECK_LE(0, children_length());
for (int i = 0; i < length(); ++i) {
Object child = child_data(i);
CHECK(child->IsPreparseData() || child->IsNull());
for (int i = 0; i < children_length(); ++i) {
Object child = get_child_raw(i);
CHECK(child->IsNull() || child->IsPreparseData());
VerifyPointer(isolate, child);
}
}

View File

@ -1084,7 +1084,8 @@ int HeapObject::SizeFromMap(Map map) const {
return BigInt::SizeFor(BigInt::unchecked_cast(*this)->length());
}
if (instance_type == PREPARSE_DATA_TYPE) {
return PreparseData::SizeFor(PreparseData::unchecked_cast(*this)->length());
PreparseData data = PreparseData::unchecked_cast(*this);
return PreparseData::SizeFor(data->data_length(), data->children_length());
}
if (instance_type == CODE_TYPE) {
return Code::unchecked_cast(*this)->CodeSize();

View File

@ -2252,10 +2252,10 @@ void LayoutDescriptor::Print(std::ostream& os) { // NOLINT
void PreparseData::PreparseDataPrint(std::ostream& os) { // NOLINT
PrintHeader(os, "PreparseData");
os << "\n - scope_data: " << Brief(scope_data());
os << "\n - length: " << length();
for (int i = 0; i < length(); ++i) {
os << "\n - [" << i << "]: " << Brief(child_data(i));
os << "\n - data_length: " << data_length();
os << "\n - children_length: " << children_length();
for (int i = 0; i < children_length(); ++i) {
os << "\n - [" << i << "]: " << Brief(get_child(i));
}
os << "\n";
}

View File

@ -3600,7 +3600,8 @@ void HeapObject::HeapObjectShortPrint(std::ostream& os) { // NOLINT
case PREPARSE_DATA_TYPE: {
PreparseData data = PreparseData::cast(*this);
os << "<PreparseData[" << data->length() << "]>";
os << "<PreparseData[data=" << data->data_length()
<< " children=" << data->children_length() << "]>";
break;
}

View File

@ -24,35 +24,64 @@ namespace internal {
OBJECT_CONSTRUCTORS_IMPL(PreparseData, HeapObject)
CAST_ACCESSOR(PreparseData)
ACCESSORS(PreparseData, scope_data, PodArray<uint8_t>, kScopeDataOffset)
INT_ACCESSORS(PreparseData, length, kLengthOffset)
INT_ACCESSORS(PreparseData, data_length, kDataLengthOffset)
INT_ACCESSORS(PreparseData, children_length, kInnerLengthOffset)
Object PreparseData::child_data(int index) const {
DCHECK_GE(index, 0);
DCHECK_LT(index, this->length());
int offset = kChildDataStartOffset + index * kTaggedSize;
return RELAXED_READ_FIELD(*this, offset);
int PreparseData::inner_start_offset() const {
return InnerOffset(data_length());
}
void PreparseData::set_child_data(int index, Object value,
WriteBarrierMode mode) {
DCHECK_GE(index, 0);
DCHECK_LT(index, this->length());
int offset = kChildDataStartOffset + index * kTaggedSize;
RELAXED_WRITE_FIELD(*this, offset, value);
CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
}
ObjectSlot PreparseData::child_data_start() const {
return RawField(kChildDataStartOffset);
ObjectSlot PreparseData::inner_data_start() const {
return RawField(inner_start_offset());
}
void PreparseData::clear_padding() {
if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
FIELD_SIZE(kOptionalPaddingOffset));
}
int data_end_offset = kDataStartOffset + data_length();
int padding_size = inner_start_offset() - data_end_offset;
DCHECK_LE(0, padding_size);
if (padding_size == 0) return;
memset(reinterpret_cast<void*>(address() + data_end_offset), 0, padding_size);
}
byte PreparseData::get(int index) const {
DCHECK_LE(0, index);
DCHECK_LT(index, data_length());
int offset = kDataStartOffset + index * kByteSize;
return READ_BYTE_FIELD(*this, offset);
}
void PreparseData::set(int index, byte value) {
DCHECK_LE(0, index);
DCHECK_LT(index, data_length());
int offset = kDataStartOffset + index * kByteSize;
WRITE_BYTE_FIELD(*this, offset, value);
}
void PreparseData::copy_in(int index, const byte* buffer, int length) {
DCHECK(index >= 0 && length >= 0 && length <= kMaxInt - index &&
index + length <= this->data_length());
Address dst_addr = FIELD_ADDR(this, kDataStartOffset + index * kByteSize);
memcpy(reinterpret_cast<void*>(dst_addr), buffer, length);
}
PreparseData PreparseData::get_child(int index) const {
return PreparseData::cast(get_child_raw(index));
}
Object PreparseData::get_child_raw(int index) const {
DCHECK_LE(0, index);
DCHECK_LT(index, this->children_length());
int offset = inner_start_offset() + index * kTaggedSize;
return RELAXED_READ_FIELD(*this, offset);
}
void PreparseData::set_child(int index, PreparseData value,
WriteBarrierMode mode) {
DCHECK_LE(0, index);
DCHECK_LT(index, this->children_length());
int offset = inner_start_offset() + index * kTaggedSize;
RELAXED_WRITE_FIELD(*this, offset, value);
CONDITIONAL_WRITE_BARRIER(*this, offset, value, mode);
}
OBJECT_CONSTRUCTORS_IMPL(UncompiledData, HeapObject)
@ -65,11 +94,10 @@ INT32_ACCESSORS(UncompiledData, end_position, kEndPositionOffset)
INT32_ACCESSORS(UncompiledData, function_literal_id, kFunctionLiteralIdOffset)
void UncompiledData::clear_padding() {
if (FIELD_SIZE(kOptionalPaddingOffset) != 0) {
if (FIELD_SIZE(kOptionalPaddingOffset) == 0) return;
DCHECK_EQ(4, FIELD_SIZE(kOptionalPaddingOffset));
memset(reinterpret_cast<void*>(address() + kOptionalPaddingOffset), 0,
FIELD_SIZE(kOptionalPaddingOffset));
}
}
CAST_ACCESSOR(UncompiledDataWithoutPreparseData)

View File

@ -27,17 +27,38 @@ class WasmExportedFunctionData;
// Data collected by the pre-parser storing information about scopes and inner
// functions.
//
// PreparseData Layout:
// +-------------------------------+
// | data_length | children_length |
// +-------------------------------+
// | Scope Byte Data ... |
// | ... |
// +-------------------------------+
// | [Padding] |
// +-------------------------------+
// | Inner PreparseData 1 |
// +-------------------------------+
// | ... |
// +-------------------------------+
// | Inner PreparseData N |
// +-------------------------------+
class PreparseData : public HeapObject {
public:
DECL_ACCESSORS(scope_data, PodArray<uint8_t>)
DECL_INT_ACCESSORS(length)
DECL_INT_ACCESSORS(data_length)
DECL_INT_ACCESSORS(children_length)
inline Object child_data(int index) const;
inline void set_child_data(int index, Object value,
inline int inner_start_offset() const;
inline ObjectSlot inner_data_start() const;
inline byte get(int index) const;
inline void set(int index, byte value);
inline void copy_in(int index, const byte* buffer, int length);
inline PreparseData get_child(int index) const;
inline void set_child(int index, PreparseData value,
WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
inline ObjectSlot child_data_start() const;
// Clear uninitialized padding space.
inline void clear_padding();
@ -47,22 +68,29 @@ class PreparseData : public HeapObject {
// Layout description.
#define PREPARSE_DATA_FIELDS(V) \
V(kScopeDataOffset, kTaggedSize) \
V(kLengthOffset, kIntSize) \
V(kOptionalPaddingOffset, POINTER_SIZE_PADDING(kOptionalPaddingOffset)) \
V(kDataLengthOffset, kInt32Size) \
V(kInnerLengthOffset, kInt32Size) \
/* Header size. */ \
V(kChildDataStartOffset, 0)
V(kDataStartOffset, 0) \
V(kHeaderSize, 0)
DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, PREPARSE_DATA_FIELDS)
#undef PREPARSE_DATA_FIELDS
class BodyDescriptor;
static constexpr int SizeFor(int length) {
return kChildDataStartOffset + length * kTaggedSize;
static int InnerOffset(int data_length) {
return RoundUp(kDataStartOffset + data_length * kByteSize, kTaggedSize);
}
static int SizeFor(int data_length, int children_length) {
return InnerOffset(data_length) + children_length * kTaggedSize;
}
OBJECT_CONSTRUCTORS(PreparseData, HeapObject);
private:
inline Object get_child_raw(int index) const;
};
// Abstract class representing extra data for an uncompiled function, which is
@ -84,7 +112,6 @@ class UncompiledData : public HeapObject {
[](HeapObject object, ObjectSlot slot, HeapObject target) {});
// Layout description.
#define UNCOMPILED_DATA_FIELDS(V) \
V(kStartOfPointerFieldsOffset, 0) \
V(kInferredNameOffset, kTaggedSize) \

View File

@ -47,7 +47,7 @@ class PreparseDataBuilder::ByteData : public ZoneObject,
void OverwriteFirstUint32(uint32_t data);
#endif
Handle<PodArray<uint8_t>> Serialize(Isolate* isolate);
void StoreInto(PreparseData data);
size_t size() const { return backing_store_.size(); }
@ -60,6 +60,21 @@ class PreparseDataBuilder::ByteData : public ZoneObject,
ZoneChunkList<uint8_t> backing_store_;
};
// Wraps a ZoneVector<uint8_t> to have with functions named the same as
// PodArray<uint8_t>.
class ZoneVectorWrapper {
public:
ZoneVectorWrapper() = default;
explicit ZoneVectorWrapper(ZoneVector<uint8_t>* data) : data_(data) {}
int data_length() const { return static_cast<int>(data_->size()); }
uint8_t get(int index) const { return data_->at(index); }
private:
ZoneVector<uint8_t>* data_ = nullptr;
};
template <class Data>
class BaseConsumedPreparseData : public ConsumedPreparseData {
public:
@ -93,19 +108,19 @@ class BaseConsumedPreparseData : public ConsumedPreparseData {
};
void SetPosition(int position) {
DCHECK_LE(position, data_.length());
DCHECK_LE(position, data_.data_length());
index_ = position;
}
size_t RemainingBytes() const {
DCHECK(has_data_);
DCHECK_LE(index_, data_.length());
return data_.length() - index_;
DCHECK_LE(index_, data_.data_length());
return data_.data_length() - index_;
}
bool HasRemainingBytes(size_t bytes) const {
DCHECK(has_data_);
return index_ <= data_.length() && bytes <= RemainingBytes();
return index_ <= data_.data_length() && bytes <= RemainingBytes();
}
int32_t ReadUint32() {
@ -188,33 +203,18 @@ class BaseConsumedPreparseData : public ConsumedPreparseData {
// Implementation of ConsumedPreparseData for on-heap data.
class OnHeapConsumedPreparseData final
: public BaseConsumedPreparseData<PodArray<uint8_t>> {
: public BaseConsumedPreparseData<PreparseData> {
public:
OnHeapConsumedPreparseData(Isolate* isolate, Handle<PreparseData> data);
PodArray<uint8_t> GetScopeData() final;
ProducedPreparseData* GetChildData(Zone* zone, int child_index) final;
PreparseData GetScopeData() final;
ProducedPreparseData* GetChildData(Zone* zone, int index) final;
private:
Isolate* isolate_;
Handle<PreparseData> data_;
};
// Wraps a ZoneVector<uint8_t> to have with functions named the same as
// PodArray<uint8_t>.
class ZoneVectorWrapper {
public:
ZoneVectorWrapper() = default;
explicit ZoneVectorWrapper(ZoneVector<uint8_t>* data) : data_(data) {}
int length() const { return static_cast<int>(data_->size()); }
uint8_t get(int index) const { return data_->at(index); }
private:
ZoneVector<uint8_t>* data_ = nullptr;
};
// A serialized PreparseData in zone memory (as apposed to being on-heap).
class ZonePreparseData : public ZoneObject {
public:

View File

@ -135,19 +135,12 @@ void PreparseDataBuilder::ByteData::WriteQuarter(uint8_t data) {
backing_store_.back() |= (data << shift_amount);
}
Handle<PodArray<uint8_t>> PreparseDataBuilder::ByteData::Serialize(
Isolate* isolate) {
Handle<PodArray<uint8_t>> array = PodArray<uint8_t>::New(
isolate, static_cast<int>(backing_store_.size()), TENURED);
void PreparseDataBuilder::ByteData::StoreInto(PreparseData data) {
DisallowHeapAllocation no_gc;
PodArray<uint8_t> raw_array = *array;
int i = 0;
for (uint8_t item : backing_store_) {
raw_array->set(i++, item);
data->set(i++, item);
}
return array;
}
PreparseDataBuilder::PreparseDataBuilder(Zone* zone,
@ -252,17 +245,15 @@ Handle<PreparseData> PreparseDataBuilder::Serialize(Isolate* isolate) {
DCHECK(!ThisOrParentBailedOut());
int child_data_length = static_cast<int>(data_for_inner_functions_.size());
Handle<PreparseData> data =
isolate->factory()->NewPreparseData(child_data_length);
Handle<PodArray<uint8_t>> scope_data_array = byte_data_->Serialize(isolate);
data->set_scope_data(*scope_data_array);
Handle<PreparseData> data = isolate->factory()->NewPreparseData(
static_cast<int>(byte_data_->size()), child_data_length);
byte_data_->StoreInto(*data);
int i = 0;
for (const auto& item : data_for_inner_functions_) {
DCHECK_NOT_NULL(item);
Handle<PreparseData> child_data = item->Serialize(isolate);
data->set_child_data(i++, *child_data);
data->set_child(i++, *child_data);
}
return data;
@ -588,25 +579,18 @@ void BaseConsumedPreparseData<Data>::VerifyDataStart() {
}
#endif
PodArray<uint8_t> OnHeapConsumedPreparseData::GetScopeData() {
return data_->scope_data();
}
PreparseData OnHeapConsumedPreparseData::GetScopeData() { return *data_; }
ProducedPreparseData* OnHeapConsumedPreparseData::GetChildData(
Zone* zone, int child_index) {
CHECK_GT(data_->length(), child_index);
Object child_data = data_->child_data(child_index);
if (!child_data->IsPreparseData()) return nullptr;
Handle<PreparseData> child_data_handle(PreparseData::cast(child_data),
isolate_);
ProducedPreparseData* OnHeapConsumedPreparseData::GetChildData(Zone* zone,
int index) {
DisallowHeapAllocation no_gc;
Handle<PreparseData> child_data_handle(data_->get_child(index), isolate_);
return ProducedPreparseData::For(child_data_handle, zone);
}
OnHeapConsumedPreparseData::OnHeapConsumedPreparseData(
Isolate* isolate, Handle<PreparseData> data)
: BaseConsumedPreparseData<PodArray<uint8_t>>(),
isolate_(isolate),
data_(data) {
: BaseConsumedPreparseData<PreparseData>(), isolate_(isolate), data_(data) {
DCHECK_NOT_NULL(isolate);
DCHECK(data->IsPreparseData());
#ifdef DEBUG
@ -621,22 +605,17 @@ ZonePreparseData::ZonePreparseData(Zone* zone,
children_(child_length, zone) {}
Handle<PreparseData> ZonePreparseData::Serialize(Isolate* isolate) {
int data_size = static_cast<int>(byte_data()->size());
int child_data_length = child_length();
Handle<PreparseData> result =
isolate->factory()->NewPreparseData(child_data_length);
Handle<PodArray<uint8_t>> scope_data_array = PodArray<uint8_t>::New(
isolate, static_cast<int>(byte_data()->size()), TENURED);
scope_data_array->copy_in(0, byte_data()->data(),
static_cast<int>(byte_data()->size()));
result->set_scope_data(*scope_data_array);
isolate->factory()->NewPreparseData(data_size, child_data_length);
result->copy_in(0, byte_data()->data(), data_size);
for (int i = 0; i < child_data_length; i++) {
ZonePreparseData* child = get_child(i);
if (child) {
DCHECK_NOT_NULL(child);
Handle<PreparseData> child_data = child->Serialize(isolate);
result->set_child_data(i, *child_data);
}
result->set_child(i, *child_data);
}
return result;
}

View File

@ -862,7 +862,9 @@ TEST(ProducingAndConsumingByteData) {
{
// Serialize as an OnHeapConsumedPreparseData, and read back data.
i::Handle<i::PodArray<uint8_t>> data_on_heap = bytes.Serialize(isolate);
i::Handle<i::PreparseData> data_on_heap =
isolate->factory()->NewPreparseData(static_cast<int>(bytes.size()), 0);
bytes.StoreInto(*data_on_heap);
i::OnHeapConsumedPreparseData::ByteData bytes_for_reading;
i::OnHeapConsumedPreparseData::ByteData::ReadingScope reading_scope(
&bytes_for_reading, *data_on_heap);