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();
|
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
|
} // namespace
|
||||||
|
|
||||||
RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
|
RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
|
||||||
@ -258,7 +354,10 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
|
|||||||
return ReadOnlyRoots(isolate).undefined_value();
|
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
|
// For OSR'd code, we keep the optimized code around if deoptimization occurs
|
||||||
// outside the outermost loop containing the loop that triggered OSR
|
// 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
|
// still worth jumping to the OSR'd code on the next run. The reduced cost of
|
||||||
// the loop should pay for the deoptimization costs.
|
// the loop should pay for the deoptimization costs.
|
||||||
const BytecodeOffset osr_offset = optimized_code->osr_offset();
|
const BytecodeOffset osr_offset = optimized_code->osr_offset();
|
||||||
if (osr_offset.IsNone() ||
|
if (osr_offset.IsNone()) {
|
||||||
DeoptExitIsInsideOsrLoop(isolate, *function, deopt_exit_offset,
|
Deoptimizer::DeoptimizeFunction(*function, *optimized_code);
|
||||||
osr_offset)) {
|
DeoptAllOsrLoopsContainingDeoptExit(isolate, *function, deopt_exit_offset);
|
||||||
|
} else if (DeoptExitIsInsideOsrLoop(isolate, *function, deopt_exit_offset,
|
||||||
|
osr_offset)) {
|
||||||
Deoptimizer::DeoptimizeFunction(*function, *optimized_code);
|
Deoptimizer::DeoptimizeFunction(*function, *optimized_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// Use of this source code is governed by a BSD-style license that can be
|
// Use of this source code is governed by a BSD-style license that can be
|
||||||
// found in the LICENSE file.
|
// found in the LICENSE file.
|
||||||
|
|
||||||
|
// Flags: --interrupt-budget=100 --deopt-every-n-times=4
|
||||||
// Flags: --allow-natives-syntax --use-osr
|
// Flags: --allow-natives-syntax --use-osr
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
Loading…
Reference in New Issue
Block a user