Commit 3d02ccf7 authored by Leszek Swirski's avatar Leszek Swirski Committed by V8 LUCI CQ

[compiler] Change liveness to use a flat array

Bytecode liveness needs a mapping from offset to liveness. This was
previously a hashmap with a very weak hash (the identity function) and
both inserts and lookups showed up as a non-trivial costs during
compilation.

Now, replace the hashmap with a simple flat array of liveness, indexed
by offset, pre-sized to the size of the bytecode. This will have a lot
of empty entries, but will have much better runtime performance and
probably ends up not much less memory efficient as a hashmap if the
hashmap has to resize inside the Zone, and is likely negligible compared
to the other compilation memory overheads.

Change-Id: Id21375bfcbf0d53b5ed9c41f30cdf7fde66ee699
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3455802Reviewed-by: 's avatarTobias Tebbi <tebbi@chromium.org>
Commit-Queue: Leszek Swirski <leszeks@chromium.org>
Cr-Commit-Position: refs/heads/main@{#79049}
parent 18de64a1
......@@ -92,7 +92,6 @@ BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
end_to_header_(zone),
header_to_info_(zone),
osr_entry_point_(-1) {
if (analyze_liveness) liveness_map_.emplace(bytecode_array->length(), zone);
Analyze();
}
......@@ -394,6 +393,12 @@ void BytecodeAnalysis::Analyze() {
DCHECK_EQ(osr_loop_end_offset < 0, osr_bailout_id_.IsNone());
interpreter::BytecodeArrayRandomIterator iterator(bytecode_array(), zone());
bytecode_count_ = iterator.size();
if (analyze_liveness_) {
liveness_map_.emplace(bytecode_array()->length(), zone());
}
for (iterator.GoToEnd(); iterator.IsValid(); --iterator) {
Bytecode bytecode = iterator.current_bytecode();
int current_offset = iterator.current_offset();
......
......@@ -133,6 +133,10 @@ class V8_EXPORT_PRIVATE BytecodeAnalysis : public ZoneObject {
// Return whether liveness analysis was performed (for verification purposes).
bool liveness_analyzed() const { return analyze_liveness_; }
// Return the number of bytecodes (i.e. the number of bytecode operations, as
// opposed to the number of bytes in the bytecode).
int bytecode_count() const { return bytecode_count_; }
private:
struct LoopStackEntry {
int header_offset;
......@@ -176,6 +180,7 @@ class V8_EXPORT_PRIVATE BytecodeAnalysis : public ZoneObject {
ZoneMap<int, LoopInfo> header_to_info_;
int osr_entry_point_;
base::Optional<BytecodeLivenessMap> liveness_map_;
int bytecode_count_;
};
} // namespace compiler
......
......@@ -8,25 +8,6 @@ namespace v8 {
namespace internal {
namespace compiler {
BytecodeLivenessMap::BytecodeLivenessMap(int bytecode_size, Zone* zone)
: liveness_map_(base::bits::RoundUpToPowerOfTwo32(bytecode_size / 4 + 1),
base::KeyEqualityMatcher<int>(),
ZoneAllocationPolicy(zone)) {}
uint32_t OffsetHash(int offset) { return offset; }
BytecodeLiveness& BytecodeLivenessMap::InsertNewLiveness(int offset) {
return liveness_map_.LookupOrInsert(offset, OffsetHash(offset))->value;
}
BytecodeLiveness& BytecodeLivenessMap::GetLiveness(int offset) {
return liveness_map_.Lookup(offset, OffsetHash(offset))->value;
}
const BytecodeLiveness& BytecodeLivenessMap::GetLiveness(int offset) const {
return liveness_map_.Lookup(offset, OffsetHash(offset))->value;
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -5,7 +5,6 @@
#ifndef V8_COMPILER_BYTECODE_LIVENESS_MAP_H_
#define V8_COMPILER_BYTECODE_LIVENESS_MAP_H_
#include "src/base/hashmap.h"
#include "src/utils/bit-vector.h"
#include "src/zone/zone.h"
......@@ -85,12 +84,38 @@ struct BytecodeLiveness {
class V8_EXPORT_PRIVATE BytecodeLivenessMap {
public:
BytecodeLivenessMap(int size, Zone* zone);
BytecodeLivenessMap(int bytecode_size, Zone* zone)
: liveness_(zone->NewArray<BytecodeLiveness>(bytecode_size))
#ifdef DEBUG
,
size_(bytecode_size)
#endif
{
}
BytecodeLiveness& InsertNewLiveness(int offset);
BytecodeLiveness& InsertNewLiveness(int offset) {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, size_);
#ifdef DEBUG
// Null out the in/out liveness, so that later DCHECKs know whether these
// have been correctly initialised or not. That code does initialise them
// unconditionally though, so we can skip the nulling out in release.
liveness_[offset].in = nullptr;
liveness_[offset].out = nullptr;
#endif
return liveness_[offset];
}
BytecodeLiveness& GetLiveness(int offset);
const BytecodeLiveness& GetLiveness(int offset) const;
BytecodeLiveness& GetLiveness(int offset) {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, size_);
return liveness_[offset];
}
const BytecodeLiveness& GetLiveness(int offset) const {
DCHECK_GE(offset, 0);
DCHECK_LT(offset, size_);
return liveness_[offset];
}
BytecodeLivenessState* GetInLiveness(int offset) {
return GetLiveness(offset).in;
......@@ -107,9 +132,10 @@ class V8_EXPORT_PRIVATE BytecodeLivenessMap {
}
private:
base::TemplateHashMapImpl<int, BytecodeLiveness,
base::KeyEqualityMatcher<int>, ZoneAllocationPolicy>
liveness_map_;
BytecodeLiveness* liveness_;
#ifdef DEBUG
size_t size_;
#endif
};
} // namespace compiler
......
......@@ -49,7 +49,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayRandomIterator final
int current_index() const { return current_index_; }
size_t size() const { return offsets_.size(); }
int size() const { return static_cast<int>(offsets_.size()); }
void GoToIndex(int index) {
current_index_ = index;
......@@ -60,8 +60,7 @@ class V8_EXPORT_PRIVATE BytecodeArrayRandomIterator final
UpdateOffsetFromIndex();
}
void GoToEnd() {
DCHECK_LT(offsets_.size() - 1, static_cast<size_t>(INT_MAX));
current_index_ = static_cast<int>(offsets_.size() - 1);
current_index_ = size() - 1;
UpdateOffsetFromIndex();
}
......
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