Reland "[compiler] Remove the optimized OSR code if deoptimizing at inside of loop"
This is a reland of commit c8c176190a
This CL includes:
- crrev.com/c/3679846 Add condition use_ic to the removing the optimized OSR code logic
- crrev.com/c/3686589 Add out of bytecode array to break condition of removing OSR code cache logic
- Add JumpLoop nesting level 0 to break condition of removing OSR code cache logic
- Change to use Deoptimizer::DeoptimizeFunction() to deoptimize OSR code
Original change's description:
> [compiler] Remove the optimized OSR code if deoptimizing at inside of loop
>
> If the optimized code is deoptimized and the deoptimized exit offset is
> inside of the optimized OSR code related loop, the optimized OSR code is
> also out of date, remove the optimized OSR code, it will avoid hit the
> optimized OSR code and soon later deoptimization of the optimized OSR
> code.
> This CL will reduce deoptimization. E.g. Deoptimization of JetStream2
> case navier-stokes function addFields is reduced from twice to once.
>
> Change-Id: I5bbf3039e916c3736b5b967d1f36b6ea90cfd40b
> Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3648219
> Reviewed-by: Leszek Swirski <leszeks@chromium.org>
> Commit-Queue: Tao Pan <tao.pan@intel.com>
> Cr-Commit-Position: refs/heads/main@{#80826}
Bug: chromium:1330444
Change-Id: I97a466ddfa764438b45f33c6ae33cb921d57278d
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3690451
Reviewed-by: Leszek Swirski <leszeks@chromium.org>
Commit-Queue: Tao Pan <tao.pan@intel.com>
Cr-Commit-Position: refs/heads/main@{#81110}
This commit is contained in:
parent
c2ede7acd2
commit
c2d239ddb3
@ -218,6 +218,102 @@ bool DeoptExitIsInsideOsrLoop(Isolate* isolate, JSFunction function,
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
bool TryGetOptimizedOsrCode(Isolate* isolate, FeedbackVector vector,
|
||||
const interpreter::BytecodeArrayIterator& it,
|
||||
CodeT* code_out) {
|
||||
base::Optional<CodeT> maybe_code =
|
||||
vector.GetOptimizedOsrCode(isolate, it.GetSlotOperand(2));
|
||||
if (maybe_code.has_value()) {
|
||||
*code_out = maybe_code.value();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Deoptimize all osr'd loops which is in the same outermost loop with deopt
|
||||
// exit. For example:
|
||||
// for (;;) {
|
||||
// for (;;) {
|
||||
// } // Type a: loop start < OSR backedge < deopt exit
|
||||
// for (;;) {
|
||||
// <- Deopt
|
||||
// for (;;) {
|
||||
// } // Type b: deopt exit < loop start < OSR backedge
|
||||
// } // Type c: loop start < deopt exit < OSR backedge
|
||||
// } // The outermost loop
|
||||
void DeoptAllOsrLoopsContainingDeoptExit(Isolate* isolate, JSFunction function,
|
||||
BytecodeOffset deopt_exit_offset) {
|
||||
DisallowGarbageCollection no_gc;
|
||||
DCHECK(!deopt_exit_offset.IsNone());
|
||||
|
||||
if (!FLAG_use_ic ||
|
||||
!function.feedback_vector().maybe_has_optimized_osr_code()) {
|
||||
return;
|
||||
}
|
||||
Handle<BytecodeArray> bytecode_array(
|
||||
function.shared().GetBytecodeArray(isolate), isolate);
|
||||
DCHECK(interpreter::BytecodeArrayIterator::IsValidOffset(
|
||||
bytecode_array, deopt_exit_offset.ToInt()));
|
||||
|
||||
interpreter::BytecodeArrayIterator it(bytecode_array,
|
||||
deopt_exit_offset.ToInt());
|
||||
|
||||
FeedbackVector vector = function.feedback_vector();
|
||||
CodeT code;
|
||||
base::SmallVector<CodeT, 8> osr_codes;
|
||||
// Visit before the first loop-with-deopt is found
|
||||
for (; !it.done(); it.Advance()) {
|
||||
// We're only interested in loop ranges.
|
||||
if (it.current_bytecode() != interpreter::Bytecode::kJumpLoop) continue;
|
||||
// Is the deopt exit contained in the current loop?
|
||||
if (base::IsInRange(deopt_exit_offset.ToInt(), it.GetJumpTargetOffset(),
|
||||
it.current_offset())) {
|
||||
break;
|
||||
}
|
||||
// We've reached nesting level 0, i.e. the current JumpLoop concludes a
|
||||
// top-level loop, return as the deopt exit is not in any loop. For example:
|
||||
// <- Deopt
|
||||
// for (;;) {
|
||||
// } // The outermost loop
|
||||
const int loop_nesting_level = it.GetImmediateOperand(1);
|
||||
if (loop_nesting_level == 0) return;
|
||||
if (TryGetOptimizedOsrCode(isolate, vector, it, &code)) {
|
||||
// Collect type b osr'd loops
|
||||
osr_codes.push_back(code);
|
||||
}
|
||||
}
|
||||
if (it.done()) return;
|
||||
for (size_t i = 0, size = osr_codes.size(); i < size; i++) {
|
||||
// Deoptimize type b osr'd loops
|
||||
Deoptimizer::DeoptimizeFunction(function, FromCodeT(osr_codes[i]));
|
||||
}
|
||||
// Visit after the first loop-with-deopt is found
|
||||
for (; !it.done(); it.Advance()) {
|
||||
// We're only interested in loop ranges.
|
||||
if (it.current_bytecode() != interpreter::Bytecode::kJumpLoop) continue;
|
||||
if (TryGetOptimizedOsrCode(isolate, vector, it, &code)) {
|
||||
// Deoptimize type c osr'd loops
|
||||
Deoptimizer::DeoptimizeFunction(function, FromCodeT(code));
|
||||
}
|
||||
// We've reached nesting level 0, i.e. the current JumpLoop concludes a
|
||||
// top-level loop.
|
||||
const int loop_nesting_level = it.GetImmediateOperand(1);
|
||||
if (loop_nesting_level == 0) break;
|
||||
}
|
||||
if (it.done()) return;
|
||||
// Revisit from start of outermost loop to deopt
|
||||
DCHECK_LE(it.GetJumpTargetOffset(), deopt_exit_offset.ToInt());
|
||||
for (it.SetOffset(it.GetJumpTargetOffset());
|
||||
it.current_offset() < deopt_exit_offset.ToInt(); it.Advance()) {
|
||||
// We're only interested in loop ranges.
|
||||
if (it.current_bytecode() != interpreter::Bytecode::kJumpLoop) continue;
|
||||
if (TryGetOptimizedOsrCode(isolate, vector, it, &code)) {
|
||||
// Deoptimize type a osr'd loops
|
||||
Deoptimizer::DeoptimizeFunction(function, FromCodeT(code));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
|
||||
@ -258,7 +354,10 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
|
||||
return ReadOnlyRoots(isolate).undefined_value();
|
||||
}
|
||||
|
||||
// Non-OSR'd code is deoptimized unconditionally.
|
||||
// Non-OSR'd code is deoptimized unconditionally. If the deoptimization occurs
|
||||
// inside the outermost loop containning a loop that can trigger OSR
|
||||
// compilation, we remove the OSR code, it will avoid hit the out of date OSR
|
||||
// code and soon later deoptimization.
|
||||
//
|
||||
// For OSR'd code, we keep the optimized code around if deoptimization occurs
|
||||
// outside the outermost loop containing the loop that triggered OSR
|
||||
@ -267,9 +366,11 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
|
||||
// still worth jumping to the OSR'd code on the next run. The reduced cost of
|
||||
// the loop should pay for the deoptimization costs.
|
||||
const BytecodeOffset osr_offset = optimized_code->osr_offset();
|
||||
if (osr_offset.IsNone() ||
|
||||
DeoptExitIsInsideOsrLoop(isolate, *function, deopt_exit_offset,
|
||||
osr_offset)) {
|
||||
if (osr_offset.IsNone()) {
|
||||
Deoptimizer::DeoptimizeFunction(*function, *optimized_code);
|
||||
DeoptAllOsrLoopsContainingDeoptExit(isolate, *function, deopt_exit_offset);
|
||||
} else if (DeoptExitIsInsideOsrLoop(isolate, *function, deopt_exit_offset,
|
||||
osr_offset)) {
|
||||
Deoptimizer::DeoptimizeFunction(*function, *optimized_code);
|
||||
}
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
|
||||
// Flags: --interrupt-budget=100 --deopt-every-n-times=4
|
||||
// Flags: --allow-natives-syntax --use-osr
|
||||
|
||||
"use strict";
|
||||
|
Loading…
Reference in New Issue
Block a user