[turbofan] Improve broker tracing wrt. function inlining
Make it clearer when the broker is missing information about a potential inlinee. Bug: v8:7790 Change-Id: I73d6066e75049e15a3fd821ac685476812482142 Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/1825241 Commit-Queue: Georg Neis <neis@chromium.org> Reviewed-by: Maya Lekova <mslekova@chromium.org> Cr-Commit-Position: refs/heads/master@{#64007}
This commit is contained in:
parent
0cf720862a
commit
2d09117798
@ -329,8 +329,6 @@ class V8_EXPORT_PRIVATE JSFunctionRef : public JSObjectRef {
|
||||
SharedFunctionInfoRef shared() const;
|
||||
FeedbackVectorRef feedback_vector() const;
|
||||
int InitialMapInstanceSizeWithMinSlack() const;
|
||||
|
||||
bool IsSerializedForCompilation() const;
|
||||
};
|
||||
|
||||
class JSRegExpRef : public JSObjectRef {
|
||||
@ -727,7 +725,6 @@ class BytecodeArrayRef : public FixedArrayBaseRef {
|
||||
Address handler_table_address() const;
|
||||
int handler_table_size() const;
|
||||
|
||||
bool IsSerializedForCompilation() const;
|
||||
void SerializeForCompilation();
|
||||
};
|
||||
|
||||
|
@ -1497,10 +1497,6 @@ class BytecodeArrayData : public FixedArrayBaseData {
|
||||
return *(Handle<Smi>::cast(constant_pool_[index]->object()));
|
||||
}
|
||||
|
||||
bool IsSerializedForCompilation() const {
|
||||
return is_serialized_for_compilation_;
|
||||
}
|
||||
|
||||
void SerializeForCompilation(JSHeapBroker* broker) {
|
||||
if (is_serialized_for_compilation_) return;
|
||||
|
||||
@ -3084,11 +3080,6 @@ Smi BytecodeArrayRef::GetConstantAtIndexAsSmi(int index) const {
|
||||
return data()->AsBytecodeArray()->GetConstantAtIndexAsSmi(index);
|
||||
}
|
||||
|
||||
bool BytecodeArrayRef::IsSerializedForCompilation() const {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) return true;
|
||||
return data()->AsBytecodeArray()->IsSerializedForCompilation();
|
||||
}
|
||||
|
||||
void BytecodeArrayRef::SerializeForCompilation() {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) return;
|
||||
data()->AsBytecodeArray()->SerializeForCompilation(broker());
|
||||
@ -3867,18 +3858,6 @@ bool JSFunctionRef::serialized() const {
|
||||
return data()->AsJSFunction()->serialized();
|
||||
}
|
||||
|
||||
bool JSFunctionRef::IsSerializedForCompilation() const {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) {
|
||||
return handle(object()->shared(), broker()->isolate())->HasBytecodeArray();
|
||||
}
|
||||
|
||||
// We get a crash if we try to access the shared() getter without
|
||||
// checking for `serialized` first. Also it's possible to have a
|
||||
// JSFunctionRef without a feedback vector.
|
||||
return serialized() && has_feedback_vector() &&
|
||||
shared().IsSerializedForCompilation(feedback_vector());
|
||||
}
|
||||
|
||||
JSArrayRef SharedFunctionInfoRef::GetTemplateObject(
|
||||
ObjectRef description, FeedbackVectorRef vector, FeedbackSlot slot,
|
||||
SerializationPolicy policy) {
|
||||
@ -3921,6 +3900,7 @@ JSArrayRef SharedFunctionInfoRef::GetTemplateObject(
|
||||
void SharedFunctionInfoRef::SetSerializedForCompilation(
|
||||
FeedbackVectorRef feedback) {
|
||||
CHECK_EQ(broker()->mode(), JSHeapBroker::kSerializing);
|
||||
CHECK(HasBytecodeArray());
|
||||
data()->AsSharedFunctionInfo()->SetSerializedForCompilation(broker(),
|
||||
feedback);
|
||||
}
|
||||
@ -3947,7 +3927,7 @@ SharedFunctionInfoRef::function_template_info() const {
|
||||
|
||||
bool SharedFunctionInfoRef::IsSerializedForCompilation(
|
||||
FeedbackVectorRef feedback) const {
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) return true;
|
||||
if (broker()->mode() == JSHeapBroker::kDisabled) return HasBytecodeArray();
|
||||
return data()->AsSharedFunctionInfo()->IsSerializedForCompilation(feedback);
|
||||
}
|
||||
|
||||
|
@ -22,9 +22,35 @@ namespace compiler {
|
||||
} while (false)
|
||||
|
||||
namespace {
|
||||
bool IsSmall(BytecodeArrayRef bytecode) {
|
||||
bool IsSmall(BytecodeArrayRef const& bytecode) {
|
||||
return bytecode.length() <= FLAG_max_inlined_bytecode_size_small;
|
||||
}
|
||||
|
||||
bool CanConsiderForInlining(JSHeapBroker* broker,
|
||||
SharedFunctionInfoRef const& shared,
|
||||
FeedbackVectorRef const& feedback_vector) {
|
||||
if (!shared.IsInlineable()) return false;
|
||||
DCHECK(shared.HasBytecodeArray());
|
||||
if (!shared.IsSerializedForCompilation(feedback_vector)) {
|
||||
TRACE_BROKER_MISSING(
|
||||
broker, "data for " << shared << " (not serialized for compilation)");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CanConsiderForInlining(JSHeapBroker* broker,
|
||||
JSFunctionRef const& function) {
|
||||
if (!function.has_feedback_vector()) return false;
|
||||
if (!function.serialized()) {
|
||||
TRACE_BROKER_MISSING(
|
||||
broker, "data for " << function << " (cannot consider for inlining)");
|
||||
return false;
|
||||
}
|
||||
return CanConsiderForInlining(broker, function.shared(),
|
||||
function.feedback_vector());
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions(
|
||||
@ -38,11 +64,11 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions(
|
||||
if (m.HasValue() && m.Ref(broker()).IsJSFunction()) {
|
||||
out.functions[0] = m.Ref(broker()).AsJSFunction();
|
||||
JSFunctionRef function = out.functions[0].value();
|
||||
if (function.IsSerializedForCompilation()) {
|
||||
if (CanConsiderForInlining(broker(), function)) {
|
||||
out.bytecode[0] = function.shared().GetBytecodeArray();
|
||||
out.num_functions = 1;
|
||||
return out;
|
||||
}
|
||||
out.num_functions = 1;
|
||||
return out;
|
||||
}
|
||||
if (m.IsPhi()) {
|
||||
int const value_input_count = m.node()->op()->ValueInputCount();
|
||||
@ -59,7 +85,7 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions(
|
||||
|
||||
out.functions[n] = m.Ref(broker()).AsJSFunction();
|
||||
JSFunctionRef function = out.functions[n].value();
|
||||
if (function.IsSerializedForCompilation()) {
|
||||
if (CanConsiderForInlining(broker(), function)) {
|
||||
out.bytecode[n] = function.shared().GetBytecodeArray();
|
||||
}
|
||||
}
|
||||
@ -67,11 +93,14 @@ JSInliningHeuristic::Candidate JSInliningHeuristic::CollectFunctions(
|
||||
return out;
|
||||
}
|
||||
if (m.IsJSCreateClosure()) {
|
||||
CreateClosureParameters const& p = CreateClosureParametersOf(m.op());
|
||||
DCHECK(!out.functions[0].has_value());
|
||||
out.shared_info = SharedFunctionInfoRef(broker(), p.shared_info());
|
||||
SharedFunctionInfoRef shared_info = out.shared_info.value();
|
||||
if (shared_info.HasBytecodeArray()) {
|
||||
CreateClosureParameters const& p = CreateClosureParametersOf(m.op());
|
||||
FeedbackCellRef feedback_cell(broker(), p.feedback_cell());
|
||||
SharedFunctionInfoRef shared_info(broker(), p.shared_info());
|
||||
out.shared_info = shared_info;
|
||||
if (feedback_cell.value().IsFeedbackVector() &&
|
||||
CanConsiderForInlining(broker(), shared_info,
|
||||
feedback_cell.value().AsFeedbackVector())) {
|
||||
out.bytecode[0] = shared_info.GetBytecodeArray();
|
||||
}
|
||||
out.num_functions = 1;
|
||||
@ -135,7 +164,8 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
|
||||
SharedFunctionInfoRef shared = candidate.functions[i].has_value()
|
||||
? candidate.functions[i].value().shared()
|
||||
: candidate.shared_info.value();
|
||||
candidate.can_inline_function[i] = shared.IsInlineable();
|
||||
candidate.can_inline_function[i] = candidate.bytecode[i].has_value();
|
||||
CHECK_IMPLIES(candidate.can_inline_function[i], shared.IsInlineable());
|
||||
// Do not allow direct recursion i.e. f() -> f(). We still allow indirect
|
||||
// recurion like f() -> g() -> f(). The indirect recursion is helpful in
|
||||
// cases where f() is a small dispatch function that calls the appropriate
|
||||
@ -151,11 +181,9 @@ Reduction JSInliningHeuristic::Reduce(Node* node) {
|
||||
node->id(), node->op()->mnemonic());
|
||||
candidate.can_inline_function[i] = false;
|
||||
}
|
||||
// A function reaching this point should always have its bytecode
|
||||
// serialized.
|
||||
BytecodeArrayRef bytecode = candidate.bytecode[i].value();
|
||||
if (candidate.can_inline_function[i]) {
|
||||
can_inline_candidate = true;
|
||||
BytecodeArrayRef bytecode = candidate.bytecode[i].value();
|
||||
candidate.total_size += bytecode.length();
|
||||
candidate_is_small = candidate_is_small && IsSmall(bytecode);
|
||||
}
|
||||
|
@ -321,7 +321,7 @@ base::Optional<SharedFunctionInfoRef> JSInliner::DetermineCallTarget(
|
||||
|
||||
// TODO(turbofan): We might consider to eagerly create the feedback vector
|
||||
// in such a case (in {DetermineCallContext} below) eventually.
|
||||
FeedbackCellRef cell(FeedbackCellRef(broker(), p.feedback_cell()));
|
||||
FeedbackCellRef cell(broker(), p.feedback_cell());
|
||||
if (!cell.value().IsFeedbackVector()) return base::nullopt;
|
||||
|
||||
return SharedFunctionInfoRef(broker(), p.shared_info());
|
||||
@ -413,11 +413,11 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
|
||||
Node* exception_target = nullptr;
|
||||
NodeProperties::IsExceptionalCall(node, &exception_target);
|
||||
|
||||
// JSInliningHeuristic has already filtered candidates without a
|
||||
// BytecodeArray by calling SharedFunctionInfoRef::IsInlineable. For the ones
|
||||
// passing the IsInlineable check, The broker holds a reference to the
|
||||
// bytecode array, which prevents it from getting flushed.
|
||||
// Therefore, the following check should always hold true.
|
||||
// JSInliningHeuristic has already filtered candidates without a BytecodeArray
|
||||
// by calling SharedFunctionInfoRef::IsInlineable. For the ones passing the
|
||||
// IsInlineable check, the broker holds a reference to the bytecode array,
|
||||
// which prevents it from getting flushed. Therefore, the following check
|
||||
// should always hold true.
|
||||
CHECK(shared_info->is_compiled());
|
||||
|
||||
if (!FLAG_concurrent_inlining && info_->is_source_positions_enabled()) {
|
||||
@ -428,17 +428,10 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
|
||||
TRACE("Inlining " << *shared_info << " into " << outer_shared_info
|
||||
<< ((exception_target != nullptr) ? " (inside try-block)"
|
||||
: ""));
|
||||
// Determine the targets feedback vector and its context.
|
||||
// Determine the target's feedback vector and its context.
|
||||
Node* context;
|
||||
FeedbackVectorRef feedback_vector = DetermineCallContext(node, &context);
|
||||
|
||||
if (FLAG_concurrent_inlining &&
|
||||
!shared_info->IsSerializedForCompilation(feedback_vector)) {
|
||||
// TODO(neis): Should this be a broker message?
|
||||
TRACE("Missed opportunity to inline a function ("
|
||||
<< *shared_info << " with " << feedback_vector << ")");
|
||||
return NoChange();
|
||||
}
|
||||
CHECK(shared_info->IsSerializedForCompilation(feedback_vector));
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
// After this point, we've made a decision to inline this function.
|
||||
|
@ -52,17 +52,19 @@ SerializerTester::SerializerTester(const char* source)
|
||||
TEST(SerializeEmptyFunction) {
|
||||
SerializerTester tester(
|
||||
"function f() {}; %EnsureFeedbackVectorForFunction(f); return f;");
|
||||
CHECK(tester.function().IsSerializedForCompilation());
|
||||
JSFunctionRef function = tester.function();
|
||||
CHECK(
|
||||
function.shared().IsSerializedForCompilation(function.feedback_vector()));
|
||||
}
|
||||
|
||||
// This helper function allows for testing weather an inlinee candidate
|
||||
// This helper function allows for testing whether an inlinee candidate
|
||||
// was properly serialized. It expects that the top-level function (that is
|
||||
// run through the SerializerTester) will return its inlinee candidate.
|
||||
void CheckForSerializedInlinee(const char* source, int argc = 0,
|
||||
Handle<Object> argv[] = {}) {
|
||||
SerializerTester tester(source);
|
||||
JSFunctionRef f = tester.function();
|
||||
CHECK(f.IsSerializedForCompilation());
|
||||
CHECK(f.shared().IsSerializedForCompilation(f.feedback_vector()));
|
||||
|
||||
MaybeHandle<Object> g_obj = Execution::Call(
|
||||
tester.isolate(), tester.function().object(),
|
||||
|
Loading…
Reference in New Issue
Block a user