// Copyright 2018 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: --allow-natives-syntax --opt --noalways-opt --stress-flush-bytecode
// Flags: --expose-gc

Debug = debug.Debug

function foo() {
  return 44;
}

function listener(event, exec_state, event_data, data) {
  if (event != Debug.DebugEvent.Break) return;

  // Optimize foo.
  %PrepareFunctionForOptimization(foo);
  %OptimizeFunctionOnNextCall(foo);
  foo();
  assertOptimized(foo);

  // Lazily deopt foo, which marks the code for deoptimization and invalidates
  // the DeoptimizationData, but doesn't unlink the optimized code entry in
  // foo's JSFunction.
  %DeoptimizeFunction(foo);

  // Run the GC. Since the DeoptimizationData is now dead, the bytecode
  // associated with the optimized code is free to be flushed, which also
  // free's the feedback vector meta-data.
  gc();

  // Execute foo with side-effect checks, which causes the debugger to call
  // DeoptimizeFunction on foo. Even though the code is already marked for
  // deoptimization, this will try to unlink the optimized code from the
  // feedback vector, which will fail due to the feedback meta-data being
  // flushed. The deoptimizer should call JSFunction::ResetIfBytecodeFlushed
  // before trying to do this, which will clear the whole feedback vector and
  // reset the JSFunction's code entry field to CompileLazy.
  exec_state.frame(0).evaluate("foo()", true);
}

// Add the debug event listener.
Debug.setListener(listener);

function f() {
  debugger;
}
f();
