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