// Isolates repeated bytecode LoadName reads of one captured binding. The
// four-function chain approximates Navier-Stokes' measured parent depth while
// the local-slot control keeps the loop and activation shape identical.

///|
const CAPTURED_READ_SOURCE =
  #|function outer() {
  #|  var captured = 1;
  #|  function level1() {
  #|    function level2() {
  #|      function level3() {
  #|        var sum = 0;
  #|        for (var i = 0; i < 1024; i++) sum += captured;
  #|        return sum;
  #|      }
  #|      return level3();
  #|    }
  #|    return level2();
  #|  }
  #|  return level1();
  #|}
  #|outer();

///|
const LOCAL_READ_SOURCE =
  #|function outer() {
  #|  function level1() {
  #|    function level2() {
  #|      function level3() {
  #|        var captured = 1;
  #|        var sum = 0;
  #|        for (var i = 0; i < 1024; i++) sum += captured;
  #|        return sum;
  #|      }
  #|      return level3();
  #|    }
  #|    return level2();
  #|  }
  #|  return level1();
  #|}
  #|outer();

///|
test "isolate/bytecode/captured_binding_read" (b : @bench.T) {
  let captured = @compiler.compile_script_to_bytecode(
    @parser.parse(CAPTURED_READ_SOURCE).stmts,
  )
  let local_program = @compiler.compile_script_to_bytecode(
    @parser.parse(LOCAL_READ_SOURCE).stmts,
  )
  let captured_interp = @interpreter.new_interpreter()
  let local_interp = @interpreter.new_interpreter()
  guard captured.run(captured_interp).to_string() == "1024" else {
    abort("captured binding benchmark pre-check failed")
  }
  guard local_program.run(local_interp).to_string() == "1024" else {
    abort("local binding benchmark pre-check failed")
  }
  b.bench(name="captured binding read", fn() {
    b.keep(captured.run(captured_interp)) catch {
      _ => abort("captured binding read raised")
    }
  })
  b.bench(name="local slot read control", fn() {
    b.keep(local_program.run(local_interp)) catch {
      _ => abort("local slot read raised")
    }
  })
}