xref: /third_party/node/deps/v8/src/wasm/wasm-debug.cc (revision 1cb0ef41)
11cb0ef41Sopenharmony_ci// Copyright 2016 the V8 project authors. All rights reserved.
21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be
31cb0ef41Sopenharmony_ci// found in the LICENSE file.
41cb0ef41Sopenharmony_ci
51cb0ef41Sopenharmony_ci#include "src/wasm/wasm-debug.h"
61cb0ef41Sopenharmony_ci
71cb0ef41Sopenharmony_ci#include <iomanip>
81cb0ef41Sopenharmony_ci#include <unordered_map>
91cb0ef41Sopenharmony_ci
101cb0ef41Sopenharmony_ci#include "src/base/optional.h"
111cb0ef41Sopenharmony_ci#include "src/base/platform/wrappers.h"
121cb0ef41Sopenharmony_ci#include "src/codegen/assembler-inl.h"
131cb0ef41Sopenharmony_ci#include "src/common/assert-scope.h"
141cb0ef41Sopenharmony_ci#include "src/compiler/wasm-compiler.h"
151cb0ef41Sopenharmony_ci#include "src/debug/debug-evaluate.h"
161cb0ef41Sopenharmony_ci#include "src/execution/frames-inl.h"
171cb0ef41Sopenharmony_ci#include "src/heap/factory.h"
181cb0ef41Sopenharmony_ci#include "src/wasm/baseline/liftoff-compiler.h"
191cb0ef41Sopenharmony_ci#include "src/wasm/baseline/liftoff-register.h"
201cb0ef41Sopenharmony_ci#include "src/wasm/module-decoder.h"
211cb0ef41Sopenharmony_ci#include "src/wasm/value-type.h"
221cb0ef41Sopenharmony_ci#include "src/wasm/wasm-code-manager.h"
231cb0ef41Sopenharmony_ci#include "src/wasm/wasm-engine.h"
241cb0ef41Sopenharmony_ci#include "src/wasm/wasm-limits.h"
251cb0ef41Sopenharmony_ci#include "src/wasm/wasm-module.h"
261cb0ef41Sopenharmony_ci#include "src/wasm/wasm-objects-inl.h"
271cb0ef41Sopenharmony_ci#include "src/wasm/wasm-opcodes-inl.h"
281cb0ef41Sopenharmony_ci#include "src/wasm/wasm-subtyping.h"
291cb0ef41Sopenharmony_ci#include "src/wasm/wasm-value.h"
301cb0ef41Sopenharmony_ci#include "src/zone/accounting-allocator.h"
311cb0ef41Sopenharmony_ci
321cb0ef41Sopenharmony_cinamespace v8 {
331cb0ef41Sopenharmony_cinamespace internal {
341cb0ef41Sopenharmony_cinamespace wasm {
351cb0ef41Sopenharmony_ci
361cb0ef41Sopenharmony_cinamespace {
371cb0ef41Sopenharmony_ci
381cb0ef41Sopenharmony_ciusing ImportExportKey = std::pair<ImportExportKindCode, uint32_t>;
391cb0ef41Sopenharmony_ci
401cb0ef41Sopenharmony_cienum ReturnLocation { kAfterBreakpoint, kAfterWasmCall };
411cb0ef41Sopenharmony_ci
421cb0ef41Sopenharmony_ciAddress FindNewPC(WasmFrame* frame, WasmCode* wasm_code, int byte_offset,
431cb0ef41Sopenharmony_ci                  ReturnLocation return_location) {
441cb0ef41Sopenharmony_ci  base::Vector<const uint8_t> new_pos_table = wasm_code->source_positions();
451cb0ef41Sopenharmony_ci
461cb0ef41Sopenharmony_ci  DCHECK_LE(0, byte_offset);
471cb0ef41Sopenharmony_ci
481cb0ef41Sopenharmony_ci  // Find the size of the call instruction by computing the distance from the
491cb0ef41Sopenharmony_ci  // source position entry to the return address.
501cb0ef41Sopenharmony_ci  WasmCode* old_code = frame->wasm_code();
511cb0ef41Sopenharmony_ci  int pc_offset = static_cast<int>(frame->pc() - old_code->instruction_start());
521cb0ef41Sopenharmony_ci  base::Vector<const uint8_t> old_pos_table = old_code->source_positions();
531cb0ef41Sopenharmony_ci  SourcePositionTableIterator old_it(old_pos_table);
541cb0ef41Sopenharmony_ci  int call_offset = -1;
551cb0ef41Sopenharmony_ci  while (!old_it.done() && old_it.code_offset() < pc_offset) {
561cb0ef41Sopenharmony_ci    call_offset = old_it.code_offset();
571cb0ef41Sopenharmony_ci    old_it.Advance();
581cb0ef41Sopenharmony_ci  }
591cb0ef41Sopenharmony_ci  DCHECK_LE(0, call_offset);
601cb0ef41Sopenharmony_ci  int call_instruction_size = pc_offset - call_offset;
611cb0ef41Sopenharmony_ci
621cb0ef41Sopenharmony_ci  // If {return_location == kAfterBreakpoint} we search for the first code
631cb0ef41Sopenharmony_ci  // offset which is marked as instruction (i.e. not the breakpoint).
641cb0ef41Sopenharmony_ci  // If {return_location == kAfterWasmCall} we return the last code offset
651cb0ef41Sopenharmony_ci  // associated with the byte offset.
661cb0ef41Sopenharmony_ci  SourcePositionTableIterator it(new_pos_table);
671cb0ef41Sopenharmony_ci  while (!it.done() && it.source_position().ScriptOffset() != byte_offset) {
681cb0ef41Sopenharmony_ci    it.Advance();
691cb0ef41Sopenharmony_ci  }
701cb0ef41Sopenharmony_ci  if (return_location == kAfterBreakpoint) {
711cb0ef41Sopenharmony_ci    while (!it.is_statement()) it.Advance();
721cb0ef41Sopenharmony_ci    DCHECK_EQ(byte_offset, it.source_position().ScriptOffset());
731cb0ef41Sopenharmony_ci    return wasm_code->instruction_start() + it.code_offset() +
741cb0ef41Sopenharmony_ci           call_instruction_size;
751cb0ef41Sopenharmony_ci  }
761cb0ef41Sopenharmony_ci
771cb0ef41Sopenharmony_ci  DCHECK_EQ(kAfterWasmCall, return_location);
781cb0ef41Sopenharmony_ci  int code_offset;
791cb0ef41Sopenharmony_ci  do {
801cb0ef41Sopenharmony_ci    code_offset = it.code_offset();
811cb0ef41Sopenharmony_ci    it.Advance();
821cb0ef41Sopenharmony_ci  } while (!it.done() && it.source_position().ScriptOffset() == byte_offset);
831cb0ef41Sopenharmony_ci  return wasm_code->instruction_start() + code_offset + call_instruction_size;
841cb0ef41Sopenharmony_ci}
851cb0ef41Sopenharmony_ci
861cb0ef41Sopenharmony_ci}  // namespace
871cb0ef41Sopenharmony_ci
881cb0ef41Sopenharmony_civoid DebugSideTable::Print(std::ostream& os) const {
891cb0ef41Sopenharmony_ci  os << "Debug side table (" << num_locals_ << " locals, " << entries_.size()
901cb0ef41Sopenharmony_ci     << " entries):\n";
911cb0ef41Sopenharmony_ci  for (auto& entry : entries_) entry.Print(os);
921cb0ef41Sopenharmony_ci  os << "\n";
931cb0ef41Sopenharmony_ci}
941cb0ef41Sopenharmony_ci
951cb0ef41Sopenharmony_civoid DebugSideTable::Entry::Print(std::ostream& os) const {
961cb0ef41Sopenharmony_ci  os << std::setw(6) << std::hex << pc_offset_ << std::dec << " stack height "
971cb0ef41Sopenharmony_ci     << stack_height_ << " [";
981cb0ef41Sopenharmony_ci  for (auto& value : changed_values_) {
991cb0ef41Sopenharmony_ci    os << " " << value.type.name() << ":";
1001cb0ef41Sopenharmony_ci    switch (value.storage) {
1011cb0ef41Sopenharmony_ci      case kConstant:
1021cb0ef41Sopenharmony_ci        os << "const#" << value.i32_const;
1031cb0ef41Sopenharmony_ci        break;
1041cb0ef41Sopenharmony_ci      case kRegister:
1051cb0ef41Sopenharmony_ci        os << "reg#" << value.reg_code;
1061cb0ef41Sopenharmony_ci        break;
1071cb0ef41Sopenharmony_ci      case kStack:
1081cb0ef41Sopenharmony_ci        os << "stack#" << value.stack_offset;
1091cb0ef41Sopenharmony_ci        break;
1101cb0ef41Sopenharmony_ci    }
1111cb0ef41Sopenharmony_ci  }
1121cb0ef41Sopenharmony_ci  os << " ]\n";
1131cb0ef41Sopenharmony_ci}
1141cb0ef41Sopenharmony_ci
1151cb0ef41Sopenharmony_ciclass DebugInfoImpl {
1161cb0ef41Sopenharmony_ci public:
1171cb0ef41Sopenharmony_ci  explicit DebugInfoImpl(NativeModule* native_module)
1181cb0ef41Sopenharmony_ci      : native_module_(native_module) {}
1191cb0ef41Sopenharmony_ci
1201cb0ef41Sopenharmony_ci  DebugInfoImpl(const DebugInfoImpl&) = delete;
1211cb0ef41Sopenharmony_ci  DebugInfoImpl& operator=(const DebugInfoImpl&) = delete;
1221cb0ef41Sopenharmony_ci
1231cb0ef41Sopenharmony_ci  int GetNumLocals(Address pc) {
1241cb0ef41Sopenharmony_ci    FrameInspectionScope scope(this, pc);
1251cb0ef41Sopenharmony_ci    if (!scope.is_inspectable()) return 0;
1261cb0ef41Sopenharmony_ci    return scope.debug_side_table->num_locals();
1271cb0ef41Sopenharmony_ci  }
1281cb0ef41Sopenharmony_ci
1291cb0ef41Sopenharmony_ci  WasmValue GetLocalValue(int local, Address pc, Address fp,
1301cb0ef41Sopenharmony_ci                          Address debug_break_fp, Isolate* isolate) {
1311cb0ef41Sopenharmony_ci    FrameInspectionScope scope(this, pc);
1321cb0ef41Sopenharmony_ci    return GetValue(scope.debug_side_table, scope.debug_side_table_entry, local,
1331cb0ef41Sopenharmony_ci                    fp, debug_break_fp, isolate);
1341cb0ef41Sopenharmony_ci  }
1351cb0ef41Sopenharmony_ci
1361cb0ef41Sopenharmony_ci  int GetStackDepth(Address pc) {
1371cb0ef41Sopenharmony_ci    FrameInspectionScope scope(this, pc);
1381cb0ef41Sopenharmony_ci    if (!scope.is_inspectable()) return 0;
1391cb0ef41Sopenharmony_ci    int num_locals = scope.debug_side_table->num_locals();
1401cb0ef41Sopenharmony_ci    int stack_height = scope.debug_side_table_entry->stack_height();
1411cb0ef41Sopenharmony_ci    return stack_height - num_locals;
1421cb0ef41Sopenharmony_ci  }
1431cb0ef41Sopenharmony_ci
1441cb0ef41Sopenharmony_ci  WasmValue GetStackValue(int index, Address pc, Address fp,
1451cb0ef41Sopenharmony_ci                          Address debug_break_fp, Isolate* isolate) {
1461cb0ef41Sopenharmony_ci    FrameInspectionScope scope(this, pc);
1471cb0ef41Sopenharmony_ci    int num_locals = scope.debug_side_table->num_locals();
1481cb0ef41Sopenharmony_ci    int value_count = scope.debug_side_table_entry->stack_height();
1491cb0ef41Sopenharmony_ci    if (num_locals + index >= value_count) return {};
1501cb0ef41Sopenharmony_ci    return GetValue(scope.debug_side_table, scope.debug_side_table_entry,
1511cb0ef41Sopenharmony_ci                    num_locals + index, fp, debug_break_fp, isolate);
1521cb0ef41Sopenharmony_ci  }
1531cb0ef41Sopenharmony_ci
1541cb0ef41Sopenharmony_ci  const WasmFunction& GetFunctionAtAddress(Address pc) {
1551cb0ef41Sopenharmony_ci    FrameInspectionScope scope(this, pc);
1561cb0ef41Sopenharmony_ci    auto* module = native_module_->module();
1571cb0ef41Sopenharmony_ci    return module->functions[scope.code->index()];
1581cb0ef41Sopenharmony_ci  }
1591cb0ef41Sopenharmony_ci
1601cb0ef41Sopenharmony_ci  WireBytesRef GetExportName(ImportExportKindCode kind, uint32_t index) {
1611cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
1621cb0ef41Sopenharmony_ci    if (!export_names_) {
1631cb0ef41Sopenharmony_ci      export_names_ =
1641cb0ef41Sopenharmony_ci          std::make_unique<std::map<ImportExportKey, WireBytesRef>>();
1651cb0ef41Sopenharmony_ci      for (auto exp : native_module_->module()->export_table) {
1661cb0ef41Sopenharmony_ci        auto exp_key = std::make_pair(exp.kind, exp.index);
1671cb0ef41Sopenharmony_ci        if (export_names_->find(exp_key) != export_names_->end()) continue;
1681cb0ef41Sopenharmony_ci        export_names_->insert(std::make_pair(exp_key, exp.name));
1691cb0ef41Sopenharmony_ci      }
1701cb0ef41Sopenharmony_ci    }
1711cb0ef41Sopenharmony_ci    auto it = export_names_->find(std::make_pair(kind, index));
1721cb0ef41Sopenharmony_ci    if (it != export_names_->end()) return it->second;
1731cb0ef41Sopenharmony_ci    return {};
1741cb0ef41Sopenharmony_ci  }
1751cb0ef41Sopenharmony_ci
1761cb0ef41Sopenharmony_ci  std::pair<WireBytesRef, WireBytesRef> GetImportName(ImportExportKindCode kind,
1771cb0ef41Sopenharmony_ci                                                      uint32_t index) {
1781cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
1791cb0ef41Sopenharmony_ci    if (!import_names_) {
1801cb0ef41Sopenharmony_ci      import_names_ = std::make_unique<
1811cb0ef41Sopenharmony_ci          std::map<ImportExportKey, std::pair<WireBytesRef, WireBytesRef>>>();
1821cb0ef41Sopenharmony_ci      for (auto imp : native_module_->module()->import_table) {
1831cb0ef41Sopenharmony_ci        import_names_->insert(
1841cb0ef41Sopenharmony_ci            std::make_pair(std::make_pair(imp.kind, imp.index),
1851cb0ef41Sopenharmony_ci                           std::make_pair(imp.module_name, imp.field_name)));
1861cb0ef41Sopenharmony_ci      }
1871cb0ef41Sopenharmony_ci    }
1881cb0ef41Sopenharmony_ci    auto it = import_names_->find(std::make_pair(kind, index));
1891cb0ef41Sopenharmony_ci    if (it != import_names_->end()) return it->second;
1901cb0ef41Sopenharmony_ci    return {};
1911cb0ef41Sopenharmony_ci  }
1921cb0ef41Sopenharmony_ci
1931cb0ef41Sopenharmony_ci  WireBytesRef GetTypeName(int type_index) {
1941cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
1951cb0ef41Sopenharmony_ci    if (!type_names_) {
1961cb0ef41Sopenharmony_ci      type_names_ = std::make_unique<NameMap>(DecodeNameMap(
1971cb0ef41Sopenharmony_ci          native_module_->wire_bytes(), NameSectionKindCode::kTypeCode));
1981cb0ef41Sopenharmony_ci    }
1991cb0ef41Sopenharmony_ci    return type_names_->GetName(type_index);
2001cb0ef41Sopenharmony_ci  }
2011cb0ef41Sopenharmony_ci
2021cb0ef41Sopenharmony_ci  WireBytesRef GetLocalName(int func_index, int local_index) {
2031cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
2041cb0ef41Sopenharmony_ci    if (!local_names_) {
2051cb0ef41Sopenharmony_ci      local_names_ = std::make_unique<IndirectNameMap>(DecodeIndirectNameMap(
2061cb0ef41Sopenharmony_ci          native_module_->wire_bytes(), NameSectionKindCode::kLocalCode));
2071cb0ef41Sopenharmony_ci    }
2081cb0ef41Sopenharmony_ci    return local_names_->GetName(func_index, local_index);
2091cb0ef41Sopenharmony_ci  }
2101cb0ef41Sopenharmony_ci
2111cb0ef41Sopenharmony_ci  WireBytesRef GetFieldName(int struct_index, int field_index) {
2121cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
2131cb0ef41Sopenharmony_ci    if (!field_names_) {
2141cb0ef41Sopenharmony_ci      field_names_ = std::make_unique<IndirectNameMap>(DecodeIndirectNameMap(
2151cb0ef41Sopenharmony_ci          native_module_->wire_bytes(), NameSectionKindCode::kFieldCode));
2161cb0ef41Sopenharmony_ci    }
2171cb0ef41Sopenharmony_ci    return field_names_->GetName(struct_index, field_index);
2181cb0ef41Sopenharmony_ci  }
2191cb0ef41Sopenharmony_ci
2201cb0ef41Sopenharmony_ci  // If the frame position is not in the list of breakpoints, return that
2211cb0ef41Sopenharmony_ci  // position. Return 0 otherwise.
2221cb0ef41Sopenharmony_ci  // This is used to generate a "dead breakpoint" in Liftoff, which is necessary
2231cb0ef41Sopenharmony_ci  // for OSR to find the correct return address.
2241cb0ef41Sopenharmony_ci  int DeadBreakpoint(WasmFrame* frame, base::Vector<const int> breakpoints) {
2251cb0ef41Sopenharmony_ci    const auto& function =
2261cb0ef41Sopenharmony_ci        native_module_->module()->functions[frame->function_index()];
2271cb0ef41Sopenharmony_ci    int offset = frame->position() - function.code.offset();
2281cb0ef41Sopenharmony_ci    if (std::binary_search(breakpoints.begin(), breakpoints.end(), offset)) {
2291cb0ef41Sopenharmony_ci      return 0;
2301cb0ef41Sopenharmony_ci    }
2311cb0ef41Sopenharmony_ci    return offset;
2321cb0ef41Sopenharmony_ci  }
2331cb0ef41Sopenharmony_ci
2341cb0ef41Sopenharmony_ci  // Find the dead breakpoint (see above) for the top wasm frame, if that frame
2351cb0ef41Sopenharmony_ci  // is in the function of the given index.
2361cb0ef41Sopenharmony_ci  int DeadBreakpoint(int func_index, base::Vector<const int> breakpoints,
2371cb0ef41Sopenharmony_ci                     Isolate* isolate) {
2381cb0ef41Sopenharmony_ci    StackTraceFrameIterator it(isolate);
2391cb0ef41Sopenharmony_ci    if (it.done() || !it.is_wasm()) return 0;
2401cb0ef41Sopenharmony_ci    auto* wasm_frame = WasmFrame::cast(it.frame());
2411cb0ef41Sopenharmony_ci    if (static_cast<int>(wasm_frame->function_index()) != func_index) return 0;
2421cb0ef41Sopenharmony_ci    return DeadBreakpoint(wasm_frame, breakpoints);
2431cb0ef41Sopenharmony_ci  }
2441cb0ef41Sopenharmony_ci
2451cb0ef41Sopenharmony_ci  WasmCode* RecompileLiftoffWithBreakpoints(int func_index,
2461cb0ef41Sopenharmony_ci                                            base::Vector<const int> offsets,
2471cb0ef41Sopenharmony_ci                                            int dead_breakpoint) {
2481cb0ef41Sopenharmony_ci    DCHECK(!mutex_.TryLock());  // Mutex is held externally.
2491cb0ef41Sopenharmony_ci
2501cb0ef41Sopenharmony_ci    ForDebugging for_debugging = offsets.size() == 1 && offsets[0] == 0
2511cb0ef41Sopenharmony_ci                                     ? kForStepping
2521cb0ef41Sopenharmony_ci                                     : kWithBreakpoints;
2531cb0ef41Sopenharmony_ci
2541cb0ef41Sopenharmony_ci    // Check the cache first.
2551cb0ef41Sopenharmony_ci    for (auto begin = cached_debugging_code_.begin(), it = begin,
2561cb0ef41Sopenharmony_ci              end = cached_debugging_code_.end();
2571cb0ef41Sopenharmony_ci         it != end; ++it) {
2581cb0ef41Sopenharmony_ci      if (it->func_index == func_index &&
2591cb0ef41Sopenharmony_ci          it->breakpoint_offsets.as_vector() == offsets &&
2601cb0ef41Sopenharmony_ci          it->dead_breakpoint == dead_breakpoint) {
2611cb0ef41Sopenharmony_ci        // Rotate the cache entry to the front (for LRU).
2621cb0ef41Sopenharmony_ci        for (; it != begin; --it) std::iter_swap(it, it - 1);
2631cb0ef41Sopenharmony_ci        if (for_debugging == kWithBreakpoints) {
2641cb0ef41Sopenharmony_ci          // Re-install the code, in case it was replaced in the meantime.
2651cb0ef41Sopenharmony_ci          native_module_->ReinstallDebugCode(it->code);
2661cb0ef41Sopenharmony_ci        }
2671cb0ef41Sopenharmony_ci        return it->code;
2681cb0ef41Sopenharmony_ci      }
2691cb0ef41Sopenharmony_ci    }
2701cb0ef41Sopenharmony_ci
2711cb0ef41Sopenharmony_ci    // Recompile the function with Liftoff, setting the new breakpoints.
2721cb0ef41Sopenharmony_ci    // Not thread-safe. The caller is responsible for locking {mutex_}.
2731cb0ef41Sopenharmony_ci    CompilationEnv env = native_module_->CreateCompilationEnv();
2741cb0ef41Sopenharmony_ci    auto* function = &native_module_->module()->functions[func_index];
2751cb0ef41Sopenharmony_ci    base::Vector<const uint8_t> wire_bytes = native_module_->wire_bytes();
2761cb0ef41Sopenharmony_ci    FunctionBody body{function->sig, function->code.offset(),
2771cb0ef41Sopenharmony_ci                      wire_bytes.begin() + function->code.offset(),
2781cb0ef41Sopenharmony_ci                      wire_bytes.begin() + function->code.end_offset()};
2791cb0ef41Sopenharmony_ci    std::unique_ptr<DebugSideTable> debug_sidetable;
2801cb0ef41Sopenharmony_ci
2811cb0ef41Sopenharmony_ci    // Debug side tables for stepping are generated lazily.
2821cb0ef41Sopenharmony_ci    bool generate_debug_sidetable = for_debugging == kWithBreakpoints;
2831cb0ef41Sopenharmony_ci    WasmCompilationResult result = ExecuteLiftoffCompilation(
2841cb0ef41Sopenharmony_ci        &env, body, func_index, for_debugging,
2851cb0ef41Sopenharmony_ci        LiftoffOptions{}
2861cb0ef41Sopenharmony_ci            .set_breakpoints(offsets)
2871cb0ef41Sopenharmony_ci            .set_dead_breakpoint(dead_breakpoint)
2881cb0ef41Sopenharmony_ci            .set_debug_sidetable(generate_debug_sidetable ? &debug_sidetable
2891cb0ef41Sopenharmony_ci                                                          : nullptr));
2901cb0ef41Sopenharmony_ci    // Liftoff compilation failure is a FATAL error. We rely on complete Liftoff
2911cb0ef41Sopenharmony_ci    // support for debugging.
2921cb0ef41Sopenharmony_ci    if (!result.succeeded()) FATAL("Liftoff compilation failed");
2931cb0ef41Sopenharmony_ci    DCHECK_EQ(generate_debug_sidetable, debug_sidetable != nullptr);
2941cb0ef41Sopenharmony_ci
2951cb0ef41Sopenharmony_ci    WasmCode* new_code = native_module_->PublishCode(
2961cb0ef41Sopenharmony_ci        native_module_->AddCompiledCode(std::move(result)));
2971cb0ef41Sopenharmony_ci
2981cb0ef41Sopenharmony_ci    DCHECK(new_code->is_inspectable());
2991cb0ef41Sopenharmony_ci    if (generate_debug_sidetable) {
3001cb0ef41Sopenharmony_ci      base::MutexGuard lock(&debug_side_tables_mutex_);
3011cb0ef41Sopenharmony_ci      DCHECK_EQ(0, debug_side_tables_.count(new_code));
3021cb0ef41Sopenharmony_ci      debug_side_tables_.emplace(new_code, std::move(debug_sidetable));
3031cb0ef41Sopenharmony_ci    }
3041cb0ef41Sopenharmony_ci
3051cb0ef41Sopenharmony_ci    // Insert new code into the cache. Insert before existing elements for LRU.
3061cb0ef41Sopenharmony_ci    cached_debugging_code_.insert(
3071cb0ef41Sopenharmony_ci        cached_debugging_code_.begin(),
3081cb0ef41Sopenharmony_ci        CachedDebuggingCode{func_index, base::OwnedVector<int>::Of(offsets),
3091cb0ef41Sopenharmony_ci                            dead_breakpoint, new_code});
3101cb0ef41Sopenharmony_ci    // Increase the ref count (for the cache entry).
3111cb0ef41Sopenharmony_ci    new_code->IncRef();
3121cb0ef41Sopenharmony_ci    // Remove exceeding element.
3131cb0ef41Sopenharmony_ci    if (cached_debugging_code_.size() > kMaxCachedDebuggingCode) {
3141cb0ef41Sopenharmony_ci      // Put the code in the surrounding CodeRefScope to delay deletion until
3151cb0ef41Sopenharmony_ci      // after the mutex is released.
3161cb0ef41Sopenharmony_ci      WasmCodeRefScope::AddRef(cached_debugging_code_.back().code);
3171cb0ef41Sopenharmony_ci      cached_debugging_code_.back().code->DecRefOnLiveCode();
3181cb0ef41Sopenharmony_ci      cached_debugging_code_.pop_back();
3191cb0ef41Sopenharmony_ci    }
3201cb0ef41Sopenharmony_ci    DCHECK_GE(kMaxCachedDebuggingCode, cached_debugging_code_.size());
3211cb0ef41Sopenharmony_ci
3221cb0ef41Sopenharmony_ci    return new_code;
3231cb0ef41Sopenharmony_ci  }
3241cb0ef41Sopenharmony_ci
3251cb0ef41Sopenharmony_ci  void SetBreakpoint(int func_index, int offset, Isolate* isolate) {
3261cb0ef41Sopenharmony_ci    // Put the code ref scope outside of the mutex, so we don't unnecessarily
3271cb0ef41Sopenharmony_ci    // hold the mutex while freeing code.
3281cb0ef41Sopenharmony_ci    WasmCodeRefScope wasm_code_ref_scope;
3291cb0ef41Sopenharmony_ci
3301cb0ef41Sopenharmony_ci    // Hold the mutex while modifying breakpoints, to ensure consistency when
3311cb0ef41Sopenharmony_ci    // multiple isolates set/remove breakpoints at the same time.
3321cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
3331cb0ef41Sopenharmony_ci
3341cb0ef41Sopenharmony_ci    // offset == 0 indicates flooding and should not happen here.
3351cb0ef41Sopenharmony_ci    DCHECK_NE(0, offset);
3361cb0ef41Sopenharmony_ci
3371cb0ef41Sopenharmony_ci    // Get the set of previously set breakpoints, to check later whether a new
3381cb0ef41Sopenharmony_ci    // breakpoint was actually added.
3391cb0ef41Sopenharmony_ci    std::vector<int> all_breakpoints = FindAllBreakpoints(func_index);
3401cb0ef41Sopenharmony_ci
3411cb0ef41Sopenharmony_ci    auto& isolate_data = per_isolate_data_[isolate];
3421cb0ef41Sopenharmony_ci    std::vector<int>& breakpoints =
3431cb0ef41Sopenharmony_ci        isolate_data.breakpoints_per_function[func_index];
3441cb0ef41Sopenharmony_ci    auto insertion_point =
3451cb0ef41Sopenharmony_ci        std::lower_bound(breakpoints.begin(), breakpoints.end(), offset);
3461cb0ef41Sopenharmony_ci    if (insertion_point != breakpoints.end() && *insertion_point == offset) {
3471cb0ef41Sopenharmony_ci      // The breakpoint is already set for this isolate.
3481cb0ef41Sopenharmony_ci      return;
3491cb0ef41Sopenharmony_ci    }
3501cb0ef41Sopenharmony_ci    breakpoints.insert(insertion_point, offset);
3511cb0ef41Sopenharmony_ci
3521cb0ef41Sopenharmony_ci    DCHECK(std::is_sorted(all_breakpoints.begin(), all_breakpoints.end()));
3531cb0ef41Sopenharmony_ci    // Find the insertion position within {all_breakpoints}.
3541cb0ef41Sopenharmony_ci    insertion_point = std::lower_bound(all_breakpoints.begin(),
3551cb0ef41Sopenharmony_ci                                       all_breakpoints.end(), offset);
3561cb0ef41Sopenharmony_ci    bool breakpoint_exists =
3571cb0ef41Sopenharmony_ci        insertion_point != all_breakpoints.end() && *insertion_point == offset;
3581cb0ef41Sopenharmony_ci    // If the breakpoint was already set before, then we can just reuse the old
3591cb0ef41Sopenharmony_ci    // code. Otherwise, recompile it. In any case, rewrite this isolate's stack
3601cb0ef41Sopenharmony_ci    // to make sure that it uses up-to-date code containing the breakpoint.
3611cb0ef41Sopenharmony_ci    WasmCode* new_code;
3621cb0ef41Sopenharmony_ci    if (breakpoint_exists) {
3631cb0ef41Sopenharmony_ci      new_code = native_module_->GetCode(func_index);
3641cb0ef41Sopenharmony_ci    } else {
3651cb0ef41Sopenharmony_ci      all_breakpoints.insert(insertion_point, offset);
3661cb0ef41Sopenharmony_ci      int dead_breakpoint =
3671cb0ef41Sopenharmony_ci          DeadBreakpoint(func_index, base::VectorOf(all_breakpoints), isolate);
3681cb0ef41Sopenharmony_ci      new_code = RecompileLiftoffWithBreakpoints(
3691cb0ef41Sopenharmony_ci          func_index, base::VectorOf(all_breakpoints), dead_breakpoint);
3701cb0ef41Sopenharmony_ci    }
3711cb0ef41Sopenharmony_ci    UpdateReturnAddresses(isolate, new_code, isolate_data.stepping_frame);
3721cb0ef41Sopenharmony_ci  }
3731cb0ef41Sopenharmony_ci
3741cb0ef41Sopenharmony_ci  std::vector<int> FindAllBreakpoints(int func_index) {
3751cb0ef41Sopenharmony_ci    DCHECK(!mutex_.TryLock());  // Mutex must be held externally.
3761cb0ef41Sopenharmony_ci    std::set<int> breakpoints;
3771cb0ef41Sopenharmony_ci    for (auto& data : per_isolate_data_) {
3781cb0ef41Sopenharmony_ci      auto it = data.second.breakpoints_per_function.find(func_index);
3791cb0ef41Sopenharmony_ci      if (it == data.second.breakpoints_per_function.end()) continue;
3801cb0ef41Sopenharmony_ci      for (int offset : it->second) breakpoints.insert(offset);
3811cb0ef41Sopenharmony_ci    }
3821cb0ef41Sopenharmony_ci    return {breakpoints.begin(), breakpoints.end()};
3831cb0ef41Sopenharmony_ci  }
3841cb0ef41Sopenharmony_ci
3851cb0ef41Sopenharmony_ci  void UpdateBreakpoints(int func_index, base::Vector<int> breakpoints,
3861cb0ef41Sopenharmony_ci                         Isolate* isolate, StackFrameId stepping_frame,
3871cb0ef41Sopenharmony_ci                         int dead_breakpoint) {
3881cb0ef41Sopenharmony_ci    DCHECK(!mutex_.TryLock());  // Mutex is held externally.
3891cb0ef41Sopenharmony_ci    WasmCode* new_code = RecompileLiftoffWithBreakpoints(
3901cb0ef41Sopenharmony_ci        func_index, breakpoints, dead_breakpoint);
3911cb0ef41Sopenharmony_ci    UpdateReturnAddresses(isolate, new_code, stepping_frame);
3921cb0ef41Sopenharmony_ci  }
3931cb0ef41Sopenharmony_ci
3941cb0ef41Sopenharmony_ci  void FloodWithBreakpoints(WasmFrame* frame, ReturnLocation return_location) {
3951cb0ef41Sopenharmony_ci    // 0 is an invalid offset used to indicate flooding.
3961cb0ef41Sopenharmony_ci    constexpr int kFloodingBreakpoints[] = {0};
3971cb0ef41Sopenharmony_ci    DCHECK(frame->wasm_code()->is_liftoff());
3981cb0ef41Sopenharmony_ci    // Generate an additional source position for the current byte offset.
3991cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
4001cb0ef41Sopenharmony_ci    WasmCode* new_code = RecompileLiftoffWithBreakpoints(
4011cb0ef41Sopenharmony_ci        frame->function_index(), base::ArrayVector(kFloodingBreakpoints), 0);
4021cb0ef41Sopenharmony_ci    UpdateReturnAddress(frame, new_code, return_location);
4031cb0ef41Sopenharmony_ci
4041cb0ef41Sopenharmony_ci    per_isolate_data_[frame->isolate()].stepping_frame = frame->id();
4051cb0ef41Sopenharmony_ci  }
4061cb0ef41Sopenharmony_ci
4071cb0ef41Sopenharmony_ci  bool PrepareStep(WasmFrame* frame) {
4081cb0ef41Sopenharmony_ci    WasmCodeRefScope wasm_code_ref_scope;
4091cb0ef41Sopenharmony_ci    wasm::WasmCode* code = frame->wasm_code();
4101cb0ef41Sopenharmony_ci    if (!code->is_liftoff()) return false;  // Cannot step in TurboFan code.
4111cb0ef41Sopenharmony_ci    if (IsAtReturn(frame)) return false;    // Will return after this step.
4121cb0ef41Sopenharmony_ci    FloodWithBreakpoints(frame, kAfterBreakpoint);
4131cb0ef41Sopenharmony_ci    return true;
4141cb0ef41Sopenharmony_ci  }
4151cb0ef41Sopenharmony_ci
4161cb0ef41Sopenharmony_ci  void PrepareStepOutTo(WasmFrame* frame) {
4171cb0ef41Sopenharmony_ci    WasmCodeRefScope wasm_code_ref_scope;
4181cb0ef41Sopenharmony_ci    wasm::WasmCode* code = frame->wasm_code();
4191cb0ef41Sopenharmony_ci    if (!code->is_liftoff()) return;  // Cannot step out to TurboFan code.
4201cb0ef41Sopenharmony_ci    FloodWithBreakpoints(frame, kAfterWasmCall);
4211cb0ef41Sopenharmony_ci  }
4221cb0ef41Sopenharmony_ci
4231cb0ef41Sopenharmony_ci  void ClearStepping(WasmFrame* frame) {
4241cb0ef41Sopenharmony_ci    WasmCodeRefScope wasm_code_ref_scope;
4251cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
4261cb0ef41Sopenharmony_ci    auto* code = frame->wasm_code();
4271cb0ef41Sopenharmony_ci    if (code->for_debugging() != kForStepping) return;
4281cb0ef41Sopenharmony_ci    int func_index = code->index();
4291cb0ef41Sopenharmony_ci    std::vector<int> breakpoints = FindAllBreakpoints(func_index);
4301cb0ef41Sopenharmony_ci    int dead_breakpoint = DeadBreakpoint(frame, base::VectorOf(breakpoints));
4311cb0ef41Sopenharmony_ci    WasmCode* new_code = RecompileLiftoffWithBreakpoints(
4321cb0ef41Sopenharmony_ci        func_index, base::VectorOf(breakpoints), dead_breakpoint);
4331cb0ef41Sopenharmony_ci    UpdateReturnAddress(frame, new_code, kAfterBreakpoint);
4341cb0ef41Sopenharmony_ci  }
4351cb0ef41Sopenharmony_ci
4361cb0ef41Sopenharmony_ci  void ClearStepping(Isolate* isolate) {
4371cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
4381cb0ef41Sopenharmony_ci    auto it = per_isolate_data_.find(isolate);
4391cb0ef41Sopenharmony_ci    if (it != per_isolate_data_.end()) it->second.stepping_frame = NO_ID;
4401cb0ef41Sopenharmony_ci  }
4411cb0ef41Sopenharmony_ci
4421cb0ef41Sopenharmony_ci  bool IsStepping(WasmFrame* frame) {
4431cb0ef41Sopenharmony_ci    Isolate* isolate = frame->wasm_instance().GetIsolate();
4441cb0ef41Sopenharmony_ci    if (isolate->debug()->last_step_action() == StepInto) return true;
4451cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
4461cb0ef41Sopenharmony_ci    auto it = per_isolate_data_.find(isolate);
4471cb0ef41Sopenharmony_ci    return it != per_isolate_data_.end() &&
4481cb0ef41Sopenharmony_ci           it->second.stepping_frame == frame->id();
4491cb0ef41Sopenharmony_ci  }
4501cb0ef41Sopenharmony_ci
4511cb0ef41Sopenharmony_ci  void RemoveBreakpoint(int func_index, int position, Isolate* isolate) {
4521cb0ef41Sopenharmony_ci    // Put the code ref scope outside of the mutex, so we don't unnecessarily
4531cb0ef41Sopenharmony_ci    // hold the mutex while freeing code.
4541cb0ef41Sopenharmony_ci    WasmCodeRefScope wasm_code_ref_scope;
4551cb0ef41Sopenharmony_ci
4561cb0ef41Sopenharmony_ci    // Hold the mutex while modifying breakpoints, to ensure consistency when
4571cb0ef41Sopenharmony_ci    // multiple isolates set/remove breakpoints at the same time.
4581cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
4591cb0ef41Sopenharmony_ci
4601cb0ef41Sopenharmony_ci    const auto& function = native_module_->module()->functions[func_index];
4611cb0ef41Sopenharmony_ci    int offset = position - function.code.offset();
4621cb0ef41Sopenharmony_ci
4631cb0ef41Sopenharmony_ci    auto& isolate_data = per_isolate_data_[isolate];
4641cb0ef41Sopenharmony_ci    std::vector<int>& breakpoints =
4651cb0ef41Sopenharmony_ci        isolate_data.breakpoints_per_function[func_index];
4661cb0ef41Sopenharmony_ci    DCHECK_LT(0, offset);
4671cb0ef41Sopenharmony_ci    auto insertion_point =
4681cb0ef41Sopenharmony_ci        std::lower_bound(breakpoints.begin(), breakpoints.end(), offset);
4691cb0ef41Sopenharmony_ci    if (insertion_point == breakpoints.end()) return;
4701cb0ef41Sopenharmony_ci    if (*insertion_point != offset) return;
4711cb0ef41Sopenharmony_ci    breakpoints.erase(insertion_point);
4721cb0ef41Sopenharmony_ci
4731cb0ef41Sopenharmony_ci    std::vector<int> remaining = FindAllBreakpoints(func_index);
4741cb0ef41Sopenharmony_ci    // If the breakpoint is still set in another isolate, don't remove it.
4751cb0ef41Sopenharmony_ci    DCHECK(std::is_sorted(remaining.begin(), remaining.end()));
4761cb0ef41Sopenharmony_ci    if (std::binary_search(remaining.begin(), remaining.end(), offset)) return;
4771cb0ef41Sopenharmony_ci    int dead_breakpoint =
4781cb0ef41Sopenharmony_ci        DeadBreakpoint(func_index, base::VectorOf(remaining), isolate);
4791cb0ef41Sopenharmony_ci    UpdateBreakpoints(func_index, base::VectorOf(remaining), isolate,
4801cb0ef41Sopenharmony_ci                      isolate_data.stepping_frame, dead_breakpoint);
4811cb0ef41Sopenharmony_ci  }
4821cb0ef41Sopenharmony_ci
4831cb0ef41Sopenharmony_ci  void RemoveDebugSideTables(base::Vector<WasmCode* const> codes) {
4841cb0ef41Sopenharmony_ci    base::MutexGuard guard(&debug_side_tables_mutex_);
4851cb0ef41Sopenharmony_ci    for (auto* code : codes) {
4861cb0ef41Sopenharmony_ci      debug_side_tables_.erase(code);
4871cb0ef41Sopenharmony_ci    }
4881cb0ef41Sopenharmony_ci  }
4891cb0ef41Sopenharmony_ci
4901cb0ef41Sopenharmony_ci  DebugSideTable* GetDebugSideTableIfExists(const WasmCode* code) const {
4911cb0ef41Sopenharmony_ci    base::MutexGuard guard(&debug_side_tables_mutex_);
4921cb0ef41Sopenharmony_ci    auto it = debug_side_tables_.find(code);
4931cb0ef41Sopenharmony_ci    return it == debug_side_tables_.end() ? nullptr : it->second.get();
4941cb0ef41Sopenharmony_ci  }
4951cb0ef41Sopenharmony_ci
4961cb0ef41Sopenharmony_ci  static bool HasRemovedBreakpoints(const std::vector<int>& removed,
4971cb0ef41Sopenharmony_ci                                    const std::vector<int>& remaining) {
4981cb0ef41Sopenharmony_ci    DCHECK(std::is_sorted(remaining.begin(), remaining.end()));
4991cb0ef41Sopenharmony_ci    for (int offset : removed) {
5001cb0ef41Sopenharmony_ci      // Return true if we removed a breakpoint which is not part of remaining.
5011cb0ef41Sopenharmony_ci      if (!std::binary_search(remaining.begin(), remaining.end(), offset)) {
5021cb0ef41Sopenharmony_ci        return true;
5031cb0ef41Sopenharmony_ci      }
5041cb0ef41Sopenharmony_ci    }
5051cb0ef41Sopenharmony_ci    return false;
5061cb0ef41Sopenharmony_ci  }
5071cb0ef41Sopenharmony_ci
5081cb0ef41Sopenharmony_ci  void RemoveIsolate(Isolate* isolate) {
5091cb0ef41Sopenharmony_ci    // Put the code ref scope outside of the mutex, so we don't unnecessarily
5101cb0ef41Sopenharmony_ci    // hold the mutex while freeing code.
5111cb0ef41Sopenharmony_ci    WasmCodeRefScope wasm_code_ref_scope;
5121cb0ef41Sopenharmony_ci
5131cb0ef41Sopenharmony_ci    base::MutexGuard guard(&mutex_);
5141cb0ef41Sopenharmony_ci    auto per_isolate_data_it = per_isolate_data_.find(isolate);
5151cb0ef41Sopenharmony_ci    if (per_isolate_data_it == per_isolate_data_.end()) return;
5161cb0ef41Sopenharmony_ci    std::unordered_map<int, std::vector<int>> removed_per_function =
5171cb0ef41Sopenharmony_ci        std::move(per_isolate_data_it->second.breakpoints_per_function);
5181cb0ef41Sopenharmony_ci    per_isolate_data_.erase(per_isolate_data_it);
5191cb0ef41Sopenharmony_ci    for (auto& entry : removed_per_function) {
5201cb0ef41Sopenharmony_ci      int func_index = entry.first;
5211cb0ef41Sopenharmony_ci      std::vector<int>& removed = entry.second;
5221cb0ef41Sopenharmony_ci      std::vector<int> remaining = FindAllBreakpoints(func_index);
5231cb0ef41Sopenharmony_ci      if (HasRemovedBreakpoints(removed, remaining)) {
5241cb0ef41Sopenharmony_ci        RecompileLiftoffWithBreakpoints(func_index, base::VectorOf(remaining),
5251cb0ef41Sopenharmony_ci                                        0);
5261cb0ef41Sopenharmony_ci      }
5271cb0ef41Sopenharmony_ci    }
5281cb0ef41Sopenharmony_ci  }
5291cb0ef41Sopenharmony_ci
5301cb0ef41Sopenharmony_ci private:
5311cb0ef41Sopenharmony_ci  struct FrameInspectionScope {
5321cb0ef41Sopenharmony_ci    FrameInspectionScope(DebugInfoImpl* debug_info, Address pc)
5331cb0ef41Sopenharmony_ci        : code(wasm::GetWasmCodeManager()->LookupCode(pc)),
5341cb0ef41Sopenharmony_ci          pc_offset(static_cast<int>(pc - code->instruction_start())),
5351cb0ef41Sopenharmony_ci          debug_side_table(code->is_inspectable()
5361cb0ef41Sopenharmony_ci                               ? debug_info->GetDebugSideTable(code)
5371cb0ef41Sopenharmony_ci                               : nullptr),
5381cb0ef41Sopenharmony_ci          debug_side_table_entry(debug_side_table
5391cb0ef41Sopenharmony_ci                                     ? debug_side_table->GetEntry(pc_offset)
5401cb0ef41Sopenharmony_ci                                     : nullptr) {
5411cb0ef41Sopenharmony_ci      DCHECK_IMPLIES(code->is_inspectable(), debug_side_table_entry != nullptr);
5421cb0ef41Sopenharmony_ci    }
5431cb0ef41Sopenharmony_ci
5441cb0ef41Sopenharmony_ci    bool is_inspectable() const { return debug_side_table_entry; }
5451cb0ef41Sopenharmony_ci
5461cb0ef41Sopenharmony_ci    wasm::WasmCodeRefScope wasm_code_ref_scope;
5471cb0ef41Sopenharmony_ci    wasm::WasmCode* code;
5481cb0ef41Sopenharmony_ci    int pc_offset;
5491cb0ef41Sopenharmony_ci    const DebugSideTable* debug_side_table;
5501cb0ef41Sopenharmony_ci    const DebugSideTable::Entry* debug_side_table_entry;
5511cb0ef41Sopenharmony_ci  };
5521cb0ef41Sopenharmony_ci
5531cb0ef41Sopenharmony_ci  const DebugSideTable* GetDebugSideTable(WasmCode* code) {
5541cb0ef41Sopenharmony_ci    DCHECK(code->is_inspectable());
5551cb0ef41Sopenharmony_ci    {
5561cb0ef41Sopenharmony_ci      // Only hold the mutex temporarily. We can't hold it while generating the
5571cb0ef41Sopenharmony_ci      // debug side table, because compilation takes the {NativeModule} lock.
5581cb0ef41Sopenharmony_ci      base::MutexGuard guard(&debug_side_tables_mutex_);
5591cb0ef41Sopenharmony_ci      auto it = debug_side_tables_.find(code);
5601cb0ef41Sopenharmony_ci      if (it != debug_side_tables_.end()) return it->second.get();
5611cb0ef41Sopenharmony_ci    }
5621cb0ef41Sopenharmony_ci
5631cb0ef41Sopenharmony_ci    // Otherwise create the debug side table now.
5641cb0ef41Sopenharmony_ci    std::unique_ptr<DebugSideTable> debug_side_table =
5651cb0ef41Sopenharmony_ci        GenerateLiftoffDebugSideTable(code);
5661cb0ef41Sopenharmony_ci    DebugSideTable* ret = debug_side_table.get();
5671cb0ef41Sopenharmony_ci
5681cb0ef41Sopenharmony_ci    // Check cache again, maybe another thread concurrently generated a debug
5691cb0ef41Sopenharmony_ci    // side table already.
5701cb0ef41Sopenharmony_ci    {
5711cb0ef41Sopenharmony_ci      base::MutexGuard guard(&debug_side_tables_mutex_);
5721cb0ef41Sopenharmony_ci      auto& slot = debug_side_tables_[code];
5731cb0ef41Sopenharmony_ci      if (slot != nullptr) return slot.get();
5741cb0ef41Sopenharmony_ci      slot = std::move(debug_side_table);
5751cb0ef41Sopenharmony_ci    }
5761cb0ef41Sopenharmony_ci
5771cb0ef41Sopenharmony_ci    // Print the code together with the debug table, if requested.
5781cb0ef41Sopenharmony_ci    code->MaybePrint();
5791cb0ef41Sopenharmony_ci    return ret;
5801cb0ef41Sopenharmony_ci  }
5811cb0ef41Sopenharmony_ci
5821cb0ef41Sopenharmony_ci  // Get the value of a local (including parameters) or stack value. Stack
5831cb0ef41Sopenharmony_ci  // values follow the locals in the same index space.
5841cb0ef41Sopenharmony_ci  WasmValue GetValue(const DebugSideTable* debug_side_table,
5851cb0ef41Sopenharmony_ci                     const DebugSideTable::Entry* debug_side_table_entry,
5861cb0ef41Sopenharmony_ci                     int index, Address stack_frame_base,
5871cb0ef41Sopenharmony_ci                     Address debug_break_fp, Isolate* isolate) const {
5881cb0ef41Sopenharmony_ci    const auto* value =
5891cb0ef41Sopenharmony_ci        debug_side_table->FindValue(debug_side_table_entry, index);
5901cb0ef41Sopenharmony_ci    if (value->is_constant()) {
5911cb0ef41Sopenharmony_ci      DCHECK(value->type == kWasmI32 || value->type == kWasmI64);
5921cb0ef41Sopenharmony_ci      return value->type == kWasmI32 ? WasmValue(value->i32_const)
5931cb0ef41Sopenharmony_ci                                     : WasmValue(int64_t{value->i32_const});
5941cb0ef41Sopenharmony_ci    }
5951cb0ef41Sopenharmony_ci
5961cb0ef41Sopenharmony_ci    if (value->is_register()) {
5971cb0ef41Sopenharmony_ci      auto reg = LiftoffRegister::from_liftoff_code(value->reg_code);
5981cb0ef41Sopenharmony_ci      auto gp_addr = [debug_break_fp](Register reg) {
5991cb0ef41Sopenharmony_ci        return debug_break_fp +
6001cb0ef41Sopenharmony_ci               WasmDebugBreakFrameConstants::GetPushedGpRegisterOffset(
6011cb0ef41Sopenharmony_ci                   reg.code());
6021cb0ef41Sopenharmony_ci      };
6031cb0ef41Sopenharmony_ci      if (reg.is_gp_pair()) {
6041cb0ef41Sopenharmony_ci        DCHECK_EQ(kWasmI64, value->type);
6051cb0ef41Sopenharmony_ci        uint32_t low_word = ReadUnalignedValue<uint32_t>(gp_addr(reg.low_gp()));
6061cb0ef41Sopenharmony_ci        uint32_t high_word =
6071cb0ef41Sopenharmony_ci            ReadUnalignedValue<uint32_t>(gp_addr(reg.high_gp()));
6081cb0ef41Sopenharmony_ci        return WasmValue((uint64_t{high_word} << 32) | low_word);
6091cb0ef41Sopenharmony_ci      }
6101cb0ef41Sopenharmony_ci      if (reg.is_gp()) {
6111cb0ef41Sopenharmony_ci        if (value->type == kWasmI32) {
6121cb0ef41Sopenharmony_ci          return WasmValue(ReadUnalignedValue<uint32_t>(gp_addr(reg.gp())));
6131cb0ef41Sopenharmony_ci        } else if (value->type == kWasmI64) {
6141cb0ef41Sopenharmony_ci          return WasmValue(ReadUnalignedValue<uint64_t>(gp_addr(reg.gp())));
6151cb0ef41Sopenharmony_ci        } else if (value->type.is_reference()) {
6161cb0ef41Sopenharmony_ci          Handle<Object> obj(
6171cb0ef41Sopenharmony_ci              Object(ReadUnalignedValue<Address>(gp_addr(reg.gp()))), isolate);
6181cb0ef41Sopenharmony_ci          return WasmValue(obj, value->type);
6191cb0ef41Sopenharmony_ci        } else {
6201cb0ef41Sopenharmony_ci          UNREACHABLE();
6211cb0ef41Sopenharmony_ci        }
6221cb0ef41Sopenharmony_ci      }
6231cb0ef41Sopenharmony_ci      DCHECK(reg.is_fp() || reg.is_fp_pair());
6241cb0ef41Sopenharmony_ci      // ifdef here to workaround unreachable code for is_fp_pair.
6251cb0ef41Sopenharmony_ci#ifdef V8_TARGET_ARCH_ARM
6261cb0ef41Sopenharmony_ci      int code = reg.is_fp_pair() ? reg.low_fp().code() : reg.fp().code();
6271cb0ef41Sopenharmony_ci#else
6281cb0ef41Sopenharmony_ci      int code = reg.fp().code();
6291cb0ef41Sopenharmony_ci#endif
6301cb0ef41Sopenharmony_ci      Address spilled_addr =
6311cb0ef41Sopenharmony_ci          debug_break_fp +
6321cb0ef41Sopenharmony_ci          WasmDebugBreakFrameConstants::GetPushedFpRegisterOffset(code);
6331cb0ef41Sopenharmony_ci      if (value->type == kWasmF32) {
6341cb0ef41Sopenharmony_ci        return WasmValue(ReadUnalignedValue<float>(spilled_addr));
6351cb0ef41Sopenharmony_ci      } else if (value->type == kWasmF64) {
6361cb0ef41Sopenharmony_ci        return WasmValue(ReadUnalignedValue<double>(spilled_addr));
6371cb0ef41Sopenharmony_ci      } else if (value->type == kWasmS128) {
6381cb0ef41Sopenharmony_ci        return WasmValue(Simd128(ReadUnalignedValue<int16>(spilled_addr)));
6391cb0ef41Sopenharmony_ci      } else {
6401cb0ef41Sopenharmony_ci        // All other cases should have been handled above.
6411cb0ef41Sopenharmony_ci        UNREACHABLE();
6421cb0ef41Sopenharmony_ci      }
6431cb0ef41Sopenharmony_ci    }
6441cb0ef41Sopenharmony_ci
6451cb0ef41Sopenharmony_ci    // Otherwise load the value from the stack.
6461cb0ef41Sopenharmony_ci    Address stack_address = stack_frame_base - value->stack_offset;
6471cb0ef41Sopenharmony_ci    switch (value->type.kind()) {
6481cb0ef41Sopenharmony_ci      case kI32:
6491cb0ef41Sopenharmony_ci        return WasmValue(ReadUnalignedValue<int32_t>(stack_address));
6501cb0ef41Sopenharmony_ci      case kI64:
6511cb0ef41Sopenharmony_ci        return WasmValue(ReadUnalignedValue<int64_t>(stack_address));
6521cb0ef41Sopenharmony_ci      case kF32:
6531cb0ef41Sopenharmony_ci        return WasmValue(ReadUnalignedValue<float>(stack_address));
6541cb0ef41Sopenharmony_ci      case kF64:
6551cb0ef41Sopenharmony_ci        return WasmValue(ReadUnalignedValue<double>(stack_address));
6561cb0ef41Sopenharmony_ci      case kS128:
6571cb0ef41Sopenharmony_ci        return WasmValue(Simd128(ReadUnalignedValue<int16>(stack_address)));
6581cb0ef41Sopenharmony_ci      case kRef:
6591cb0ef41Sopenharmony_ci      case kOptRef:
6601cb0ef41Sopenharmony_ci      case kRtt: {
6611cb0ef41Sopenharmony_ci        Handle<Object> obj(Object(ReadUnalignedValue<Address>(stack_address)),
6621cb0ef41Sopenharmony_ci                           isolate);
6631cb0ef41Sopenharmony_ci        return WasmValue(obj, value->type);
6641cb0ef41Sopenharmony_ci      }
6651cb0ef41Sopenharmony_ci      case kI8:
6661cb0ef41Sopenharmony_ci      case kI16:
6671cb0ef41Sopenharmony_ci      case kVoid:
6681cb0ef41Sopenharmony_ci      case kBottom:
6691cb0ef41Sopenharmony_ci        UNREACHABLE();
6701cb0ef41Sopenharmony_ci    }
6711cb0ef41Sopenharmony_ci  }
6721cb0ef41Sopenharmony_ci
6731cb0ef41Sopenharmony_ci  // After installing a Liftoff code object with a different set of breakpoints,
6741cb0ef41Sopenharmony_ci  // update return addresses on the stack so that execution resumes in the new
6751cb0ef41Sopenharmony_ci  // code. The frame layout itself should be independent of breakpoints.
6761cb0ef41Sopenharmony_ci  void UpdateReturnAddresses(Isolate* isolate, WasmCode* new_code,
6771cb0ef41Sopenharmony_ci                             StackFrameId stepping_frame) {
6781cb0ef41Sopenharmony_ci    // The first return location is after the breakpoint, others are after wasm
6791cb0ef41Sopenharmony_ci    // calls.
6801cb0ef41Sopenharmony_ci    ReturnLocation return_location = kAfterBreakpoint;
6811cb0ef41Sopenharmony_ci    for (StackTraceFrameIterator it(isolate); !it.done();
6821cb0ef41Sopenharmony_ci         it.Advance(), return_location = kAfterWasmCall) {
6831cb0ef41Sopenharmony_ci      // We still need the flooded function for stepping.
6841cb0ef41Sopenharmony_ci      if (it.frame()->id() == stepping_frame) continue;
6851cb0ef41Sopenharmony_ci      if (!it.is_wasm()) continue;
6861cb0ef41Sopenharmony_ci      WasmFrame* frame = WasmFrame::cast(it.frame());
6871cb0ef41Sopenharmony_ci      if (frame->native_module() != new_code->native_module()) continue;
6881cb0ef41Sopenharmony_ci      if (frame->function_index() != new_code->index()) continue;
6891cb0ef41Sopenharmony_ci      if (!frame->wasm_code()->is_liftoff()) continue;
6901cb0ef41Sopenharmony_ci      UpdateReturnAddress(frame, new_code, return_location);
6911cb0ef41Sopenharmony_ci    }
6921cb0ef41Sopenharmony_ci  }
6931cb0ef41Sopenharmony_ci
6941cb0ef41Sopenharmony_ci  void UpdateReturnAddress(WasmFrame* frame, WasmCode* new_code,
6951cb0ef41Sopenharmony_ci                           ReturnLocation return_location) {
6961cb0ef41Sopenharmony_ci    DCHECK(new_code->is_liftoff());
6971cb0ef41Sopenharmony_ci    DCHECK_EQ(frame->function_index(), new_code->index());
6981cb0ef41Sopenharmony_ci    DCHECK_EQ(frame->native_module(), new_code->native_module());
6991cb0ef41Sopenharmony_ci    DCHECK(frame->wasm_code()->is_liftoff());
7001cb0ef41Sopenharmony_ci    Address new_pc =
7011cb0ef41Sopenharmony_ci        FindNewPC(frame, new_code, frame->byte_offset(), return_location);
7021cb0ef41Sopenharmony_ci#ifdef DEBUG
7031cb0ef41Sopenharmony_ci    int old_position = frame->position();
7041cb0ef41Sopenharmony_ci#endif
7051cb0ef41Sopenharmony_ci#if V8_TARGET_ARCH_X64
7061cb0ef41Sopenharmony_ci    if (frame->wasm_code()->for_debugging()) {
7071cb0ef41Sopenharmony_ci      base::Memory<Address>(frame->fp() - kOSRTargetOffset) = new_pc;
7081cb0ef41Sopenharmony_ci    }
7091cb0ef41Sopenharmony_ci#else
7101cb0ef41Sopenharmony_ci    PointerAuthentication::ReplacePC(frame->pc_address(), new_pc,
7111cb0ef41Sopenharmony_ci                                     kSystemPointerSize);
7121cb0ef41Sopenharmony_ci#endif
7131cb0ef41Sopenharmony_ci    // The frame position should still be the same after OSR.
7141cb0ef41Sopenharmony_ci    DCHECK_EQ(old_position, frame->position());
7151cb0ef41Sopenharmony_ci  }
7161cb0ef41Sopenharmony_ci
7171cb0ef41Sopenharmony_ci  bool IsAtReturn(WasmFrame* frame) {
7181cb0ef41Sopenharmony_ci    DisallowGarbageCollection no_gc;
7191cb0ef41Sopenharmony_ci    int position = frame->position();
7201cb0ef41Sopenharmony_ci    NativeModule* native_module =
7211cb0ef41Sopenharmony_ci        frame->wasm_instance().module_object().native_module();
7221cb0ef41Sopenharmony_ci    uint8_t opcode = native_module->wire_bytes()[position];
7231cb0ef41Sopenharmony_ci    if (opcode == kExprReturn) return true;
7241cb0ef41Sopenharmony_ci    // Another implicit return is at the last kExprEnd in the function body.
7251cb0ef41Sopenharmony_ci    int func_index = frame->function_index();
7261cb0ef41Sopenharmony_ci    WireBytesRef code = native_module->module()->functions[func_index].code;
7271cb0ef41Sopenharmony_ci    return static_cast<size_t>(position) == code.end_offset() - 1;
7281cb0ef41Sopenharmony_ci  }
7291cb0ef41Sopenharmony_ci
7301cb0ef41Sopenharmony_ci  // Isolate-specific data, for debugging modules that are shared by multiple
7311cb0ef41Sopenharmony_ci  // isolates.
7321cb0ef41Sopenharmony_ci  struct PerIsolateDebugData {
7331cb0ef41Sopenharmony_ci    // Keeps track of the currently set breakpoints (by offset within that
7341cb0ef41Sopenharmony_ci    // function).
7351cb0ef41Sopenharmony_ci    std::unordered_map<int, std::vector<int>> breakpoints_per_function;
7361cb0ef41Sopenharmony_ci
7371cb0ef41Sopenharmony_ci    // Store the frame ID when stepping, to avoid overwriting that frame when
7381cb0ef41Sopenharmony_ci    // setting or removing a breakpoint.
7391cb0ef41Sopenharmony_ci    StackFrameId stepping_frame = NO_ID;
7401cb0ef41Sopenharmony_ci  };
7411cb0ef41Sopenharmony_ci
7421cb0ef41Sopenharmony_ci  NativeModule* const native_module_;
7431cb0ef41Sopenharmony_ci
7441cb0ef41Sopenharmony_ci  mutable base::Mutex debug_side_tables_mutex_;
7451cb0ef41Sopenharmony_ci
7461cb0ef41Sopenharmony_ci  // DebugSideTable per code object, lazily initialized.
7471cb0ef41Sopenharmony_ci  std::unordered_map<const WasmCode*, std::unique_ptr<DebugSideTable>>
7481cb0ef41Sopenharmony_ci      debug_side_tables_;
7491cb0ef41Sopenharmony_ci
7501cb0ef41Sopenharmony_ci  // {mutex_} protects all fields below.
7511cb0ef41Sopenharmony_ci  mutable base::Mutex mutex_;
7521cb0ef41Sopenharmony_ci
7531cb0ef41Sopenharmony_ci  // Cache a fixed number of WasmCode objects that were generated for debugging.
7541cb0ef41Sopenharmony_ci  // This is useful especially in stepping, because stepping code is cleared on
7551cb0ef41Sopenharmony_ci  // every pause and re-installed on the next step.
7561cb0ef41Sopenharmony_ci  // This is a LRU cache (most recently used entries first).
7571cb0ef41Sopenharmony_ci  static constexpr size_t kMaxCachedDebuggingCode = 3;
7581cb0ef41Sopenharmony_ci  struct CachedDebuggingCode {
7591cb0ef41Sopenharmony_ci    int func_index;
7601cb0ef41Sopenharmony_ci    base::OwnedVector<const int> breakpoint_offsets;
7611cb0ef41Sopenharmony_ci    int dead_breakpoint;
7621cb0ef41Sopenharmony_ci    WasmCode* code;
7631cb0ef41Sopenharmony_ci  };
7641cb0ef41Sopenharmony_ci  std::vector<CachedDebuggingCode> cached_debugging_code_;
7651cb0ef41Sopenharmony_ci
7661cb0ef41Sopenharmony_ci  // Names of exports, lazily derived from the exports table.
7671cb0ef41Sopenharmony_ci  std::unique_ptr<std::map<ImportExportKey, wasm::WireBytesRef>> export_names_;
7681cb0ef41Sopenharmony_ci
7691cb0ef41Sopenharmony_ci  // Names of imports, lazily derived from the imports table.
7701cb0ef41Sopenharmony_ci  std::unique_ptr<std::map<ImportExportKey,
7711cb0ef41Sopenharmony_ci                           std::pair<wasm::WireBytesRef, wasm::WireBytesRef>>>
7721cb0ef41Sopenharmony_ci      import_names_;
7731cb0ef41Sopenharmony_ci
7741cb0ef41Sopenharmony_ci  // Names of types, lazily decoded from the wire bytes.
7751cb0ef41Sopenharmony_ci  std::unique_ptr<NameMap> type_names_;
7761cb0ef41Sopenharmony_ci  // Names of locals, lazily decoded from the wire bytes.
7771cb0ef41Sopenharmony_ci  std::unique_ptr<IndirectNameMap> local_names_;
7781cb0ef41Sopenharmony_ci  // Names of struct fields, lazily decoded from the wire bytes.
7791cb0ef41Sopenharmony_ci  std::unique_ptr<IndirectNameMap> field_names_;
7801cb0ef41Sopenharmony_ci
7811cb0ef41Sopenharmony_ci  // Isolate-specific data.
7821cb0ef41Sopenharmony_ci  std::unordered_map<Isolate*, PerIsolateDebugData> per_isolate_data_;
7831cb0ef41Sopenharmony_ci};
7841cb0ef41Sopenharmony_ci
7851cb0ef41Sopenharmony_ciDebugInfo::DebugInfo(NativeModule* native_module)
7861cb0ef41Sopenharmony_ci    : impl_(std::make_unique<DebugInfoImpl>(native_module)) {}
7871cb0ef41Sopenharmony_ci
7881cb0ef41Sopenharmony_ciDebugInfo::~DebugInfo() = default;
7891cb0ef41Sopenharmony_ci
7901cb0ef41Sopenharmony_ciint DebugInfo::GetNumLocals(Address pc) { return impl_->GetNumLocals(pc); }
7911cb0ef41Sopenharmony_ci
7921cb0ef41Sopenharmony_ciWasmValue DebugInfo::GetLocalValue(int local, Address pc, Address fp,
7931cb0ef41Sopenharmony_ci                                   Address debug_break_fp, Isolate* isolate) {
7941cb0ef41Sopenharmony_ci  return impl_->GetLocalValue(local, pc, fp, debug_break_fp, isolate);
7951cb0ef41Sopenharmony_ci}
7961cb0ef41Sopenharmony_ci
7971cb0ef41Sopenharmony_ciint DebugInfo::GetStackDepth(Address pc) { return impl_->GetStackDepth(pc); }
7981cb0ef41Sopenharmony_ci
7991cb0ef41Sopenharmony_ciWasmValue DebugInfo::GetStackValue(int index, Address pc, Address fp,
8001cb0ef41Sopenharmony_ci                                   Address debug_break_fp, Isolate* isolate) {
8011cb0ef41Sopenharmony_ci  return impl_->GetStackValue(index, pc, fp, debug_break_fp, isolate);
8021cb0ef41Sopenharmony_ci}
8031cb0ef41Sopenharmony_ci
8041cb0ef41Sopenharmony_ciconst wasm::WasmFunction& DebugInfo::GetFunctionAtAddress(Address pc) {
8051cb0ef41Sopenharmony_ci  return impl_->GetFunctionAtAddress(pc);
8061cb0ef41Sopenharmony_ci}
8071cb0ef41Sopenharmony_ci
8081cb0ef41Sopenharmony_ciWireBytesRef DebugInfo::GetExportName(ImportExportKindCode code,
8091cb0ef41Sopenharmony_ci                                      uint32_t index) {
8101cb0ef41Sopenharmony_ci  return impl_->GetExportName(code, index);
8111cb0ef41Sopenharmony_ci}
8121cb0ef41Sopenharmony_ci
8131cb0ef41Sopenharmony_cistd::pair<WireBytesRef, WireBytesRef> DebugInfo::GetImportName(
8141cb0ef41Sopenharmony_ci    ImportExportKindCode code, uint32_t index) {
8151cb0ef41Sopenharmony_ci  return impl_->GetImportName(code, index);
8161cb0ef41Sopenharmony_ci}
8171cb0ef41Sopenharmony_ci
8181cb0ef41Sopenharmony_ciWireBytesRef DebugInfo::GetTypeName(int type_index) {
8191cb0ef41Sopenharmony_ci  return impl_->GetTypeName(type_index);
8201cb0ef41Sopenharmony_ci}
8211cb0ef41Sopenharmony_ci
8221cb0ef41Sopenharmony_ciWireBytesRef DebugInfo::GetLocalName(int func_index, int local_index) {
8231cb0ef41Sopenharmony_ci  return impl_->GetLocalName(func_index, local_index);
8241cb0ef41Sopenharmony_ci}
8251cb0ef41Sopenharmony_ci
8261cb0ef41Sopenharmony_ciWireBytesRef DebugInfo::GetFieldName(int struct_index, int field_index) {
8271cb0ef41Sopenharmony_ci  return impl_->GetFieldName(struct_index, field_index);
8281cb0ef41Sopenharmony_ci}
8291cb0ef41Sopenharmony_ci
8301cb0ef41Sopenharmony_civoid DebugInfo::SetBreakpoint(int func_index, int offset,
8311cb0ef41Sopenharmony_ci                              Isolate* current_isolate) {
8321cb0ef41Sopenharmony_ci  impl_->SetBreakpoint(func_index, offset, current_isolate);
8331cb0ef41Sopenharmony_ci}
8341cb0ef41Sopenharmony_ci
8351cb0ef41Sopenharmony_cibool DebugInfo::PrepareStep(WasmFrame* frame) {
8361cb0ef41Sopenharmony_ci  return impl_->PrepareStep(frame);
8371cb0ef41Sopenharmony_ci}
8381cb0ef41Sopenharmony_ci
8391cb0ef41Sopenharmony_civoid DebugInfo::PrepareStepOutTo(WasmFrame* frame) {
8401cb0ef41Sopenharmony_ci  impl_->PrepareStepOutTo(frame);
8411cb0ef41Sopenharmony_ci}
8421cb0ef41Sopenharmony_ci
8431cb0ef41Sopenharmony_civoid DebugInfo::ClearStepping(Isolate* isolate) {
8441cb0ef41Sopenharmony_ci  impl_->ClearStepping(isolate);
8451cb0ef41Sopenharmony_ci}
8461cb0ef41Sopenharmony_ci
8471cb0ef41Sopenharmony_civoid DebugInfo::ClearStepping(WasmFrame* frame) { impl_->ClearStepping(frame); }
8481cb0ef41Sopenharmony_ci
8491cb0ef41Sopenharmony_cibool DebugInfo::IsStepping(WasmFrame* frame) {
8501cb0ef41Sopenharmony_ci  return impl_->IsStepping(frame);
8511cb0ef41Sopenharmony_ci}
8521cb0ef41Sopenharmony_ci
8531cb0ef41Sopenharmony_civoid DebugInfo::RemoveBreakpoint(int func_index, int offset,
8541cb0ef41Sopenharmony_ci                                 Isolate* current_isolate) {
8551cb0ef41Sopenharmony_ci  impl_->RemoveBreakpoint(func_index, offset, current_isolate);
8561cb0ef41Sopenharmony_ci}
8571cb0ef41Sopenharmony_ci
8581cb0ef41Sopenharmony_civoid DebugInfo::RemoveDebugSideTables(base::Vector<WasmCode* const> code) {
8591cb0ef41Sopenharmony_ci  impl_->RemoveDebugSideTables(code);
8601cb0ef41Sopenharmony_ci}
8611cb0ef41Sopenharmony_ci
8621cb0ef41Sopenharmony_ciDebugSideTable* DebugInfo::GetDebugSideTableIfExists(
8631cb0ef41Sopenharmony_ci    const WasmCode* code) const {
8641cb0ef41Sopenharmony_ci  return impl_->GetDebugSideTableIfExists(code);
8651cb0ef41Sopenharmony_ci}
8661cb0ef41Sopenharmony_ci
8671cb0ef41Sopenharmony_civoid DebugInfo::RemoveIsolate(Isolate* isolate) {
8681cb0ef41Sopenharmony_ci  return impl_->RemoveIsolate(isolate);
8691cb0ef41Sopenharmony_ci}
8701cb0ef41Sopenharmony_ci
8711cb0ef41Sopenharmony_ci}  // namespace wasm
8721cb0ef41Sopenharmony_ci
8731cb0ef41Sopenharmony_cinamespace {
8741cb0ef41Sopenharmony_ci
8751cb0ef41Sopenharmony_ci// Return the next breakable position at or after {offset_in_func} in function
8761cb0ef41Sopenharmony_ci// {func_index}, or 0 if there is none.
8771cb0ef41Sopenharmony_ci// Note that 0 is never a breakable position in wasm, since the first byte
8781cb0ef41Sopenharmony_ci// contains the locals count for the function.
8791cb0ef41Sopenharmony_ciint FindNextBreakablePosition(wasm::NativeModule* native_module, int func_index,
8801cb0ef41Sopenharmony_ci                              int offset_in_func) {
8811cb0ef41Sopenharmony_ci  AccountingAllocator alloc;
8821cb0ef41Sopenharmony_ci  Zone tmp(&alloc, ZONE_NAME);
8831cb0ef41Sopenharmony_ci  wasm::BodyLocalDecls locals(&tmp);
8841cb0ef41Sopenharmony_ci  const byte* module_start = native_module->wire_bytes().begin();
8851cb0ef41Sopenharmony_ci  const wasm::WasmFunction& func =
8861cb0ef41Sopenharmony_ci      native_module->module()->functions[func_index];
8871cb0ef41Sopenharmony_ci  wasm::BytecodeIterator iterator(module_start + func.code.offset(),
8881cb0ef41Sopenharmony_ci                                  module_start + func.code.end_offset(),
8891cb0ef41Sopenharmony_ci                                  &locals);
8901cb0ef41Sopenharmony_ci  DCHECK_LT(0, locals.encoded_size);
8911cb0ef41Sopenharmony_ci  if (offset_in_func < 0) return 0;
8921cb0ef41Sopenharmony_ci  for (; iterator.has_next(); iterator.next()) {
8931cb0ef41Sopenharmony_ci    if (iterator.pc_offset() < static_cast<uint32_t>(offset_in_func)) continue;
8941cb0ef41Sopenharmony_ci    if (!wasm::WasmOpcodes::IsBreakable(iterator.current())) continue;
8951cb0ef41Sopenharmony_ci    return static_cast<int>(iterator.pc_offset());
8961cb0ef41Sopenharmony_ci  }
8971cb0ef41Sopenharmony_ci  return 0;
8981cb0ef41Sopenharmony_ci}
8991cb0ef41Sopenharmony_ci
9001cb0ef41Sopenharmony_civoid SetBreakOnEntryFlag(Script script, bool enabled) {
9011cb0ef41Sopenharmony_ci  if (script.break_on_entry() == enabled) return;
9021cb0ef41Sopenharmony_ci
9031cb0ef41Sopenharmony_ci  script.set_break_on_entry(enabled);
9041cb0ef41Sopenharmony_ci  // Update the "break_on_entry" flag on all live instances.
9051cb0ef41Sopenharmony_ci  i::WeakArrayList weak_instance_list = script.wasm_weak_instance_list();
9061cb0ef41Sopenharmony_ci  for (int i = 0; i < weak_instance_list.length(); ++i) {
9071cb0ef41Sopenharmony_ci    if (weak_instance_list.Get(i)->IsCleared()) continue;
9081cb0ef41Sopenharmony_ci    i::WasmInstanceObject instance =
9091cb0ef41Sopenharmony_ci        i::WasmInstanceObject::cast(weak_instance_list.Get(i)->GetHeapObject());
9101cb0ef41Sopenharmony_ci    instance.set_break_on_entry(enabled);
9111cb0ef41Sopenharmony_ci  }
9121cb0ef41Sopenharmony_ci}
9131cb0ef41Sopenharmony_ci}  // namespace
9141cb0ef41Sopenharmony_ci
9151cb0ef41Sopenharmony_ci// static
9161cb0ef41Sopenharmony_cibool WasmScript::SetBreakPoint(Handle<Script> script, int* position,
9171cb0ef41Sopenharmony_ci                               Handle<BreakPoint> break_point) {
9181cb0ef41Sopenharmony_ci  DCHECK_NE(kOnEntryBreakpointPosition, *position);
9191cb0ef41Sopenharmony_ci
9201cb0ef41Sopenharmony_ci  // Find the function for this breakpoint.
9211cb0ef41Sopenharmony_ci  const wasm::WasmModule* module = script->wasm_native_module()->module();
9221cb0ef41Sopenharmony_ci  int func_index = GetContainingWasmFunction(module, *position);
9231cb0ef41Sopenharmony_ci  if (func_index < 0) return false;
9241cb0ef41Sopenharmony_ci  const wasm::WasmFunction& func = module->functions[func_index];
9251cb0ef41Sopenharmony_ci  int offset_in_func = *position - func.code.offset();
9261cb0ef41Sopenharmony_ci
9271cb0ef41Sopenharmony_ci  int breakable_offset = FindNextBreakablePosition(script->wasm_native_module(),
9281cb0ef41Sopenharmony_ci                                                   func_index, offset_in_func);
9291cb0ef41Sopenharmony_ci  if (breakable_offset == 0) return false;
9301cb0ef41Sopenharmony_ci  *position = func.code.offset() + breakable_offset;
9311cb0ef41Sopenharmony_ci
9321cb0ef41Sopenharmony_ci  return WasmScript::SetBreakPointForFunction(script, func_index,
9331cb0ef41Sopenharmony_ci                                              breakable_offset, break_point);
9341cb0ef41Sopenharmony_ci}
9351cb0ef41Sopenharmony_ci
9361cb0ef41Sopenharmony_ci// static
9371cb0ef41Sopenharmony_civoid WasmScript::SetInstrumentationBreakpoint(Handle<Script> script,
9381cb0ef41Sopenharmony_ci                                              Handle<BreakPoint> break_point) {
9391cb0ef41Sopenharmony_ci  // Special handling for on-entry breakpoints.
9401cb0ef41Sopenharmony_ci  AddBreakpointToInfo(script, kOnEntryBreakpointPosition, break_point);
9411cb0ef41Sopenharmony_ci
9421cb0ef41Sopenharmony_ci  // Update the "break_on_entry" flag on all live instances.
9431cb0ef41Sopenharmony_ci  SetBreakOnEntryFlag(*script, true);
9441cb0ef41Sopenharmony_ci}
9451cb0ef41Sopenharmony_ci
9461cb0ef41Sopenharmony_ci// static
9471cb0ef41Sopenharmony_cibool WasmScript::SetBreakPointOnFirstBreakableForFunction(
9481cb0ef41Sopenharmony_ci    Handle<Script> script, int func_index, Handle<BreakPoint> break_point) {
9491cb0ef41Sopenharmony_ci  if (func_index < 0) return false;
9501cb0ef41Sopenharmony_ci  int offset_in_func = 0;
9511cb0ef41Sopenharmony_ci
9521cb0ef41Sopenharmony_ci  int breakable_offset = FindNextBreakablePosition(script->wasm_native_module(),
9531cb0ef41Sopenharmony_ci                                                   func_index, offset_in_func);
9541cb0ef41Sopenharmony_ci  if (breakable_offset == 0) return false;
9551cb0ef41Sopenharmony_ci  return WasmScript::SetBreakPointForFunction(script, func_index,
9561cb0ef41Sopenharmony_ci                                              breakable_offset, break_point);
9571cb0ef41Sopenharmony_ci}
9581cb0ef41Sopenharmony_ci
9591cb0ef41Sopenharmony_ci// static
9601cb0ef41Sopenharmony_cibool WasmScript::SetBreakPointForFunction(Handle<Script> script, int func_index,
9611cb0ef41Sopenharmony_ci                                          int offset,
9621cb0ef41Sopenharmony_ci                                          Handle<BreakPoint> break_point) {
9631cb0ef41Sopenharmony_ci  Isolate* isolate = script->GetIsolate();
9641cb0ef41Sopenharmony_ci
9651cb0ef41Sopenharmony_ci  DCHECK_LE(0, func_index);
9661cb0ef41Sopenharmony_ci  DCHECK_NE(0, offset);
9671cb0ef41Sopenharmony_ci
9681cb0ef41Sopenharmony_ci  // Find the function for this breakpoint.
9691cb0ef41Sopenharmony_ci  wasm::NativeModule* native_module = script->wasm_native_module();
9701cb0ef41Sopenharmony_ci  const wasm::WasmModule* module = native_module->module();
9711cb0ef41Sopenharmony_ci  const wasm::WasmFunction& func = module->functions[func_index];
9721cb0ef41Sopenharmony_ci
9731cb0ef41Sopenharmony_ci  // Insert new break point into {wasm_breakpoint_infos} of the script.
9741cb0ef41Sopenharmony_ci  AddBreakpointToInfo(script, func.code.offset() + offset, break_point);
9751cb0ef41Sopenharmony_ci
9761cb0ef41Sopenharmony_ci  native_module->GetDebugInfo()->SetBreakpoint(func_index, offset, isolate);
9771cb0ef41Sopenharmony_ci
9781cb0ef41Sopenharmony_ci  return true;
9791cb0ef41Sopenharmony_ci}
9801cb0ef41Sopenharmony_ci
9811cb0ef41Sopenharmony_cinamespace {
9821cb0ef41Sopenharmony_ci
9831cb0ef41Sopenharmony_ciint GetBreakpointPos(Isolate* isolate, Object break_point_info_or_undef) {
9841cb0ef41Sopenharmony_ci  if (break_point_info_or_undef.IsUndefined(isolate)) return kMaxInt;
9851cb0ef41Sopenharmony_ci  return BreakPointInfo::cast(break_point_info_or_undef).source_position();
9861cb0ef41Sopenharmony_ci}
9871cb0ef41Sopenharmony_ci
9881cb0ef41Sopenharmony_ciint FindBreakpointInfoInsertPos(Isolate* isolate,
9891cb0ef41Sopenharmony_ci                                Handle<FixedArray> breakpoint_infos,
9901cb0ef41Sopenharmony_ci                                int position) {
9911cb0ef41Sopenharmony_ci  // Find insert location via binary search, taking care of undefined values on
9921cb0ef41Sopenharmony_ci  // the right. {position} is either {kOnEntryBreakpointPosition} (which is -1),
9931cb0ef41Sopenharmony_ci  // or positive.
9941cb0ef41Sopenharmony_ci  DCHECK(position == WasmScript::kOnEntryBreakpointPosition || position > 0);
9951cb0ef41Sopenharmony_ci
9961cb0ef41Sopenharmony_ci  int left = 0;                            // inclusive
9971cb0ef41Sopenharmony_ci  int right = breakpoint_infos->length();  // exclusive
9981cb0ef41Sopenharmony_ci  while (right - left > 1) {
9991cb0ef41Sopenharmony_ci    int mid = left + (right - left) / 2;
10001cb0ef41Sopenharmony_ci    Object mid_obj = breakpoint_infos->get(mid);
10011cb0ef41Sopenharmony_ci    if (GetBreakpointPos(isolate, mid_obj) <= position) {
10021cb0ef41Sopenharmony_ci      left = mid;
10031cb0ef41Sopenharmony_ci    } else {
10041cb0ef41Sopenharmony_ci      right = mid;
10051cb0ef41Sopenharmony_ci    }
10061cb0ef41Sopenharmony_ci  }
10071cb0ef41Sopenharmony_ci
10081cb0ef41Sopenharmony_ci  int left_pos = GetBreakpointPos(isolate, breakpoint_infos->get(left));
10091cb0ef41Sopenharmony_ci  return left_pos < position ? left + 1 : left;
10101cb0ef41Sopenharmony_ci}
10111cb0ef41Sopenharmony_ci
10121cb0ef41Sopenharmony_ci}  // namespace
10131cb0ef41Sopenharmony_ci
10141cb0ef41Sopenharmony_ci// static
10151cb0ef41Sopenharmony_cibool WasmScript::ClearBreakPoint(Handle<Script> script, int position,
10161cb0ef41Sopenharmony_ci                                 Handle<BreakPoint> break_point) {
10171cb0ef41Sopenharmony_ci  if (!script->has_wasm_breakpoint_infos()) return false;
10181cb0ef41Sopenharmony_ci
10191cb0ef41Sopenharmony_ci  Isolate* isolate = script->GetIsolate();
10201cb0ef41Sopenharmony_ci  Handle<FixedArray> breakpoint_infos(script->wasm_breakpoint_infos(), isolate);
10211cb0ef41Sopenharmony_ci
10221cb0ef41Sopenharmony_ci  int pos = FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
10231cb0ef41Sopenharmony_ci
10241cb0ef41Sopenharmony_ci  // Does a BreakPointInfo object already exist for this position?
10251cb0ef41Sopenharmony_ci  if (pos == breakpoint_infos->length()) return false;
10261cb0ef41Sopenharmony_ci
10271cb0ef41Sopenharmony_ci  Handle<BreakPointInfo> info(BreakPointInfo::cast(breakpoint_infos->get(pos)),
10281cb0ef41Sopenharmony_ci                              isolate);
10291cb0ef41Sopenharmony_ci  BreakPointInfo::ClearBreakPoint(isolate, info, break_point);
10301cb0ef41Sopenharmony_ci
10311cb0ef41Sopenharmony_ci  // Check if there are no more breakpoints at this location.
10321cb0ef41Sopenharmony_ci  if (info->GetBreakPointCount(isolate) == 0) {
10331cb0ef41Sopenharmony_ci    // Update array by moving breakpoints up one position.
10341cb0ef41Sopenharmony_ci    for (int i = pos; i < breakpoint_infos->length() - 1; i++) {
10351cb0ef41Sopenharmony_ci      Object entry = breakpoint_infos->get(i + 1);
10361cb0ef41Sopenharmony_ci      breakpoint_infos->set(i, entry);
10371cb0ef41Sopenharmony_ci      if (entry.IsUndefined(isolate)) break;
10381cb0ef41Sopenharmony_ci    }
10391cb0ef41Sopenharmony_ci    // Make sure last array element is empty as a result.
10401cb0ef41Sopenharmony_ci    breakpoint_infos->set_undefined(breakpoint_infos->length() - 1);
10411cb0ef41Sopenharmony_ci  }
10421cb0ef41Sopenharmony_ci
10431cb0ef41Sopenharmony_ci  if (break_point->id() == v8::internal::Debug::kInstrumentationId) {
10441cb0ef41Sopenharmony_ci    // Special handling for instrumentation breakpoints.
10451cb0ef41Sopenharmony_ci    SetBreakOnEntryFlag(*script, false);
10461cb0ef41Sopenharmony_ci  } else {
10471cb0ef41Sopenharmony_ci    // Remove the breakpoint from DebugInfo and recompile.
10481cb0ef41Sopenharmony_ci    wasm::NativeModule* native_module = script->wasm_native_module();
10491cb0ef41Sopenharmony_ci    const wasm::WasmModule* module = native_module->module();
10501cb0ef41Sopenharmony_ci    int func_index = GetContainingWasmFunction(module, position);
10511cb0ef41Sopenharmony_ci    native_module->GetDebugInfo()->RemoveBreakpoint(func_index, position,
10521cb0ef41Sopenharmony_ci                                                    isolate);
10531cb0ef41Sopenharmony_ci  }
10541cb0ef41Sopenharmony_ci
10551cb0ef41Sopenharmony_ci  return true;
10561cb0ef41Sopenharmony_ci}
10571cb0ef41Sopenharmony_ci
10581cb0ef41Sopenharmony_ci// static
10591cb0ef41Sopenharmony_cibool WasmScript::ClearBreakPointById(Handle<Script> script, int breakpoint_id) {
10601cb0ef41Sopenharmony_ci  if (!script->has_wasm_breakpoint_infos()) {
10611cb0ef41Sopenharmony_ci    return false;
10621cb0ef41Sopenharmony_ci  }
10631cb0ef41Sopenharmony_ci  Isolate* isolate = script->GetIsolate();
10641cb0ef41Sopenharmony_ci  Handle<FixedArray> breakpoint_infos(script->wasm_breakpoint_infos(), isolate);
10651cb0ef41Sopenharmony_ci  // If the array exists, it should not be empty.
10661cb0ef41Sopenharmony_ci  DCHECK_LT(0, breakpoint_infos->length());
10671cb0ef41Sopenharmony_ci
10681cb0ef41Sopenharmony_ci  for (int i = 0, e = breakpoint_infos->length(); i < e; ++i) {
10691cb0ef41Sopenharmony_ci    Handle<Object> obj(breakpoint_infos->get(i), isolate);
10701cb0ef41Sopenharmony_ci    if (obj->IsUndefined(isolate)) {
10711cb0ef41Sopenharmony_ci      continue;
10721cb0ef41Sopenharmony_ci    }
10731cb0ef41Sopenharmony_ci    Handle<BreakPointInfo> breakpoint_info = Handle<BreakPointInfo>::cast(obj);
10741cb0ef41Sopenharmony_ci    Handle<BreakPoint> breakpoint;
10751cb0ef41Sopenharmony_ci    if (BreakPointInfo::GetBreakPointById(isolate, breakpoint_info,
10761cb0ef41Sopenharmony_ci                                          breakpoint_id)
10771cb0ef41Sopenharmony_ci            .ToHandle(&breakpoint)) {
10781cb0ef41Sopenharmony_ci      DCHECK(breakpoint->id() == breakpoint_id);
10791cb0ef41Sopenharmony_ci      return WasmScript::ClearBreakPoint(
10801cb0ef41Sopenharmony_ci          script, breakpoint_info->source_position(), breakpoint);
10811cb0ef41Sopenharmony_ci    }
10821cb0ef41Sopenharmony_ci  }
10831cb0ef41Sopenharmony_ci  return false;
10841cb0ef41Sopenharmony_ci}
10851cb0ef41Sopenharmony_ci
10861cb0ef41Sopenharmony_ci// static
10871cb0ef41Sopenharmony_civoid WasmScript::ClearAllBreakpoints(Script script) {
10881cb0ef41Sopenharmony_ci  script.set_wasm_breakpoint_infos(
10891cb0ef41Sopenharmony_ci      ReadOnlyRoots(script.GetIsolate()).empty_fixed_array());
10901cb0ef41Sopenharmony_ci  SetBreakOnEntryFlag(script, false);
10911cb0ef41Sopenharmony_ci}
10921cb0ef41Sopenharmony_ci
10931cb0ef41Sopenharmony_ci// static
10941cb0ef41Sopenharmony_civoid WasmScript::AddBreakpointToInfo(Handle<Script> script, int position,
10951cb0ef41Sopenharmony_ci                                     Handle<BreakPoint> break_point) {
10961cb0ef41Sopenharmony_ci  Isolate* isolate = script->GetIsolate();
10971cb0ef41Sopenharmony_ci  Handle<FixedArray> breakpoint_infos;
10981cb0ef41Sopenharmony_ci  if (script->has_wasm_breakpoint_infos()) {
10991cb0ef41Sopenharmony_ci    breakpoint_infos = handle(script->wasm_breakpoint_infos(), isolate);
11001cb0ef41Sopenharmony_ci  } else {
11011cb0ef41Sopenharmony_ci    breakpoint_infos =
11021cb0ef41Sopenharmony_ci        isolate->factory()->NewFixedArray(4, AllocationType::kOld);
11031cb0ef41Sopenharmony_ci    script->set_wasm_breakpoint_infos(*breakpoint_infos);
11041cb0ef41Sopenharmony_ci  }
11051cb0ef41Sopenharmony_ci
11061cb0ef41Sopenharmony_ci  int insert_pos =
11071cb0ef41Sopenharmony_ci      FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
11081cb0ef41Sopenharmony_ci
11091cb0ef41Sopenharmony_ci  // If a BreakPointInfo object already exists for this position, add the new
11101cb0ef41Sopenharmony_ci  // breakpoint object and return.
11111cb0ef41Sopenharmony_ci  if (insert_pos < breakpoint_infos->length() &&
11121cb0ef41Sopenharmony_ci      GetBreakpointPos(isolate, breakpoint_infos->get(insert_pos)) ==
11131cb0ef41Sopenharmony_ci          position) {
11141cb0ef41Sopenharmony_ci    Handle<BreakPointInfo> old_info(
11151cb0ef41Sopenharmony_ci        BreakPointInfo::cast(breakpoint_infos->get(insert_pos)), isolate);
11161cb0ef41Sopenharmony_ci    BreakPointInfo::SetBreakPoint(isolate, old_info, break_point);
11171cb0ef41Sopenharmony_ci    return;
11181cb0ef41Sopenharmony_ci  }
11191cb0ef41Sopenharmony_ci
11201cb0ef41Sopenharmony_ci  // Enlarge break positions array if necessary.
11211cb0ef41Sopenharmony_ci  bool need_realloc = !breakpoint_infos->get(breakpoint_infos->length() - 1)
11221cb0ef41Sopenharmony_ci                           .IsUndefined(isolate);
11231cb0ef41Sopenharmony_ci  Handle<FixedArray> new_breakpoint_infos = breakpoint_infos;
11241cb0ef41Sopenharmony_ci  if (need_realloc) {
11251cb0ef41Sopenharmony_ci    new_breakpoint_infos = isolate->factory()->NewFixedArray(
11261cb0ef41Sopenharmony_ci        2 * breakpoint_infos->length(), AllocationType::kOld);
11271cb0ef41Sopenharmony_ci    script->set_wasm_breakpoint_infos(*new_breakpoint_infos);
11281cb0ef41Sopenharmony_ci    // Copy over the entries [0, insert_pos).
11291cb0ef41Sopenharmony_ci    for (int i = 0; i < insert_pos; ++i)
11301cb0ef41Sopenharmony_ci      new_breakpoint_infos->set(i, breakpoint_infos->get(i));
11311cb0ef41Sopenharmony_ci  }
11321cb0ef41Sopenharmony_ci
11331cb0ef41Sopenharmony_ci  // Move elements [insert_pos, ...] up by one.
11341cb0ef41Sopenharmony_ci  for (int i = breakpoint_infos->length() - 1; i >= insert_pos; --i) {
11351cb0ef41Sopenharmony_ci    Object entry = breakpoint_infos->get(i);
11361cb0ef41Sopenharmony_ci    if (entry.IsUndefined(isolate)) continue;
11371cb0ef41Sopenharmony_ci    new_breakpoint_infos->set(i + 1, entry);
11381cb0ef41Sopenharmony_ci  }
11391cb0ef41Sopenharmony_ci
11401cb0ef41Sopenharmony_ci  // Generate new BreakpointInfo.
11411cb0ef41Sopenharmony_ci  Handle<BreakPointInfo> breakpoint_info =
11421cb0ef41Sopenharmony_ci      isolate->factory()->NewBreakPointInfo(position);
11431cb0ef41Sopenharmony_ci  BreakPointInfo::SetBreakPoint(isolate, breakpoint_info, break_point);
11441cb0ef41Sopenharmony_ci
11451cb0ef41Sopenharmony_ci  // Now insert new position at insert_pos.
11461cb0ef41Sopenharmony_ci  new_breakpoint_infos->set(insert_pos, *breakpoint_info);
11471cb0ef41Sopenharmony_ci}
11481cb0ef41Sopenharmony_ci
11491cb0ef41Sopenharmony_ci// static
11501cb0ef41Sopenharmony_cibool WasmScript::GetPossibleBreakpoints(
11511cb0ef41Sopenharmony_ci    wasm::NativeModule* native_module, const v8::debug::Location& start,
11521cb0ef41Sopenharmony_ci    const v8::debug::Location& end,
11531cb0ef41Sopenharmony_ci    std::vector<v8::debug::BreakLocation>* locations) {
11541cb0ef41Sopenharmony_ci  DisallowGarbageCollection no_gc;
11551cb0ef41Sopenharmony_ci
11561cb0ef41Sopenharmony_ci  const wasm::WasmModule* module = native_module->module();
11571cb0ef41Sopenharmony_ci  const std::vector<wasm::WasmFunction>& functions = module->functions;
11581cb0ef41Sopenharmony_ci
11591cb0ef41Sopenharmony_ci  if (start.GetLineNumber() != 0 || start.GetColumnNumber() < 0 ||
11601cb0ef41Sopenharmony_ci      (!end.IsEmpty() &&
11611cb0ef41Sopenharmony_ci       (end.GetLineNumber() != 0 || end.GetColumnNumber() < 0 ||
11621cb0ef41Sopenharmony_ci        end.GetColumnNumber() < start.GetColumnNumber())))
11631cb0ef41Sopenharmony_ci    return false;
11641cb0ef41Sopenharmony_ci
11651cb0ef41Sopenharmony_ci  // start_func_index, start_offset and end_func_index is inclusive.
11661cb0ef41Sopenharmony_ci  // end_offset is exclusive.
11671cb0ef41Sopenharmony_ci  // start_offset and end_offset are module-relative byte offsets.
11681cb0ef41Sopenharmony_ci  // We set strict to false because offsets may be between functions.
11691cb0ef41Sopenharmony_ci  int start_func_index =
11701cb0ef41Sopenharmony_ci      GetNearestWasmFunction(module, start.GetColumnNumber());
11711cb0ef41Sopenharmony_ci  if (start_func_index < 0) return false;
11721cb0ef41Sopenharmony_ci  uint32_t start_offset = start.GetColumnNumber();
11731cb0ef41Sopenharmony_ci  int end_func_index;
11741cb0ef41Sopenharmony_ci  uint32_t end_offset;
11751cb0ef41Sopenharmony_ci
11761cb0ef41Sopenharmony_ci  if (end.IsEmpty()) {
11771cb0ef41Sopenharmony_ci    // Default: everything till the end of the Script.
11781cb0ef41Sopenharmony_ci    end_func_index = static_cast<uint32_t>(functions.size() - 1);
11791cb0ef41Sopenharmony_ci    end_offset = functions[end_func_index].code.end_offset();
11801cb0ef41Sopenharmony_ci  } else {
11811cb0ef41Sopenharmony_ci    // If end is specified: Use it and check for valid input.
11821cb0ef41Sopenharmony_ci    end_offset = end.GetColumnNumber();
11831cb0ef41Sopenharmony_ci    end_func_index = GetNearestWasmFunction(module, end_offset);
11841cb0ef41Sopenharmony_ci    DCHECK_GE(end_func_index, start_func_index);
11851cb0ef41Sopenharmony_ci  }
11861cb0ef41Sopenharmony_ci
11871cb0ef41Sopenharmony_ci  if (start_func_index == end_func_index &&
11881cb0ef41Sopenharmony_ci      start_offset > functions[end_func_index].code.end_offset())
11891cb0ef41Sopenharmony_ci    return false;
11901cb0ef41Sopenharmony_ci  AccountingAllocator alloc;
11911cb0ef41Sopenharmony_ci  Zone tmp(&alloc, ZONE_NAME);
11921cb0ef41Sopenharmony_ci  const byte* module_start = native_module->wire_bytes().begin();
11931cb0ef41Sopenharmony_ci
11941cb0ef41Sopenharmony_ci  for (int func_idx = start_func_index; func_idx <= end_func_index;
11951cb0ef41Sopenharmony_ci       ++func_idx) {
11961cb0ef41Sopenharmony_ci    const wasm::WasmFunction& func = functions[func_idx];
11971cb0ef41Sopenharmony_ci    if (func.code.length() == 0) continue;
11981cb0ef41Sopenharmony_ci
11991cb0ef41Sopenharmony_ci    wasm::BodyLocalDecls locals(&tmp);
12001cb0ef41Sopenharmony_ci    wasm::BytecodeIterator iterator(module_start + func.code.offset(),
12011cb0ef41Sopenharmony_ci                                    module_start + func.code.end_offset(),
12021cb0ef41Sopenharmony_ci                                    &locals);
12031cb0ef41Sopenharmony_ci    DCHECK_LT(0u, locals.encoded_size);
12041cb0ef41Sopenharmony_ci    for (; iterator.has_next(); iterator.next()) {
12051cb0ef41Sopenharmony_ci      uint32_t total_offset = func.code.offset() + iterator.pc_offset();
12061cb0ef41Sopenharmony_ci      if (total_offset >= end_offset) {
12071cb0ef41Sopenharmony_ci        DCHECK_EQ(end_func_index, func_idx);
12081cb0ef41Sopenharmony_ci        break;
12091cb0ef41Sopenharmony_ci      }
12101cb0ef41Sopenharmony_ci      if (total_offset < start_offset) continue;
12111cb0ef41Sopenharmony_ci      if (!wasm::WasmOpcodes::IsBreakable(iterator.current())) continue;
12121cb0ef41Sopenharmony_ci      locations->emplace_back(0, total_offset, debug::kCommonBreakLocation);
12131cb0ef41Sopenharmony_ci    }
12141cb0ef41Sopenharmony_ci  }
12151cb0ef41Sopenharmony_ci  return true;
12161cb0ef41Sopenharmony_ci}
12171cb0ef41Sopenharmony_ci
12181cb0ef41Sopenharmony_cinamespace {
12191cb0ef41Sopenharmony_ci
12201cb0ef41Sopenharmony_cibool CheckBreakPoint(Isolate* isolate, Handle<BreakPoint> break_point,
12211cb0ef41Sopenharmony_ci                     StackFrameId frame_id) {
12221cb0ef41Sopenharmony_ci  if (break_point->condition().length() == 0) return true;
12231cb0ef41Sopenharmony_ci
12241cb0ef41Sopenharmony_ci  HandleScope scope(isolate);
12251cb0ef41Sopenharmony_ci  Handle<String> condition(break_point->condition(), isolate);
12261cb0ef41Sopenharmony_ci  Handle<Object> result;
12271cb0ef41Sopenharmony_ci  // The Wasm engine doesn't perform any sort of inlining.
12281cb0ef41Sopenharmony_ci  const int inlined_jsframe_index = 0;
12291cb0ef41Sopenharmony_ci  const bool throw_on_side_effect = false;
12301cb0ef41Sopenharmony_ci  if (!DebugEvaluate::Local(isolate, frame_id, inlined_jsframe_index, condition,
12311cb0ef41Sopenharmony_ci                            throw_on_side_effect)
12321cb0ef41Sopenharmony_ci           .ToHandle(&result)) {
12331cb0ef41Sopenharmony_ci    isolate->clear_pending_exception();
12341cb0ef41Sopenharmony_ci    return false;
12351cb0ef41Sopenharmony_ci  }
12361cb0ef41Sopenharmony_ci  return result->BooleanValue(isolate);
12371cb0ef41Sopenharmony_ci}
12381cb0ef41Sopenharmony_ci
12391cb0ef41Sopenharmony_ci}  // namespace
12401cb0ef41Sopenharmony_ci
12411cb0ef41Sopenharmony_ci// static
12421cb0ef41Sopenharmony_ciMaybeHandle<FixedArray> WasmScript::CheckBreakPoints(Isolate* isolate,
12431cb0ef41Sopenharmony_ci                                                     Handle<Script> script,
12441cb0ef41Sopenharmony_ci                                                     int position,
12451cb0ef41Sopenharmony_ci                                                     StackFrameId frame_id) {
12461cb0ef41Sopenharmony_ci  if (!script->has_wasm_breakpoint_infos()) return {};
12471cb0ef41Sopenharmony_ci
12481cb0ef41Sopenharmony_ci  Handle<FixedArray> breakpoint_infos(script->wasm_breakpoint_infos(), isolate);
12491cb0ef41Sopenharmony_ci  int insert_pos =
12501cb0ef41Sopenharmony_ci      FindBreakpointInfoInsertPos(isolate, breakpoint_infos, position);
12511cb0ef41Sopenharmony_ci  if (insert_pos >= breakpoint_infos->length()) return {};
12521cb0ef41Sopenharmony_ci
12531cb0ef41Sopenharmony_ci  Handle<Object> maybe_breakpoint_info(breakpoint_infos->get(insert_pos),
12541cb0ef41Sopenharmony_ci                                       isolate);
12551cb0ef41Sopenharmony_ci  if (maybe_breakpoint_info->IsUndefined(isolate)) return {};
12561cb0ef41Sopenharmony_ci  Handle<BreakPointInfo> breakpoint_info =
12571cb0ef41Sopenharmony_ci      Handle<BreakPointInfo>::cast(maybe_breakpoint_info);
12581cb0ef41Sopenharmony_ci  if (breakpoint_info->source_position() != position) return {};
12591cb0ef41Sopenharmony_ci
12601cb0ef41Sopenharmony_ci  Handle<Object> break_points(breakpoint_info->break_points(), isolate);
12611cb0ef41Sopenharmony_ci  if (!break_points->IsFixedArray()) {
12621cb0ef41Sopenharmony_ci    if (!CheckBreakPoint(isolate, Handle<BreakPoint>::cast(break_points),
12631cb0ef41Sopenharmony_ci                         frame_id)) {
12641cb0ef41Sopenharmony_ci      return {};
12651cb0ef41Sopenharmony_ci    }
12661cb0ef41Sopenharmony_ci    Handle<FixedArray> break_points_hit = isolate->factory()->NewFixedArray(1);
12671cb0ef41Sopenharmony_ci    break_points_hit->set(0, *break_points);
12681cb0ef41Sopenharmony_ci    return break_points_hit;
12691cb0ef41Sopenharmony_ci  }
12701cb0ef41Sopenharmony_ci
12711cb0ef41Sopenharmony_ci  Handle<FixedArray> array = Handle<FixedArray>::cast(break_points);
12721cb0ef41Sopenharmony_ci  Handle<FixedArray> break_points_hit =
12731cb0ef41Sopenharmony_ci      isolate->factory()->NewFixedArray(array->length());
12741cb0ef41Sopenharmony_ci  int break_points_hit_count = 0;
12751cb0ef41Sopenharmony_ci  for (int i = 0; i < array->length(); ++i) {
12761cb0ef41Sopenharmony_ci    Handle<BreakPoint> break_point(BreakPoint::cast(array->get(i)), isolate);
12771cb0ef41Sopenharmony_ci    if (CheckBreakPoint(isolate, break_point, frame_id)) {
12781cb0ef41Sopenharmony_ci      break_points_hit->set(break_points_hit_count++, *break_point);
12791cb0ef41Sopenharmony_ci    }
12801cb0ef41Sopenharmony_ci  }
12811cb0ef41Sopenharmony_ci  if (break_points_hit_count == 0) return {};
12821cb0ef41Sopenharmony_ci  break_points_hit->Shrink(isolate, break_points_hit_count);
12831cb0ef41Sopenharmony_ci  return break_points_hit;
12841cb0ef41Sopenharmony_ci}
12851cb0ef41Sopenharmony_ci
12861cb0ef41Sopenharmony_ci}  // namespace internal
12871cb0ef41Sopenharmony_ci}  // namespace v8
1288