[wasm] Add return value to the tracing of function calls

Added return value display when tracing function calls in wasm.
The new types handled are I32, I64, F32 and F64.
Only single return value is handled.

R=clemensb@chromium.org

Bug: v8:10559
Change-Id: I726d08fcfdc8bf2c3e43a25ec1932412ff74387b
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2225024
Reviewed-by: Clemens Backes <clemensb@chromium.org>
Commit-Queue: Arnaud Robin <arobin@google.com>
Cr-Commit-Position: refs/heads/master@{#68143}
This commit is contained in:
Arnaud Robin 2020-06-03 15:38:42 +02:00 committed by Commit Bot
parent a9b7830d3a
commit 171d94111a
8 changed files with 129 additions and 4 deletions

View File

@ -22,6 +22,7 @@ extern runtime WasmStackGuard(Context): JSAny;
extern runtime ThrowWasmStackOverflow(Context): JSAny; extern runtime ThrowWasmStackOverflow(Context): JSAny;
extern runtime WasmTraceMemory(Context, Smi): JSAny; extern runtime WasmTraceMemory(Context, Smi): JSAny;
extern runtime WasmTraceEnter(Context): JSAny; extern runtime WasmTraceEnter(Context): JSAny;
extern runtime WasmTraceExit(Context, Smi): JSAny;
extern runtime WasmAtomicNotify( extern runtime WasmAtomicNotify(
Context, WasmInstanceObject, Number, Number): Smi; Context, WasmInstanceObject, Number, Number): Smi;
extern runtime WasmI32AtomicWait( extern runtime WasmI32AtomicWait(
@ -215,6 +216,10 @@ builtin WasmTraceEnter(): JSAny {
tail runtime::WasmTraceEnter(LoadContextFromFrame()); tail runtime::WasmTraceEnter(LoadContextFromFrame());
} }
builtin WasmTraceExit(info: Smi): JSAny {
tail runtime::WasmTraceExit(LoadContextFromFrame(), info);
}
builtin WasmAllocateJSArray(implicit context: Context)(size: Smi): JSArray { builtin WasmAllocateJSArray(implicit context: Context)(size: Smi): JSArray {
const map: Map = GetFastPackedElementsJSArrayMap(); const map: Map = GetFastPackedElementsJSArrayMap();
return AllocateJSArray(ElementsKind::PACKED_ELEMENTS, map, size, size); return AllocateJSArray(ElementsKind::PACKED_ELEMENTS, map, size, size);

View File

@ -950,11 +950,65 @@ RUNTIME_FUNCTION(Runtime_TraceExit) {
RUNTIME_FUNCTION(Runtime_WasmTraceEnter) { RUNTIME_FUNCTION(Runtime_WasmTraceEnter) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK_EQ(0, args.length()); DCHECK_EQ(0, args.length());
// TODO(10559): Print more useful info here. // TODO(10559): Print function name and indentation.
PrintF("Enter function\n"); PrintF("Enter function\n");
return ReadOnlyRoots(isolate).undefined_value(); return ReadOnlyRoots(isolate).undefined_value();
} }
RUNTIME_FUNCTION(Runtime_WasmTraceExit) {
HandleScope shs(isolate);
DCHECK_EQ(1, args.length());
CONVERT_ARG_CHECKED(Smi, value_addr_smi, 0);
// TODO(10559): Print function name and indentation.
PrintF("Exit function");
// Find the caller wasm frame.
wasm::WasmCodeRefScope wasm_code_ref_scope;
StackTraceFrameIterator it(isolate);
DCHECK(!it.done());
DCHECK(it.is_wasm());
WasmFrame* frame = WasmFrame::cast(it.frame());
int func_index = frame->function_index();
const wasm::FunctionSig* sig =
frame->wasm_instance().module()->functions[func_index].sig;
size_t num_returns = sig->return_count();
if (num_returns == 1) {
wasm::ValueType return_type = sig->GetReturn(0);
switch (return_type.kind()) {
case wasm::ValueType::kI32: {
int32_t value = ReadUnalignedValue<int32_t>(value_addr_smi.ptr());
PrintF(" -> %d\n", value);
break;
}
case wasm::ValueType::kI64: {
int64_t value = ReadUnalignedValue<int64_t>(value_addr_smi.ptr());
PrintF(" -> %" PRId64 "\n", value);
break;
}
case wasm::ValueType::kF32: {
float_t value = ReadUnalignedValue<float_t>(value_addr_smi.ptr());
PrintF(" -> %f\n", value);
break;
}
case wasm::ValueType::kF64: {
double_t value = ReadUnalignedValue<double_t>(value_addr_smi.ptr());
PrintF(" -> %f\n", value);
break;
}
default:
PrintF(" -> Unsupported type\n");
break;
}
} else {
// TODO(wasm) Handle multiple return values.
PrintF("\n");
}
return ReadOnlyRoots(isolate).undefined_value();
}
RUNTIME_FUNCTION(Runtime_HaveSameMap) { RUNTIME_FUNCTION(Runtime_HaveSameMap) {
SealHandleScope shs(isolate); SealHandleScope shs(isolate);
DCHECK_EQ(2, args.length()); DCHECK_EQ(2, args.length());

View File

@ -543,6 +543,7 @@ namespace internal {
F(WasmTierUpFunction, 2, 1) \ F(WasmTierUpFunction, 2, 1) \
F(WasmTierUpModule, 1, 1) \ F(WasmTierUpModule, 1, 1) \
F(WasmTraceEnter, 0, 1) \ F(WasmTraceEnter, 0, 1) \
F(WasmTraceExit, 1, 1) \
F(WasmTraceMemory, 1, 1) \ F(WasmTraceMemory, 1, 1) \
I(DeoptimizeNow, 0, 1) I(DeoptimizeNow, 0, 1)

View File

@ -284,6 +284,8 @@ class LiftoffAssembler : public TurboAssembler {
explicit LiftoffAssembler(std::unique_ptr<AssemblerBuffer>); explicit LiftoffAssembler(std::unique_ptr<AssemblerBuffer>);
~LiftoffAssembler() override; ~LiftoffAssembler() override;
LiftoffRegister LoadToRegister(VarState slot, LiftoffRegList pinned);
LiftoffRegister PopToRegister(LiftoffRegList pinned = {}); LiftoffRegister PopToRegister(LiftoffRegList pinned = {});
// Returns the register which holds the value of stack slot {index}. If the // Returns the register which holds the value of stack slot {index}. If the
@ -1138,7 +1140,6 @@ class LiftoffAssembler : public TurboAssembler {
} }
private: private:
LiftoffRegister LoadToRegister(VarState slot, LiftoffRegList pinned);
LiftoffRegister LoadI64HalfIntoRegister(VarState slot, RegPairHalf half); LiftoffRegister LoadI64HalfIntoRegister(VarState slot, RegPairHalf half);
uint32_t num_locals_ = 0; uint32_t num_locals_ = 0;

View File

@ -1545,7 +1545,45 @@ class LiftoffCompiler {
__ cache_state()->stack_state.pop_back(); __ cache_state()->stack_state.pop_back();
} }
void TraceFunctionExit(FullDecoder* decoder) {
DEBUG_CODE_COMMENT("trace function exit");
// Before making the runtime call, spill all cache registers.
__ SpillAllRegisters();
LiftoffRegList pinned;
// Get a register to hold the stack slot for the return value.
LiftoffRegister info = pinned.set(__ GetUnusedRegister(kGpReg, pinned));
__ AllocateStackSlot(info.gp(), sizeof(int64_t));
// Store the return value if there is exactly one. Multiple return values
// are not handled yet.
size_t num_returns = decoder->sig_->return_count();
if (num_returns == 1) {
ValueType return_type = decoder->sig_->GetReturn(0);
LiftoffRegister return_reg =
__ LoadToRegister(__ cache_state()->stack_state.back(), pinned);
__ Store(info.gp(), no_reg, 0, return_reg,
StoreType::ForValueType(return_type), pinned);
}
// Put the parameter in its place.
WasmTraceExitDescriptor descriptor;
DCHECK_EQ(0, descriptor.GetStackParameterCount());
DCHECK_EQ(1, descriptor.GetRegisterParameterCount());
Register param_reg = descriptor.GetRegisterParameter(0);
if (info.gp() != param_reg) {
__ Move(param_reg, info.gp(), LiftoffAssembler::kWasmIntPtr);
}
source_position_table_builder_.AddPosition(
__ pc_offset(), SourcePosition(decoder->position()), false);
__ CallRuntimeStub(WasmCode::kWasmTraceExit);
safepoint_table_builder_.DefineSafepoint(&asm_, Safepoint::kNoLazyDeopt);
__ DeallocateStackSlot(sizeof(int64_t));
}
void ReturnImpl(FullDecoder* decoder) { void ReturnImpl(FullDecoder* decoder) {
if (FLAG_trace_wasm) TraceFunctionExit(decoder);
size_t num_returns = decoder->sig_->return_count(); size_t num_returns = decoder->sig_->return_count();
if (num_returns > 0) __ MoveToReturnLocations(decoder->sig_, descriptor_); if (num_returns > 0) __ MoveToReturnLocations(decoder->sig_, descriptor_);
DEBUG_CODE_COMMENT("leave frame"); DEBUG_CODE_COMMENT("leave frame");

View File

@ -72,6 +72,7 @@ struct WasmModule;
V(WasmThrow) \ V(WasmThrow) \
V(WasmRethrow) \ V(WasmRethrow) \
V(WasmTraceEnter) \ V(WasmTraceEnter) \
V(WasmTraceExit) \
V(WasmTraceMemory) \ V(WasmTraceMemory) \
V(ArgumentsAdaptorTrampoline) \ V(ArgumentsAdaptorTrampoline) \
V(BigIntToI32Pair) \ V(BigIntToI32Pair) \

View File

@ -8,11 +8,28 @@ load('test/mjsunit/wasm/wasm-module-builder.js');
let builder = new WasmModuleBuilder(); let builder = new WasmModuleBuilder();
let kRet23Function = builder.addFunction('ret_23', kSig_i_v) let kRet23Function = builder.addFunction('ret_23', kSig_i_v)
.addBody([kExprI32Const, 23]) .addBody([kExprI32Const, 23])
.exportFunc()
.index;
let kRet57Function = builder.addFunction('ret_57', kSig_l_v)
.addBody([kExprI64Const, 57])
.exportFunc()
.index;
let kRet0Function = builder.addFunction('ret_0', kSig_f_v)
.addBody(wasmF32Const(0))
.exportFunc()
.index;
let kRet1Function = builder.addFunction('ret_1', kSig_d_v)
.addBody(wasmF64Const(1))
.exportFunc() .exportFunc()
.index; .index;
builder.addFunction('main', kSig_v_v) builder.addFunction('main', kSig_v_v)
.addBody([kExprCallFunction, kRet23Function, kExprDrop]) .addBody([
kExprCallFunction, kRet23Function, kExprDrop, // -
kExprCallFunction, kRet57Function, kExprDrop, // -
kExprCallFunction, kRet0Function, kExprDrop, // -
kExprCallFunction, kRet1Function, kExprDrop // -
])
.exportAs('main'); .exportAs('main');
let instance = builder.instantiate(); let instance = builder.instantiate();

View File

@ -1,2 +1,10 @@
Enter function Enter function
Enter function Enter function
Exit function -> 23
Enter function
Exit function -> 57
Enter function
Exit function -> 0.000000
Enter function
Exit function -> 1.000000
Exit function