Commit 59bda196 authored by Clemens Backes's avatar Clemens Backes Committed by Commit Bot

[wasm] Add builtin and runtime function for debug breaks

This CL adds the "WasmDebugBreak" builtin for x64, ia32, arm and arm64.
It stores all wasm parameter registers to the stack and calls the
respective runtime function.
The runtime function does not do anything yet, but the
inspector/debugger/wasm-set-breakpoint-liftoff test will already execute
both the builtin and the runtime function.

R=thibaudm@chromium.org

Bug: v8:10147
Change-Id: I445fdd7c202480ece951f5efbb4845cf21410d91
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2036082Reviewed-by: 's avatarThibaud Michaud <thibaudm@chromium.org>
Reviewed-by: 's avatarJakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66126}
parent cf1fad58
......@@ -6,15 +6,15 @@
#include "src/api/api-arguments.h"
#include "src/codegen/code-factory.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frame-constants.h"
#include "src/execution/frames.h"
#include "src/logging/counters.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/heap/heap-inl.h"
#include "src/logging/counters.h"
#include "src/objects/cell.h"
#include "src/objects/foreign.h"
#include "src/objects/heap-number.h"
......@@ -22,6 +22,7 @@
#include "src/objects/objects-inl.h"
#include "src/objects/smi.h"
#include "src/runtime/runtime.h"
#include "src/wasm/wasm-linkage.h"
#include "src/wasm/wasm-objects.h"
namespace v8 {
......@@ -2433,6 +2434,37 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Jump(r8);
}
void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) {
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
{
// TODO(clemensb): Use a separate frame type and make it inspectable.
FrameAndConstantPoolScope scope(masm, StackFrame::INTERNAL);
// Save all parameter registers. They might hold live values, we restore
// them after the runtime call.
RegList gp_regs = 0;
for (Register reg : wasm::kGpParamRegisters) gp_regs |= reg.bit();
constexpr DwVfpRegister lowest_fp_reg = wasm::kFpParamRegisters[0];
constexpr DwVfpRegister highest_fp_reg =
wasm::kFpParamRegisters[arraysize(wasm::kFpParamRegisters) - 1];
STATIC_ASSERT(arraysize(wasm::kFpParamRegisters) ==
highest_fp_reg.code() - lowest_fp_reg.code() + 1);
__ stm(db_w, sp, gp_regs);
__ vstm(db_w, sp, lowest_fp_reg, highest_fp_reg);
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(cp, Smi::zero());
__ CallRuntime(Runtime::kWasmDebugBreak, 0);
// Restore registers.
__ vldm(ia_w, sp, lowest_fp_reg, highest_fp_reg);
__ ldm(ia_w, sp, gp_regs);
}
__ Ret();
}
void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
SaveFPRegsMode save_doubles, ArgvMode argv_mode,
bool builtin_exit_frame) {
......
......@@ -6,15 +6,15 @@
#include "src/api/api-arguments.h"
#include "src/codegen/code-factory.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frame-constants.h"
#include "src/execution/frames.h"
#include "src/logging/counters.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/heap/heap-inl.h"
#include "src/logging/counters.h"
#include "src/objects/cell.h"
#include "src/objects/foreign.h"
#include "src/objects/heap-number.h"
......@@ -22,6 +22,7 @@
#include "src/objects/objects-inl.h"
#include "src/objects/smi.h"
#include "src/runtime/runtime.h"
#include "src/wasm/wasm-linkage.h"
#include "src/wasm/wasm-objects.h"
#if defined(V8_OS_WIN)
......@@ -2950,6 +2951,40 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ Jump(x8);
}
void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) {
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
{
// TODO(clemensb): Use a separate frame type and make it inspectable.
FrameScope scope(masm, StackFrame::INTERNAL);
// Save all parameter registers. They might hold live values, we restore
// them after the runtime call.
RegList gp_regs = 0;
for (Register reg : wasm::kGpParamRegisters) gp_regs |= reg.bit();
// The size of {gp_regs} must be a multiple of 2, so that the total pushed
// size is a multiple of 16 bytes.
if (NumRegs(gp_regs) % 2) {
// Just add any unset register.
gp_regs |= 1 << base::bits::CountTrailingZeros(~gp_regs);
}
RegList fp_regs = 0;
for (DoubleRegister reg : wasm::kFpParamRegisters) fp_regs |= reg.bit();
__ PushXRegList(gp_regs);
__ PushDRegList(fp_regs);
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(cp, Smi::zero());
__ CallRuntime(Runtime::kWasmDebugBreak, 0);
// Restore registers.
__ PopDRegList(fp_regs);
__ PopXRegList(gp_regs);
}
__ Ret();
}
void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
SaveFPRegsMode save_doubles, ArgvMode argv_mode,
bool builtin_exit_frame) {
......
......@@ -858,6 +858,7 @@ namespace internal {
\
/* Wasm */ \
ASM(WasmCompileLazy, Dummy) \
ASM(WasmDebugBreak, Dummy) \
TFC(WasmAtomicNotify, WasmAtomicNotify) \
TFC(WasmI32AtomicWait, WasmI32AtomicWait) \
TFC(WasmI64AtomicWait, WasmI64AtomicWait) \
......
......@@ -7,15 +7,15 @@
#include "src/api/api-arguments.h"
#include "src/base/iterator.h"
#include "src/codegen/code-factory.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/debug/debug.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frame-constants.h"
#include "src/execution/frames.h"
#include "src/logging/counters.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/heap/heap-inl.h"
#include "src/logging/counters.h"
#include "src/objects/cell.h"
#include "src/objects/foreign.h"
#include "src/objects/heap-number.h"
......@@ -2594,6 +2594,47 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ jmp(edi);
}
void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) {
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
{
// TODO(clemensb): Use a separate frame type and make it inspectable.
FrameScope scope(masm, StackFrame::INTERNAL);
// Save all parameter registers. They might hold live values, we restore
// them after the runtime call.
// TODO(clemensb): Make these registers available for inspection.
for (Register reg : wasm::kGpParamRegisters) {
__ Push(reg);
}
constexpr int kFpStackSize =
kSimd128Size * arraysize(wasm::kFpParamRegisters);
__ AllocateStackSpace(kFpStackSize);
int offset = 0;
for (DoubleRegister reg : wasm::kFpParamRegisters) {
__ movdqu(Operand(esp, offset), reg);
offset += kSimd128Size;
}
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(kContextRegister, Smi::zero());
__ CallRuntime(Runtime::kWasmDebugBreak, 0);
// Restore registers.
for (DoubleRegister reg : base::Reversed(wasm::kFpParamRegisters)) {
offset -= kSimd128Size;
__ movdqu(reg, Operand(esp, offset));
}
__ add(esp, Immediate(kFpStackSize));
for (Register reg : base::Reversed(wasm::kGpParamRegisters)) {
__ Pop(reg);
}
}
__ ret(0);
}
void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
SaveFPRegsMode save_doubles, ArgvMode argv_mode,
bool builtin_exit_frame) {
......
......@@ -7,15 +7,15 @@
#include "src/api/api-arguments.h"
#include "src/base/iterator.h"
#include "src/codegen/code-factory.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/codegen/x64/assembler-x64.h"
#include "src/deoptimizer/deoptimizer.h"
#include "src/execution/frame-constants.h"
#include "src/execution/frames.h"
#include "src/logging/counters.h"
// For interpreter_entry_return_pc_offset. TODO(jkummerow): Drop.
#include "src/codegen/macro-assembler-inl.h"
#include "src/codegen/register-configuration.h"
#include "src/heap/heap-inl.h"
#include "src/logging/counters.h"
#include "src/objects/cell.h"
#include "src/objects/debug-objects.h"
#include "src/objects/foreign.h"
......@@ -23,6 +23,7 @@
#include "src/objects/js-generator.h"
#include "src/objects/objects-inl.h"
#include "src/objects/smi.h"
#include "src/wasm/baseline/liftoff-assembler-defs.h"
#include "src/wasm/wasm-linkage.h"
#include "src/wasm/wasm-objects.h"
......@@ -2575,6 +2576,46 @@ void Builtins::Generate_WasmCompileLazy(MacroAssembler* masm) {
__ jmp(r11);
}
void Builtins::Generate_WasmDebugBreak(MacroAssembler* masm) {
HardAbortScope hard_abort(masm); // Avoid calls to Abort.
{
// TODO(clemensb): Use a separate frame type and make it inspectable.
FrameScope scope(masm, StackFrame::INTERNAL);
// Save all parameter registers. They might hold live values, we restore
// them after the runtime call.
for (Register reg : wasm::kGpParamRegisters) {
__ Push(reg);
}
constexpr int kFpStackSize =
kSimd128Size * arraysize(wasm::kFpParamRegisters);
__ AllocateStackSpace(kFpStackSize);
int offset = 0;
for (DoubleRegister reg : wasm::kFpParamRegisters) {
__ movdqu(Operand(rsp, offset), reg);
offset += kSimd128Size;
}
// Initialize the JavaScript context with 0. CEntry will use it to
// set the current context on the isolate.
__ Move(kContextRegister, Smi::zero());
__ CallRuntime(Runtime::kWasmDebugBreak, 0);
// Restore registers.
for (DoubleRegister reg : base::Reversed(wasm::kFpParamRegisters)) {
offset -= kSimd128Size;
__ movdqu(reg, Operand(rsp, offset));
}
__ addq(rsp, Immediate(kFpStackSize));
for (Register reg : base::Reversed(wasm::kGpParamRegisters)) {
__ Pop(reg);
}
}
__ ret(0);
}
void Builtins::Generate_CEntry(MacroAssembler* masm, int result_size,
SaveFPRegsMode save_doubles, ArgvMode argv_mode,
bool builtin_exit_frame) {
......
......@@ -602,5 +602,15 @@ RUNTIME_FUNCTION(Runtime_WasmNewMultiReturnJSArray) {
fixed_array_handle, PACKED_ELEMENTS);
return *array;
}
RUNTIME_FUNCTION(Runtime_WasmDebugBreak) {
HandleScope scope(isolate);
DCHECK_EQ(0, args.length());
// TODO(clemensb): Implement.
return ReadOnlyRoots(isolate).undefined_value();
}
} // namespace internal
} // namespace v8
......@@ -570,7 +570,8 @@ namespace internal {
F(WasmIsValidFuncRefValue, 1, 1) \
F(WasmCompileLazy, 2, 1) \
F(WasmNewMultiReturnFixedArray, 1, 1) \
F(WasmNewMultiReturnJSArray, 1, 1)
F(WasmNewMultiReturnJSArray, 1, 1) \
F(WasmDebugBreak, 0, 1)
#define FOR_EACH_INTRINSIC_RETURN_PAIR_IMPL(F, I) \
F(DebugBreakOnBytecode, 1, 2) \
......
......@@ -714,6 +714,7 @@ class LiftoffAssembler : public TurboAssembler {
inline void DeallocateStackSlot(uint32_t size);
inline void DebugBreak();
////////////////////////////////////
// End of platform-specific part. //
////////////////////////////////////
......
......@@ -651,16 +651,20 @@ class LiftoffCompiler {
if (next_breakpoint_ptr_ == next_breakpoint_end_) {
next_breakpoint_ptr_ = next_breakpoint_end_ = nullptr;
}
EmitBreakpoint();
EmitBreakpoint(decoder);
}
TraceCacheState(decoder);
SLOW_DCHECK(__ ValidateCacheState());
DEBUG_CODE_COMMENT(WasmOpcodes::OpcodeName(opcode));
}
void EmitBreakpoint() {
void EmitBreakpoint(FullDecoder* decoder) {
DEBUG_CODE_COMMENT("breakpoint");
// TODO(clemensb): Actually emit a breakpoint.
source_position_table_builder_.AddPosition(
__ pc_offset(), SourcePosition(decoder->position()), false);
__ CallRuntimeStub(WasmCode::kWasmDebugBreak);
RegisterDebugSideTableEntry();
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
}
void Block(FullDecoder* decoder, Control* block) {}
......
......@@ -48,6 +48,7 @@ struct WasmModule;
#define WASM_RUNTIME_STUB_LIST(V, VTRAP) \
FOREACH_WASM_TRAPREASON(VTRAP) \
V(WasmCompileLazy) \
V(WasmDebugBreak) \
V(WasmAtomicNotify) \
V(WasmI32AtomicWait) \
V(WasmI64AtomicWait) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment