Commit 6544a1e4 authored by Ross McIlroy's avatar Ross McIlroy Committed by Commit Bot

[TurboFan] Avoid serializing BytecodeAnalysis

The SerializerForBackgroundCompilation needs bytecode analysis for loop
target analysis, but doesn't require the much more expensive liveness
analysis. In order to move more work off the main thread, perform fast
bytecode analysis without liveness analysis in
SerializerForBackgroundCompilation, and then move the full bytecode
analysis to the background thread in BytecodeGraphBuilder.

BUG=v8:7790,v8:9684

Change-Id: I63ef80ecab8ad0c56953c72be31abc8f5a74b9c1
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2593329Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Commit-Queue: Ross McIlroy <rmcilroy@chromium.org>
Cr-Commit-Position: refs/heads/master@{#71767}
parent 8eb97f5a
......@@ -90,8 +90,8 @@ BytecodeAnalysis::BytecodeAnalysis(Handle<BytecodeArray> bytecode_array,
resume_jump_targets_(zone),
end_to_header_(zone),
header_to_info_(zone),
osr_entry_point_(-1),
liveness_map_(bytecode_array->length(), zone) {
osr_entry_point_(-1) {
if (analyze_liveness) liveness_map_.emplace(bytecode_array->length(), zone);
Analyze();
}
......@@ -433,10 +433,10 @@ void BytecodeAnalysis::Analyze() {
}
if (analyze_liveness_) {
BytecodeLiveness const& liveness = liveness_map_.InitializeLiveness(
BytecodeLiveness const& liveness = liveness_map().InitializeLiveness(
current_offset, bytecode_array()->register_count(), zone());
UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness, iterator,
bytecode_array(), liveness_map_);
bytecode_array(), liveness_map());
}
}
......@@ -481,8 +481,8 @@ void BytecodeAnalysis::Analyze() {
int end_offset = iterator.current_offset();
BytecodeLiveness& header_liveness =
liveness_map_.GetLiveness(header_offset);
BytecodeLiveness& end_liveness = liveness_map_.GetLiveness(end_offset);
liveness_map().GetLiveness(header_offset);
BytecodeLiveness& end_liveness = liveness_map().GetLiveness(end_offset);
if (!end_liveness.out->UnionIsChanged(*header_liveness.in)) {
// Only update the loop body if the loop end liveness changed.
......@@ -497,15 +497,15 @@ void BytecodeAnalysis::Analyze() {
Bytecode bytecode = iterator.current_bytecode();
int current_offset = iterator.current_offset();
BytecodeLiveness const& liveness =
liveness_map_.GetLiveness(current_offset);
liveness_map().GetLiveness(current_offset);
UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness, iterator,
bytecode_array(), liveness_map_);
bytecode_array(), liveness_map());
}
// Now we are at the loop header. Since the in-liveness of the header
// can't change, we need only to update the out-liveness.
UpdateOutLiveness(iterator.current_bytecode(), header_liveness.out,
next_bytecode_in_liveness, iterator, bytecode_array(),
liveness_map_);
liveness_map());
}
// Process the generator switch statement separately, once the loops are done.
......@@ -518,12 +518,12 @@ void BytecodeAnalysis::Analyze() {
int current_offset = iterator.current_offset();
BytecodeLiveness& switch_liveness =
liveness_map_.GetLiveness(current_offset);
liveness_map().GetLiveness(current_offset);
bool any_changed = false;
for (const auto& entry : iterator.GetJumpTableTargetOffsets()) {
if (switch_liveness.out->UnionIsChanged(
*liveness_map_.GetInLiveness(entry.target_offset))) {
*liveness_map().GetInLiveness(entry.target_offset))) {
any_changed = true;
}
}
......@@ -539,13 +539,13 @@ void BytecodeAnalysis::Analyze() {
Bytecode bytecode = iterator.current_bytecode();
int current_offset = iterator.current_offset();
BytecodeLiveness const& liveness =
liveness_map_.GetLiveness(current_offset);
liveness_map().GetLiveness(current_offset);
// There shouldn't be any more loops.
DCHECK_NE(bytecode, Bytecode::kJumpLoop);
UpdateLiveness(bytecode, liveness, &next_bytecode_in_liveness, iterator,
bytecode_array(), liveness_map_);
bytecode_array(), liveness_map());
}
}
}
......@@ -624,14 +624,14 @@ const BytecodeLivenessState* BytecodeAnalysis::GetInLivenessFor(
int offset) const {
if (!analyze_liveness_) return nullptr;
return liveness_map_.GetInLiveness(offset);
return liveness_map().GetInLiveness(offset);
}
const BytecodeLivenessState* BytecodeAnalysis::GetOutLivenessFor(
int offset) const {
if (!analyze_liveness_) return nullptr;
return liveness_map_.GetOutLiveness(offset);
return liveness_map().GetOutLiveness(offset);
}
std::ostream& BytecodeAnalysis::PrintLivenessTo(std::ostream& os) const {
......@@ -826,16 +826,16 @@ bool BytecodeAnalysis::LivenessIsValid() {
int current_offset = iterator.current_offset();
BytecodeLiveness& liveness = liveness_map_.GetLiveness(current_offset);
BytecodeLiveness& liveness = liveness_map().GetLiveness(current_offset);
previous_liveness.CopyFrom(*liveness.out);
UpdateOutLiveness(bytecode, liveness.out, next_bytecode_in_liveness,
iterator, bytecode_array(), liveness_map_);
iterator, bytecode_array(), liveness_map());
// UpdateOutLiveness skips kJumpLoop, so we update it manually.
if (bytecode == Bytecode::kJumpLoop) {
int target_offset = iterator.GetJumpTargetOffset();
liveness.out->Union(*liveness_map_.GetInLiveness(target_offset));
liveness.out->Union(*liveness_map().GetInLiveness(target_offset));
}
if (!liveness.out->Equals(previous_liveness)) {
......@@ -885,7 +885,7 @@ bool BytecodeAnalysis::LivenessIsValid() {
}
// The accumulator must be dead at the start of the target of the jump.
if (liveness_map_.GetLiveness(jump_target).in->AccumulatorIsLive()) {
if (liveness_map().GetLiveness(jump_target).in->AccumulatorIsLive()) {
invalid_offset = jump_target;
which_invalid = 0;
break;
......
......@@ -154,6 +154,14 @@ class V8_EXPORT_PRIVATE BytecodeAnalysis : public ZoneObject {
Zone* zone() const { return zone_; }
Handle<BytecodeArray> bytecode_array() const { return bytecode_array_; }
BytecodeLivenessMap& liveness_map() {
DCHECK(analyze_liveness_);
return *liveness_map_;
}
const BytecodeLivenessMap& liveness_map() const {
DCHECK(analyze_liveness_);
return *liveness_map_;
}
std::ostream& PrintLivenessTo(std::ostream& os) const;
......@@ -167,7 +175,7 @@ class V8_EXPORT_PRIVATE BytecodeAnalysis : public ZoneObject {
ZoneMap<int, int> end_to_header_;
ZoneMap<int, LoopInfo> header_to_info_;
int osr_entry_point_;
BytecodeLivenessMap liveness_map_;
base::Optional<BytecodeLivenessMap> liveness_map_;
};
} // namespace compiler
......
......@@ -430,7 +430,7 @@ class BytecodeGraphBuilder {
const FrameStateFunctionInfo* const frame_state_function_info_;
std::unique_ptr<SourcePositionTableIterator> source_position_iterator_;
interpreter::BytecodeArrayIterator bytecode_iterator_;
BytecodeAnalysis const& bytecode_analysis_;
BytecodeAnalysis const bytecode_analysis_;
Environment* environment_;
bool const osr_;
int currently_peeled_loop_offset_;
......@@ -1012,12 +1012,9 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
bytecode_array().SourcePositionTable())),
bytecode_iterator_(
std::make_unique<OffHeapBytecodeArray>(bytecode_array())),
bytecode_analysis_(broker_->GetBytecodeAnalysis(
bytecode_array().object(), osr_offset,
flags & BytecodeGraphBuilderFlag::kAnalyzeEnvironmentLiveness,
broker->is_concurrent_inlining()
? SerializationPolicy::kAssumeSerialized
: SerializationPolicy::kSerializeIfNeeded)),
bytecode_analysis_(
bytecode_array().object(), local_zone, osr_offset,
flags & BytecodeGraphBuilderFlag::kAnalyzeEnvironmentLiveness),
environment_(nullptr),
osr_(!osr_offset.IsNone()),
currently_peeled_loop_offset_(-1),
......
......@@ -17,7 +17,6 @@
#include "src/codegen/code-factory.h"
#include "src/codegen/optimized-compilation-info.h"
#include "src/compiler/access-info.h"
#include "src/compiler/bytecode-analysis.h"
#include "src/compiler/graph-reducer.h"
#include "src/compiler/per-isolate-compiler-cache.h"
#include "src/execution/protectors-inl.h"
......@@ -2373,7 +2372,6 @@ JSHeapBroker::JSHeapBroker(Isolate* isolate, Zone* broker_zone,
is_concurrent_inlining_(is_concurrent_inlining),
code_kind_(code_kind),
feedback_(zone()),
bytecode_analyses_(zone()),
property_access_infos_(zone()),
minimorphic_property_access_infos_(zone()),
typed_array_string_tags_(zone()),
......@@ -5072,36 +5070,6 @@ TemplateObjectFeedback const& ProcessedFeedback::AsTemplateObject() const {
return *static_cast<TemplateObjectFeedback const*>(this);
}
BytecodeAnalysis const& JSHeapBroker::GetBytecodeAnalysis(
Handle<BytecodeArray> bytecode_array, BailoutId osr_bailout_id,
bool analyze_liveness, SerializationPolicy policy) {
ObjectData* bytecode_array_data = GetOrCreateData(bytecode_array);
CHECK_NOT_NULL(bytecode_array_data);
auto it = bytecode_analyses_.find(bytecode_array_data);
if (it != bytecode_analyses_.end()) {
// Bytecode analysis can be run for OSR or for non-OSR. In the rare case
// where we optimize for OSR and consider the top-level function itself for
// inlining (because of recursion), we need both the OSR and the non-OSR
// analysis. Fortunately, the only difference between the two lies in
// whether the OSR entry offset gets computed (from the OSR bailout id).
// Hence it's okay to reuse the OSR-version when asked for the non-OSR
// version, such that we need to store at most one analysis result per
// bytecode array.
CHECK_IMPLIES(osr_bailout_id != it->second->osr_bailout_id(),
osr_bailout_id.IsNone());
CHECK_EQ(analyze_liveness, it->second->liveness_analyzed());
return *it->second;
}
CHECK_EQ(policy, SerializationPolicy::kSerializeIfNeeded);
BytecodeAnalysis* analysis = zone()->New<BytecodeAnalysis>(
bytecode_array, zone(), osr_bailout_id, analyze_liveness);
DCHECK_EQ(analysis->osr_bailout_id(), osr_bailout_id);
bytecode_analyses_[bytecode_array_data] = analysis;
return *analysis;
}
bool JSHeapBroker::StackHasOverflowed() const {
DCHECK_IMPLIES(local_isolate_ == nullptr,
ThreadId::Current() == isolate_->thread_id());
......
......@@ -33,7 +33,6 @@ namespace v8 {
namespace internal {
namespace compiler {
class BytecodeAnalysis;
class ObjectRef;
std::ostream& operator<<(std::ostream& os, const ObjectRef& ref);
......@@ -167,10 +166,6 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
ElementAccessFeedback const& ProcessFeedbackMapsForElementAccess(
MapHandles const& maps, KeyedAccessMode const& keyed_mode,
FeedbackSlotKind slot_kind);
BytecodeAnalysis const& GetBytecodeAnalysis(
Handle<BytecodeArray> bytecode_array, BailoutId osr_offset,
bool analyze_liveness,
SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
// Binary, comparison and for-in hints can be fully expressed via
// an enum. Insufficient feedback is signaled by <Hint enum>::kNone.
......@@ -383,7 +378,6 @@ class V8_EXPORT_PRIVATE JSHeapBroker {
ZoneUnorderedMap<FeedbackSource, ProcessedFeedback const*,
FeedbackSource::Hash, FeedbackSource::Equal>
feedback_;
ZoneUnorderedMap<ObjectData*, BytecodeAnalysis*> bytecode_analyses_;
ZoneUnorderedMap<PropertyAccessTarget, PropertyAccessInfo,
PropertyAccessTarget::Hash, PropertyAccessTarget::Equal>
property_access_infos_;
......
......@@ -549,8 +549,6 @@ class SerializerForBackgroundCompilation {
Handle<FeedbackVector> feedback_vector() const;
Handle<BytecodeArray> bytecode_array() const;
BytecodeAnalysis const& GetBytecodeAnalysis(
SerializationPolicy policy = SerializationPolicy::kAssumeSerialized);
JSHeapBroker* broker() const { return broker_; }
CompilationDependencies* dependencies() const { return dependencies_; }
......@@ -558,6 +556,7 @@ class SerializerForBackgroundCompilation {
Environment* environment() const { return environment_; }
SerializerForBackgroundCompilationFlags flags() const { return flags_; }
BailoutId osr_offset() const { return osr_offset_; }
const BytecodeAnalysis& bytecode_analysis() { return *bytecode_analysis_; }
JSHeapBroker* const broker_;
CompilationDependencies* const dependencies_;
......@@ -567,6 +566,7 @@ class SerializerForBackgroundCompilation {
// {closure_hints_} but that would be cumbersome.
VirtualClosure const function_;
BailoutId const osr_offset_;
base::Optional<BytecodeAnalysis> bytecode_analysis_;
ZoneUnorderedMap<int, Environment*> jump_target_environments_;
Environment* const environment_;
HintsVector const arguments_;
......@@ -1259,18 +1259,8 @@ Handle<BytecodeArray> SerializerForBackgroundCompilation::bytecode_array()
return handle(function().shared()->GetBytecodeArray(), broker()->isolate());
}
BytecodeAnalysis const& SerializerForBackgroundCompilation::GetBytecodeAnalysis(
SerializationPolicy policy) {
return broker()->GetBytecodeAnalysis(
bytecode_array(), osr_offset(),
flags() &
SerializerForBackgroundCompilationFlag::kAnalyzeEnvironmentLiveness,
policy);
}
void SerializerForBackgroundCompilation::TraverseBytecode() {
BytecodeAnalysis const& bytecode_analysis =
GetBytecodeAnalysis(SerializationPolicy::kSerializeIfNeeded);
bytecode_analysis_.emplace(bytecode_array(), zone(), osr_offset(), false);
BytecodeArrayRef(broker(), bytecode_array()).SerializeForCompilation();
BytecodeArrayIterator iterator(bytecode_array());
......@@ -1308,10 +1298,10 @@ void SerializerForBackgroundCompilation::TraverseBytecode() {
try_start_matcher.HandlerOffsetForCurrentPosition(
save_handler_environments);
if (bytecode_analysis.IsLoopHeader(current_offset)) {
if (bytecode_analysis().IsLoopHeader(current_offset)) {
// Graph builder might insert jumps to resume targets in the loop body.
LoopInfo const& loop_info =
bytecode_analysis.GetLoopInfoFor(current_offset);
bytecode_analysis().GetLoopInfoFor(current_offset);
for (const auto& target : loop_info.resume_jump_targets()) {
ContributeToJumpTargetEnvironment(target.target_offset());
}
......@@ -2782,7 +2772,7 @@ void SerializerForBackgroundCompilation::VisitSwitchOnSmiNoFeedback(
void SerializerForBackgroundCompilation::VisitSwitchOnGeneratorState(
interpreter::BytecodeArrayIterator* iterator) {
for (const auto& target : GetBytecodeAnalysis().resume_jump_targets()) {
for (const auto& target : bytecode_analysis().resume_jump_targets()) {
ContributeToJumpTargetEnvironment(target.target_offset());
}
}
......
......@@ -10,12 +10,6 @@ namespace v8 {
namespace internal {
namespace interpreter {
BytecodeArrayRandomIterator::BytecodeArrayRandomIterator(
std::unique_ptr<AbstractBytecodeArray> bytecode_array, Zone* zone)
: BytecodeArrayAccessor(std::move(bytecode_array), 0), offsets_(zone) {
Initialize();
}
BytecodeArrayRandomIterator::BytecodeArrayRandomIterator(
Handle<BytecodeArray> bytecode_array, Zone* zone)
: BytecodeArrayAccessor(bytecode_array, 0), offsets_(zone) {
......
......@@ -18,9 +18,6 @@ namespace interpreter {
class V8_EXPORT_PRIVATE BytecodeArrayRandomIterator final
: public BytecodeArrayAccessor {
public:
BytecodeArrayRandomIterator(
std::unique_ptr<AbstractBytecodeArray> bytecode_array, Zone* zone);
BytecodeArrayRandomIterator(Handle<BytecodeArray> bytecode_array, Zone* zone);
BytecodeArrayRandomIterator(const BytecodeArrayRandomIterator&) = delete;
......
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