[Turbofan] Allow recursive inlining

Currently, we do not inline recursive functions. This is in general a
good idea but could be useful in some cases. For example, in rayTrace
there is a class.create function to create new classes, which basically
calls the initialize function on the object. When there are classes which
instantiate other classes this leads to recursion. These are really small
functions (within the small function budget) and it is good to inline them.
Allowing such functions to inline improves the score on rayTrace by 12-16%
and box2d by 24-30%.

There is also an absolute limit on the maximum levels of inlining to avoid
any corner cases and to ensure inlining always terminates.

Bug: v8:6682
Change-Id: I6784f68d6395097d126c0850b1a1336b6583d958
Reviewed-on: https://chromium-review.googlesource.com/608235
Reviewed-by: Michael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Mythri Alle <mythria@chromium.org>
Cr-Commit-Position: refs/heads/master@{#47255}
This commit is contained in:
Mythri 2017-08-09 16:23:13 +01:00 committed by Commit Bot
parent 74af07c125
commit d72c97e20b

View File

@ -24,6 +24,12 @@ namespace v8 {
namespace internal { namespace internal {
namespace compiler { namespace compiler {
namespace {
// This is just to avoid some corner cases, especially since we allow recursive
// inlining.
static const int kMaxDepthForInlining = 50;
} // namespace
#define TRACE(...) \ #define TRACE(...) \
do { \ do { \
if (FLAG_trace_turbo_inlining) PrintF(__VA_ARGS__); \ if (FLAG_trace_turbo_inlining) PrintF(__VA_ARGS__); \
@ -475,19 +481,19 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
return NoChange(); return NoChange();
} }
// TODO(turbofan): TranslatedState::GetAdaptedArguments() currently relies on // To ensure inlining always terminates, we have an upper limit on inlining
// not inlining recursive functions. We might want to relax that at some // the nested calls.
// point. int nesting_level = 0;
for (Node* frame_state = call.frame_state(); for (Node* frame_state = call.frame_state();
frame_state->opcode() == IrOpcode::kFrameState; frame_state->opcode() == IrOpcode::kFrameState;
frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) { frame_state = frame_state->InputAt(kFrameStateOuterStateInput)) {
FrameStateInfo const& frame_info = OpParameter<FrameStateInfo>(frame_state); nesting_level++;
Handle<SharedFunctionInfo> frame_shared_info; if (nesting_level > kMaxDepthForInlining) {
if (frame_info.shared_info().ToHandle(&frame_shared_info) && TRACE(
*frame_shared_info == *shared_info) { "Not inlining %s into %s because call has exceeded the maximum depth "
TRACE("Not inlining %s into %s because call is recursive\n", "for function inlining\n",
shared_info->DebugName()->ToCString().get(), shared_info->DebugName()->ToCString().get(),
info_->shared_info()->DebugName()->ToCString().get()); info_->shared_info()->DebugName()->ToCString().get());
return NoChange(); return NoChange();
} }
} }