[osr] Fix DeoptExitIsInsideOsrLoop in presence of inlining
This logic was confused in the presence of inlined frames; the deopt exit offset would point inside the innermost inlined frame while we incorrectly assumed it points at the outermost frame. Fix this by always referring to the bytecode offset of the outermost frame. Bug: v8:12161 Fixed: chromium:1320094 Change-Id: I2eb28498639432c5344859f64a9388d93ee23bde Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/3608630 Auto-Submit: Jakob Linke <jgruber@chromium.org> Reviewed-by: Toon Verwaest <verwaest@chromium.org> Commit-Queue: Jakob Linke <jgruber@chromium.org> Cr-Commit-Position: refs/heads/main@{#80212}
This commit is contained in:
parent
ac68548331
commit
4ac65c1b11
@ -533,7 +533,6 @@ Deoptimizer::Deoptimizer(Isolate* isolate, JSFunction function,
|
||||
DCHECK_EQ(0, offset % kLazyDeoptExitSize);
|
||||
deopt_exit_index_ = eager_deopt_count + (offset / kLazyDeoptExitSize);
|
||||
}
|
||||
deopt_exit_bytecode_offset_ = deopt_data.GetBytecodeOffset(deopt_exit_index_);
|
||||
}
|
||||
|
||||
Code Deoptimizer::FindOptimizedCode() {
|
||||
@ -642,7 +641,8 @@ int LookupCatchHandler(Isolate* isolate, TranslatedFrame* translated_frame,
|
||||
|
||||
} // namespace
|
||||
|
||||
void Deoptimizer::TraceDeoptBegin(int optimization_id) {
|
||||
void Deoptimizer::TraceDeoptBegin(int optimization_id,
|
||||
BytecodeOffset bytecode_offset) {
|
||||
DCHECK(tracing_enabled());
|
||||
FILE* file = trace_scope()->file();
|
||||
Deoptimizer::DeoptInfo info =
|
||||
@ -666,9 +666,8 @@ void Deoptimizer::TraceDeoptBegin(int optimization_id) {
|
||||
#ifdef DEBUG
|
||||
info.node_id,
|
||||
#endif // DEBUG
|
||||
deopt_exit_bytecode_offset_.ToInt(), deopt_exit_index_,
|
||||
fp_to_sp_delta_, caller_frame_top_,
|
||||
PointerAuthentication::StripPAC(from_));
|
||||
bytecode_offset.ToInt(), deopt_exit_index_, fp_to_sp_delta_,
|
||||
caller_frame_top_, PointerAuthentication::StripPAC(from_));
|
||||
if (verbose_tracing_enabled() && deopt_kind_ != DeoptimizeKind::kLazy) {
|
||||
PrintF(file, " ;;; deoptimize at ");
|
||||
OFStream outstr(file);
|
||||
@ -796,13 +795,15 @@ void Deoptimizer::DoComputeOutputFrames() {
|
||||
CHECK_GT(static_cast<uintptr_t>(caller_frame_top_),
|
||||
stack_guard->real_jslimit());
|
||||
|
||||
BytecodeOffset bytecode_offset =
|
||||
input_data.GetBytecodeOffset(deopt_exit_index_);
|
||||
ByteArray translations = input_data.TranslationByteArray();
|
||||
unsigned translation_index =
|
||||
input_data.TranslationIndex(deopt_exit_index_).value();
|
||||
|
||||
if (tracing_enabled()) {
|
||||
timer.Start();
|
||||
TraceDeoptBegin(input_data.OptimizationId().value());
|
||||
TraceDeoptBegin(input_data.OptimizationId().value(), bytecode_offset);
|
||||
}
|
||||
|
||||
FILE* trace_file =
|
||||
@ -817,6 +818,9 @@ void Deoptimizer::DoComputeOutputFrames() {
|
||||
: 0,
|
||||
actual_argument_count_ - kJSArgcReceiverSlots);
|
||||
|
||||
bytecode_offset_in_outermost_frame_ =
|
||||
translated_state_.frames()[0].bytecode_offset();
|
||||
|
||||
// Do the input frame to output frame(s) translation.
|
||||
size_t count = translated_state_.frames().size();
|
||||
// If we are supposed to go to the catch handler, find the catching frame
|
||||
|
@ -54,8 +54,12 @@ class Deoptimizer : public Malloced {
|
||||
Handle<JSFunction> function() const;
|
||||
Handle<Code> compiled_code() const;
|
||||
DeoptimizeKind deopt_kind() const { return deopt_kind_; }
|
||||
BytecodeOffset deopt_exit_bytecode_offset() const {
|
||||
return deopt_exit_bytecode_offset_;
|
||||
|
||||
// Where the deopt exit occurred *in the outermost frame*, i.e in the
|
||||
// function we generated OSR'd code for. If the deopt occurred in an inlined
|
||||
// function, this would point at the corresponding outermost Call bytecode.
|
||||
BytecodeOffset bytecode_offset_in_outermost_frame() const {
|
||||
return bytecode_offset_in_outermost_frame_;
|
||||
}
|
||||
|
||||
static Deoptimizer* New(Address raw_function, DeoptimizeKind kind,
|
||||
@ -183,7 +187,7 @@ class Deoptimizer : public Malloced {
|
||||
CodeTracer::Scope* verbose_trace_scope() const {
|
||||
return FLAG_trace_deopt_verbose ? trace_scope() : nullptr;
|
||||
}
|
||||
void TraceDeoptBegin(int optimization_id);
|
||||
void TraceDeoptBegin(int optimization_id, BytecodeOffset bytecode_offset);
|
||||
void TraceDeoptEnd(double deopt_duration);
|
||||
#ifdef DEBUG
|
||||
static void TraceFoundActivation(Isolate* isolate, JSFunction function);
|
||||
@ -195,7 +199,7 @@ class Deoptimizer : public Malloced {
|
||||
JSFunction function_;
|
||||
Code compiled_code_;
|
||||
unsigned deopt_exit_index_;
|
||||
BytecodeOffset deopt_exit_bytecode_offset_ = BytecodeOffset::None();
|
||||
BytecodeOffset bytecode_offset_in_outermost_frame_ = BytecodeOffset::None();
|
||||
DeoptimizeKind deopt_kind_;
|
||||
Address from_;
|
||||
int fp_to_sp_delta_;
|
||||
|
@ -41,6 +41,16 @@ void BytecodeArrayIterator::SetOffset(int offset) {
|
||||
UpdateOperandScale();
|
||||
}
|
||||
|
||||
// static
|
||||
bool BytecodeArrayIterator::IsValidOffset(Handle<BytecodeArray> bytecode_array,
|
||||
int offset) {
|
||||
for (BytecodeArrayIterator it(bytecode_array); !it.done(); it.Advance()) {
|
||||
if (it.current_offset() == offset) return true;
|
||||
if (it.current_offset() > offset) break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BytecodeArrayIterator::ApplyDebugBreak() {
|
||||
// Get the raw bytecode from the bytecode array. This may give us a
|
||||
// scaling prefix, which we can patch with the matching debug-break
|
||||
|
@ -83,6 +83,9 @@ class V8_EXPORT_PRIVATE BytecodeArrayIterator {
|
||||
void SetOffset(int offset);
|
||||
void Reset() { SetOffset(0); }
|
||||
|
||||
// Whether the given offset is reachable in this bytecode array.
|
||||
static bool IsValidOffset(Handle<BytecodeArray> bytecode_array, int offset);
|
||||
|
||||
void ApplyDebugBreak();
|
||||
|
||||
inline Bytecode current_bytecode() const {
|
||||
|
@ -188,9 +188,12 @@ bool DeoptExitIsInsideOsrLoop(Isolate* isolate, JSFunction function,
|
||||
DCHECK(!deopt_exit_offset.IsNone());
|
||||
DCHECK(!osr_offset.IsNone());
|
||||
|
||||
interpreter::BytecodeArrayIterator it(
|
||||
handle(function.shared().GetBytecodeArray(isolate), isolate),
|
||||
osr_offset.ToInt());
|
||||
Handle<BytecodeArray> bytecode_array(
|
||||
function.shared().GetBytecodeArray(isolate), isolate);
|
||||
DCHECK(interpreter::BytecodeArrayIterator::IsValidOffset(
|
||||
bytecode_array, deopt_exit_offset.ToInt()));
|
||||
|
||||
interpreter::BytecodeArrayIterator it(bytecode_array, osr_offset.ToInt());
|
||||
DCHECK_EQ(it.current_bytecode(), interpreter::Bytecode::kJumpLoop);
|
||||
|
||||
for (; !it.done(); it.Advance()) {
|
||||
@ -240,7 +243,7 @@ RUNTIME_FUNCTION(Runtime_NotifyDeoptimized) {
|
||||
// Make sure to materialize objects before causing any allocation.
|
||||
deoptimizer->MaterializeHeapObjects();
|
||||
const BytecodeOffset deopt_exit_offset =
|
||||
deoptimizer->deopt_exit_bytecode_offset();
|
||||
deoptimizer->bytecode_offset_in_outermost_frame();
|
||||
delete deoptimizer;
|
||||
|
||||
// Ensure the context register is updated for materialized objects.
|
||||
|
25
test/mjsunit/regress/regress-1320094.js
Normal file
25
test/mjsunit/regress/regress-1320094.js
Normal file
@ -0,0 +1,25 @@
|
||||
// Copyright 2022 the V8 project authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style license that can be
|
||||
// found in the LICENSE file.
|
||||
//
|
||||
// Flags: --no-use-ic
|
||||
|
||||
function getRandomProperty(v) {
|
||||
var properties = Object.getOwnPropertyNames(v);
|
||||
var proto = Object.v;
|
||||
if (proto) { properties = properties.Object.getOwnPropertyNames(); }
|
||||
if (properties.includes() && v.constructor.hasOwnProperty()) { properties = properties.Object.v.constructor.__proto__; }
|
||||
if (properties.length == 0) { return "0"; }
|
||||
return properties[rand % properties.length];
|
||||
}
|
||||
var __v_12 = {};
|
||||
function __f_7() {
|
||||
for (var __v_8 = 99; __v_8 < 100; __v_8++) {
|
||||
for (var __v_10 = 0; __v_10 < 1000; __v_10++) {
|
||||
var __v_13 = __v_12 + 3;
|
||||
__v_13.__p_702586125 = __v_13[getRandomProperty( 702586125)];
|
||||
}
|
||||
if (true) break;
|
||||
}
|
||||
}
|
||||
__f_7();
|
Loading…
Reference in New Issue
Block a user