[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/+/2036082
Reviewed-by: Thibaud Michaud <thibaudm@chromium.org>
Reviewed-by: Jakob Kummerow <jkummerow@chromium.org>
Commit-Queue: Clemens Backes <clemensb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66126}
This commit is contained in:
Clemens Backes 2020-02-04 18:17:06 +01:00 committed by Commit Bot
parent cf1fad5899
commit 59bda19676
10 changed files with 187 additions and 20 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -858,6 +858,7 @@ namespace internal {
\
/* Wasm */ \
ASM(WasmCompileLazy, Dummy) \
ASM(WasmDebugBreak, Dummy) \
TFC(WasmAtomicNotify, WasmAtomicNotify) \
TFC(WasmI32AtomicWait, WasmI32AtomicWait) \
TFC(WasmI64AtomicWait, WasmI64AtomicWait) \

View File

@ -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) {

View File

@ -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) {

View File

@ -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

View File

@ -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) \

View File

@ -714,6 +714,7 @@ class LiftoffAssembler : public TurboAssembler {
inline void DeallocateStackSlot(uint32_t size);
inline void DebugBreak();
////////////////////////////////////
// End of platform-specific part. //
////////////////////////////////////

View File

@ -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) {}

View File

@ -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) \