text: // Copyright 2016 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.
  
  #include "src/codegen/assembler-inl.h"
  #include "src/debug/debug-interface.h"
  #include "src/execution/frames-inl.h"
  #include "src/objects/property-descriptor.h"
  #include "src/utils/utils.h"
  #include "src/wasm/wasm-debug.h"
  #include "src/wasm/wasm-objects-inl.h"
  #include "test/cctest/cctest.h"
  #include "test/cctest/compiler/value-helper.h"
  #include "test/cctest/wasm/wasm-run-utils.h"
  #include "test/common/wasm/test-signatures.h"
  #include "test/common/wasm/wasm-macro-gen.h"
  
  namespace v8 {
  namespace internal {
  namespace wasm {
  
  namespace {
  
  debug::Location TranslateLocation(WasmRunnerBase* runner,
                                    const debug::Location& loc) {
    // Convert locations from {func_index, offset_in_func} to
    // {0, offset_in_module}.
    int func_index = loc.GetLineNumber();
    int func_offset = runner->builder().GetFunctionAt(func_index)->code.offset();
    int offset = loc.GetColumnNumber() + func_offset;
    return {0, offset};
  }
  
  void CheckLocations(
      WasmRunnerBase* runner, NativeModule* native_module, debug::Location start,
      debug::Location end,
      std::initializer_list<debug::Location> expected_locations_init) {
    std::vector<debug::BreakLocation> locations;
    std::vector<debug::Location> expected_locations;
    for (auto loc : expected_locations_init) {
      expected_locations.push_back(TranslateLocation(runner, loc));
    }
  
    bool success = WasmScript::GetPossibleBreakpoints(
        native_module, TranslateLocation(runner, start),
        TranslateLocation(runner, end), &locations);
    CHECK(success);
  
    printf("got %d locations: ", static_cast<int>(locations.size()));
    for (size_t i = 0, e = locations.size(); i != e; ++i) {
      printf("%s<%d,%d>", i == 0 ? "" : ", ", locations[i].GetLineNumber(),
             locations[i].GetColumnNumber());
    }
    printf("\n");
  
    CHECK_EQ(expected_locations.size(), locations.size());
    for (size_t i = 0, e = locations.size(); i != e; ++i) {
      CHECK_EQ(expected_locations[i].GetLineNumber(),
               locations[i].GetLineNumber());
      CHECK_EQ(expected_locations[i].GetColumnNumber(),
               locations[i].GetColumnNumber());
    }
  }
  
  void CheckLocationsFail(WasmRunnerBase* runner, NativeModule* native_module,
                          debug::Location start, debug::Location end) {
    std::vector<debug::BreakLocation> locations;
    bool success = WasmScript::GetPossibleBreakpoints(
        native_module, TranslateLocation(runner, start),
        TranslateLocation(runner, end), &locations);
    CHECK(!success);
  }
  
  class BreakHandler : public debug::DebugDelegate {
   public:
    enum Action {
      Continue = StepAction::LastStepAction + 1,
      StepNext = StepAction::StepNext,
      StepIn = StepAction::StepIn,
      StepOut = StepAction::StepOut
    };
    struct BreakPoint {
      int position;
      Action action;
      std::function<void(void)> pre_action;
      BreakPoint(int position, Action action)
          : position(position), action(action), pre_action([]() {}) {}
      BreakPoint(int position, Action action,
                 std::function<void(void)> pre_action)
          : position(position), action(action), pre_action(pre_action) {}
    };
  
    explicit BreakHandler(Isolate* isolate,
                          std::initializer_list<BreakPoint> expected_breaks)
        : isolate_(isolate), expected_breaks_(expected_breaks) {
      v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_), this);
    }
    ~BreakHandler() override {
      // Check that all expected breakpoints have been hit.
      CHECK_EQ(count_, expected_breaks_.size());
      v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_),
                                  nullptr);
    }
  
    int count() const { return count_; }
  
   private:
    Isolate* isolate_;
    int count_ = 0;
    std::vector<BreakPoint> expected_breaks_;
  
    void BreakProgramRequested(v8::Local<v8::Context> paused_context,
                               const std::vector<int>&) override {
      printf("Break #%d\n", count_);
      CHECK_GT(expected_breaks_.size(), count_);
  
      // Check the current position.
      StackTraceFrameIterator frame_it(isolate_);
      auto summ = FrameSummary::GetTop(frame_it.frame()).AsWasm();
      CHECK_EQ(expected_breaks_[count_].position, summ.byte_offset());
  
      expected_breaks_[count_].pre_action();
      Action next_action = expected_breaks_[count_].action;
      switch (next_action) {
        case Continue:
          break;
        case StepNext:
        case StepIn:
        case StepOut:
          isolate_->debug()->PrepareStep(static_cast<StepAction>(next_action));
          break;
        default:
          UNREACHABLE();
      }
      ++count_;
    }
  };
  
  Handle<BreakPoint> SetBreakpoint(WasmRunnerBase* runner, int function_index,
                                   int byte_offset,
                                   int expected_set_byte_offset = -1) {
    runner->TierDown();
    int func_offset =
        runner->builder().GetFunctionAt(function_index)->code.offset();
    int code_offset = func_offset + byte_offset;
    if (expected_set_byte_offset == -1) expected_set_byte_offset = byte_offset;
    Handle<WasmInstanceObject> instance = runner->builder().instance_object();
    Handle<Script> script(instance->module_object().script(),
                          runner->main_isolate());
    static int break_index = 0;
    Handle<BreakPoint> break_point =
        runner->main_isolate()->factory()->NewBreakPoint(
            break_index++, runner->main_isolate()->factory()->empty_string());
    CHECK(WasmScript::SetBreakPoint(script, &code_offset, break_point));
    return break_point;
  }
  
  void ClearBreakpoint(WasmRunnerBase* runner, int function_index,
                       int byte_offset, Handle<BreakPoint> break_point) {
    int func_offset =
        runner->builder().GetFunctionAt(function_index)->code.offset();
    int code_offset = func_offset + byte_offset;
    Handle<WasmInstanceObject> instance = runner->builder().instance_object();
    Handle<Script> script(instance->module_object().script(),
                          runner->main_isolate());
    CHECK(WasmScript::ClearBreakPoint(script, code_offset, break_point));
  }
  
  // Wrapper with operator<<.
  struct WasmValWrapper {
    WasmValue val;
  
    bool operator==(const WasmValWrapper& other) const {
      return val == other.val;
    }
  };
  
  // Only needed in debug builds. Avoid unused warning otherwise.
  #ifdef DEBUG
  std::ostream& operator<<(std::ostream& out, const WasmValWrapper& wrapper) {
    switch (wrapper.val.type().kind()) {
      case ValueType::kI32:
        out << "i32: " << wrapper.val.to<int32_t>();
        break;
      case ValueType::kI64:
        out << "i64: " << wrapper.val.to<int64_t>();
        break;
      case ValueType::kF32:
        out << "f32: " << wrapper.val.to<float>();
        break;
      case ValueType::kF64:
        out << "f64: " << wrapper.val.to<double>();
        break;
      default:
        UNIMPLEMENTED();
    }
    return out;
  }
  #endif
  
  class CollectValuesBreakHandler : public debug::DebugDelegate {
   public:
    struct BreakpointValues {
      std::vector<WasmValue> locals;
      std::vector<WasmValue> stack;
    };
  
    explicit CollectValuesBreakHandler(
        Isolate* isolate, std::initializer_list<BreakpointValues> expected_values)
        : isolate_(isolate), expected_values_(expected_values) {
      v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_), this);
    }
    ~CollectValuesBreakHandler() override {
      v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_),
                                  nullptr);
    }
  
   private:
    Isolate* isolate_;
    int count_ = 0;
    std::vector<BreakpointValues> expected_values_;
  
    void BreakProgramRequested(v8::Local<v8::Context> paused_context,
                               const std::vector<int>&) override {
      printf("Break #%d\n", count_);
      CHECK_GT(expected_values_.size(), count_);
      auto& expected = expected_values_[count_];
      ++count_;
  
      HandleScope handles(isolate_);
  
      StackTraceFrameIterator frame_it(isolate_);
      WasmFrame* frame = WasmFrame::cast(frame_it.frame());
      DebugInfo* debug_info = frame->native_module()->GetDebugInfo();
  
      int num_locals = debug_info->GetNumLocals(frame->pc());
      CHECK_EQ(expected.locals.size(), num_locals);
      for (int i = 0; i < num_locals; ++i) {
        WasmValue local_value = debug_info->GetLocalValue(
            i, frame->pc(), frame->fp(), frame->callee_fp());
        CHECK_EQ(WasmValWrapper{expected.locals[i]}, WasmValWrapper{local_value});
      }
  
      int stack_depth = debug_info->GetStackDepth(frame->pc());
      CHECK_EQ(expected.stack.size(), stack_depth);
      for (int i = 0; i < stack_depth; ++i) {
        WasmValue stack_value = debug_info->GetStackValue(
            i, frame->pc(), frame->fp(), frame->callee_fp());
        CHECK_EQ(WasmValWrapper{expected.stack[i]}, WasmValWrapper{stack_value});
      }
  
      isolate_->debug()->PrepareStep(StepAction::StepIn);
    }
  };
  
  // Special template to explicitly cast to WasmValue.
  template <typename Arg>
  WasmValue MakeWasmVal(Arg arg) {
    return WasmValue(arg);
  }
  // Translate long to i64 (ambiguous otherwise).
  template <>
  WasmValue MakeWasmVal(long arg) {  // NOLINT: allow long parameter
    return WasmValue(static_cast<int64_t>(arg));
  }
  
  template <typename... Args>
  std::vector<WasmValue> wasmVec(Args... args) {
    std::array<WasmValue, sizeof...(args)> arr{{MakeWasmVal(args)...}};
    return std::vector<WasmValue>{arr.begin(), arr.end()};
  }
  
  int GetIntReturnValue(MaybeHandle<Object> retval) {
    CHECK(!retval.is_null());
    int result;
    CHECK(retval.ToHandleChecked()->ToInt32(&result));
    return result;
  }
  
  }  // namespace
  
  WASM_COMPILED_EXEC_TEST(WasmCollectPossibleBreakpoints) {
    WasmRunner<int> runner(execution_tier);
  
    BUILD(runner, WASM_NOP, WASM_I32_ADD(WASM_ZERO, WASM_ONE));
  
    WasmInstanceObject instance = *runner.builder().instance_object();
    NativeModule* native_module = instance.module_object().native_module();
  
    std::vector<debug::Location> locations;
    // Check all locations for function 0.
    CheckLocations(&runner, native_module, {0, 0}, {0, 10},
                   {{0, 1}, {0, 2}, {0, 4}, {0, 6}, {0, 7}});
    // Check a range ending at an instruction.
    CheckLocations(&runner, native_module, {0, 2}, {0, 4}, {{0, 2}});
    // Check a range ending one behind an instruction.
    CheckLocations(&runner, native_module, {0, 2}, {0, 5}, {{0, 2}, {0, 4}});
    // Check a range starting at an instruction.
    CheckLocations(&runner, native_module, {0, 7}, {0, 8}, {{0, 7}});
    // Check from an instruction to beginning of next function.
    CheckLocations(&runner, native_module, {0, 7}, {0, 10}, {{0, 7}});
    // Check from end of one function (no valid instruction position) to beginning
    // of next function. Must be empty, but not fail.
    CheckLocations(&runner, native_module, {0, 8}, {0, 10}, {});
    // Check from one after the end of the function. Must fail.
    CheckLocationsFail(&runner, native_module, {0, 9}, {0, 10});
  }
  
  WASM_COMPILED_EXEC_TEST(WasmSimpleBreak) {
    WasmRunner<int> runner(execution_tier);
    Isolate* isolate = runner.main_isolate();
  
    BUILD(runner, WASM_NOP, WASM_I32_ADD(WASM_I32V_1(11), WASM_I32V_1(3)));
  
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
    SetBreakpoint(&runner, runner.function_index(), 4, 4);
  
    BreakHandler count_breaks(isolate, {{4, BreakHandler::Continue}});
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    MaybeHandle<Object> retval =
        Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
    CHECK_EQ(14, GetIntReturnValue(retval));
  }
  
  WASM_COMPILED_EXEC_TEST(WasmNonBreakablePosition) {
    WasmRunner<int> runner(execution_tier);
    Isolate* isolate = runner.main_isolate();
  
    BUILD(runner, WASM_RETURN1(WASM_I32V_2(1024)));
  
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
    SetBreakpoint(&runner, runner.function_index(), 2, 4);
  
    BreakHandler count_breaks(isolate, {{4, BreakHandler::Continue}});
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    MaybeHandle<Object> retval =
        Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
    CHECK_EQ(1024, GetIntReturnValue(retval));
  }
  
  WASM_COMPILED_EXEC_TEST(WasmSimpleStepping) {
    WasmRunner<int> runner(execution_tier);
    BUILD(runner, WASM_I32_ADD(WASM_I32V_1(11), WASM_I32V_1(3)));
  
    Isolate* isolate = runner.main_isolate();
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
  
    // Set breakpoint at the first I32Const.
    SetBreakpoint(&runner, runner.function_index(), 1, 1);
  
    BreakHandler count_breaks(isolate,
                              {
                                  {1, BreakHandler::StepNext},  // I32Const
                                  {3, BreakHandler::StepNext},  // I32Const
                                  {5, BreakHandler::Continue}   // I32Add
                              });
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    MaybeHandle<Object> retval =
        Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
    CHECK_EQ(14, GetIntReturnValue(retval));
  }
  
  WASM_COMPILED_EXEC_TEST(WasmStepInAndOut) {
    WasmRunner<int, int> runner(execution_tier);
    runner.TierDown();
    WasmFunctionCompiler& f2 = runner.NewFunction<void>();
    f2.AllocateLocal(kWasmI32);
  
    // Call f2 via indirect call, because a direct call requires f2 to exist when
    // we compile main, but we need to compile main first so that the order of
    // functions in the code section matches the function indexes.
  
    // return arg0
    BUILD(runner, WASM_RETURN1(WASM_LOCAL_GET(0)));
    // for (int i = 0; i < 10; ++i) { f2(i); }
    BUILD(f2, WASM_LOOP(
                  WASM_BR_IF(0, WASM_BINOP(kExprI32GeU, WASM_LOCAL_GET(0),
                                           WASM_I32V_1(10))),
                  WASM_LOCAL_SET(
                      0, WASM_BINOP(kExprI32Sub, WASM_LOCAL_GET(0), WASM_ONE)),
                  WASM_CALL_FUNCTION(runner.function_index(), WASM_LOCAL_GET(0)),
                  WASM_DROP, WASM_BR(1)));
  
    Isolate* isolate = runner.main_isolate();
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(f2.function_index());
  
    // Set first breakpoint on the LocalGet (offset 19) before the Call.
    SetBreakpoint(&runner, f2.function_index(), 19, 19);
  
    BreakHandler count_breaks(isolate,
                              {
                                  {19, BreakHandler::StepIn},   // LocalGet
                                  {21, BreakHandler::StepIn},   // Call
                                  {1, BreakHandler::StepOut},   // in f2
                                  {23, BreakHandler::Continue}  // After Call
                              });
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    CHECK(!Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr)
               .is_null());
  }
  
  WASM_COMPILED_EXEC_TEST(WasmGetLocalsAndStack) {
    WasmRunner<void, int> runner(execution_tier);
    runner.AllocateLocal(kWasmI64);
    runner.AllocateLocal(kWasmF32);
    runner.AllocateLocal(kWasmF64);
  
    BUILD(runner,
          // set [1] to 17
          WASM_LOCAL_SET(1, WASM_I64V_1(17)),
          // set [2] to <arg0> = 7
          WASM_LOCAL_SET(2, WASM_F32_SCONVERT_I32(WASM_LOCAL_GET(0))),
          // set [3] to <arg1>/2 = 8.5
          WASM_LOCAL_SET(3, WASM_F64_DIV(WASM_F64_SCONVERT_I64(WASM_LOCAL_GET(1)),
                                         WASM_F64(2))));
  
    Isolate* isolate = runner.main_isolate();
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
  
    // Set breakpoint at the first instruction (7 bytes for local decls: num
    // entries + 3x<count, type>).
    SetBreakpoint(&runner, runner.function_index(), 7, 7);
  
    CollectValuesBreakHandler break_handler(
        isolate,
        {
            // params + locals          stack
            {wasmVec(7, 0L, 0.f, 0.), wasmVec()},          // 0: i64.const[17]
            {wasmVec(7, 0L, 0.f, 0.), wasmVec(17L)},       // 1: set_local[1]
            {wasmVec(7, 17L, 0.f, 0.), wasmVec()},         // 2: get_local[0]
            {wasmVec(7, 17L, 0.f, 0.), wasmVec(7)},        // 3: f32.convert_s
            {wasmVec(7, 17L, 0.f, 0.), wasmVec(7.f)},      // 4: set_local[2]
            {wasmVec(7, 17L, 7.f, 0.), wasmVec()},         // 5: get_local[1]
            {wasmVec(7, 17L, 7.f, 0.), wasmVec(17L)},      // 6: f64.convert_s
            {wasmVec(7, 17L, 7.f, 0.), wasmVec(17.)},      // 7: f64.const[2]
            {wasmVec(7, 17L, 7.f, 0.), wasmVec(17., 2.)},  // 8: f64.div
            {wasmVec(7, 17L, 7.f, 0.), wasmVec(8.5)},      // 9: set_local[3]
            {wasmVec(7, 17L, 7.f, 8.5), wasmVec()},        // 10: end
        });
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    Handle<Object> args[]{handle(Smi::FromInt(7), isolate)};
    CHECK(!Execution::Call(isolate, main_fun_wrapper, global, 1, args).is_null());
  }
  
  WASM_COMPILED_EXEC_TEST(WasmRemoveBreakPoint) {
    WasmRunner<int> runner(execution_tier);
    Isolate* isolate = runner.main_isolate();
  
    BUILD(runner, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP,
          WASM_I32V_1(14));
  
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
  
    SetBreakpoint(&runner, runner.function_index(), 1, 1);
    SetBreakpoint(&runner, runner.function_index(), 2, 2);
    Handle<BreakPoint> to_delete =
        SetBreakpoint(&runner, runner.function_index(), 3, 3);
    SetBreakpoint(&runner, runner.function_index(), 4, 4);
  
    BreakHandler count_breaks(isolate, {{1, BreakHandler::Continue},
                                        {2, BreakHandler::Continue,
                                         [&runner, &to_delete]() {
                                           ClearBreakpoint(
                                               &runner, runner.function_index(),
                                               3, to_delete);
                                         }},
                                        {4, BreakHandler::Continue}});
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    MaybeHandle<Object> retval =
        Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
    CHECK_EQ(14, GetIntReturnValue(retval));
  }
  
  WASM_COMPILED_EXEC_TEST(WasmRemoveLastBreakPoint) {
    WasmRunner<int> runner(execution_tier);
    Isolate* isolate = runner.main_isolate();
  
    BUILD(runner, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP,
          WASM_I32V_1(14));
  
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
  
    SetBreakpoint(&runner, runner.function_index(), 1, 1);
    SetBreakpoint(&runner, runner.function_index(), 2, 2);
    Handle<BreakPoint> to_delete =
        SetBreakpoint(&runner, runner.function_index(), 3, 3);
  
    BreakHandler count_breaks(
        isolate, {{1, BreakHandler::Continue},
                  {2, BreakHandler::Continue, [&runner, &to_delete]() {
                     ClearBreakpoint(&runner, runner.function_index(), 3,
                                     to_delete);
                   }}});
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    MaybeHandle<Object> retval =
        Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
    CHECK_EQ(14, GetIntReturnValue(retval));
  }
  
  WASM_COMPILED_EXEC_TEST(WasmRemoveAllBreakPoint) {
    WasmRunner<int> runner(execution_tier);
    Isolate* isolate = runner.main_isolate();
  
    BUILD(runner, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP,
          WASM_I32V_1(14));
  
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
  
    Handle<BreakPoint> bp1 =
        SetBreakpoint(&runner, runner.function_index(), 1, 1);
    Handle<BreakPoint> bp2 =
        SetBreakpoint(&runner, runner.function_index(), 2, 2);
    Handle<BreakPoint> bp3 =
        SetBreakpoint(&runner, runner.function_index(), 3, 3);
  
    BreakHandler count_breaks(
        isolate, {{1, BreakHandler::Continue, [&runner, &bp1, &bp2, &bp3]() {
                     ClearBreakpoint(&runner, runner.function_index(), 1, bp1);
                     ClearBreakpoint(&runner, runner.function_index(), 3, bp3);
                     ClearBreakpoint(&runner, runner.function_index(), 2, bp2);
                   }}});
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    MaybeHandle<Object> retval =
        Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
    CHECK_EQ(14, GetIntReturnValue(retval));
  }
  
  WASM_COMPILED_EXEC_TEST(WasmBreakInPostMVP) {
    // This test checks that we don't fail if experimental / post-MVP opcodes are
    // being used. There was a bug where we were trying to update the "detected"
    // features set, but we were passing a nullptr when compiling with
    // breakpoints.
    EXPERIMENTAL_FLAG_SCOPE(mv);
    WasmRunner<int> runner(execution_tier);
    Isolate* isolate = runner.main_isolate();
  
    // [] -> [i32, i32]
    ValueType sig_types[] = {kWasmI32, kWasmI32};
    FunctionSig sig{2, 0, sig_types};
    uint8_t sig_idx = runner.builder().AddSignature(&sig);
  
    constexpr int kReturn = 13;
    constexpr int kIgnored = 23;
    BUILD(runner,
          WASM_BLOCK_X(sig_idx, WASM_I32V_1(kReturn), WASM_I32V_1(kIgnored)),
          WASM_DROP);
  
    Handle<JSFunction> main_fun_wrapper =
        runner.builder().WrapCode(runner.function_index());
  
    SetBreakpoint(&runner, runner.function_index(), 3, 3);
  
    BreakHandler count_breaks(isolate, {{3, BreakHandler::Continue}});
  
    Handle<Object> global(isolate->context().global_object(), isolate);
    MaybeHandle<Object> retval =
        Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
    CHECK_EQ(kReturn, GetIntReturnValue(retval));
  }
  
  WASM_COMPILED_EXEC_TEST(Regress10889) {
    FLAG_SCOPE(print_wasm_code);
    WasmRunner<int> runner(execution_tier);
    BUILD(runner, WASM_I32V_1(0));
    SetBreakpoint(&runner, runner.function_index(), 1, 1);
  }
  
  }  // namespace wasm
  }  // namespace internal
  }  // namespace v8
  