Commit c134f0af authored by Thibaud Michaud's avatar Thibaud Michaud Committed by V8 LUCI CQ

[wasm][liftoff] Add step counter in Liftoff

Add a new testing tier based on Liftoff. In this tier, the Liftoff
compiler takes an address to a counter, and decrements that counter at
every instruction. When the counter reaches 0, execution aborts.

R=clemensb@chromium.org

Bug: v8:11856
Change-Id: I20970e323ff19f7cb6ab6855377c678ca391421e
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2944440Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Commit-Queue: Thibaud Michaud <thibaudm@chromium.org>
Cr-Commit-Position: refs/heads/master@{#75022}
parent 385f304d
......@@ -22,6 +22,7 @@
#include "src/utils/ostreams.h"
#include "src/utils/utils.h"
#include "src/wasm/baseline/liftoff-assembler.h"
#include "src/wasm/baseline/liftoff-register.h"
#include "src/wasm/function-body-decoder-impl.h"
#include "src/wasm/function-compiler.h"
#include "src/wasm/memory-tracing.h"
......@@ -455,7 +456,8 @@ class LiftoffCompiler {
std::unique_ptr<AssemblerBuffer> buffer,
DebugSideTableBuilder* debug_sidetable_builder,
ForDebugging for_debugging, int func_index,
Vector<const int> breakpoints = {}, int dead_breakpoint = 0)
Vector<const int> breakpoints = {}, int dead_breakpoint = 0,
int* max_steps = nullptr)
: asm_(std::move(buffer)),
descriptor_(
GetLoweredCallDescriptor(compilation_zone, call_descriptor)),
......@@ -471,7 +473,8 @@ class LiftoffCompiler {
next_breakpoint_ptr_(breakpoints.begin()),
next_breakpoint_end_(breakpoints.end()),
dead_breakpoint_(dead_breakpoint),
handlers_(compilation_zone) {
handlers_(compilation_zone),
max_steps_(max_steps) {
if (breakpoints.empty()) {
next_breakpoint_ptr_ = next_breakpoint_end_ = nullptr;
}
......@@ -1018,6 +1021,26 @@ class LiftoffCompiler {
EmitBreakpoint(decoder);
__ bind(&cont);
}
if (V8_UNLIKELY(max_steps_ != nullptr)) {
LiftoffRegList pinned;
LiftoffRegister max_steps = __ GetUnusedRegister(kGpReg, {});
pinned.set(max_steps);
LiftoffRegister max_steps_addr = __ GetUnusedRegister(kGpReg, pinned);
pinned.set(max_steps_addr);
__ LoadConstant(
max_steps_addr,
WasmValue::ForUintPtr(reinterpret_cast<uintptr_t>(max_steps_)));
__ Load(max_steps, max_steps_addr.gp(), no_reg, 0, LoadType::kI32Load,
pinned);
Label cont;
__ emit_i32_cond_jumpi(kUnequal, &cont, max_steps.gp(), 0);
// Abort.
Trap(decoder, kTrapUnreachable);
__ bind(&cont);
__ emit_i32_subi(max_steps.gp(), max_steps.gp(), 1);
__ Store(max_steps_addr.gp(), no_reg, 0, max_steps, StoreType::kI32Store,
pinned);
}
}
void NextInstruction(FullDecoder* decoder, WasmOpcode opcode) {
......@@ -6079,6 +6102,8 @@ class LiftoffCompiler {
// Current number of exception refs on the stack.
int num_exceptions_ = 0;
int* max_steps_;
bool has_outstanding_op() const {
return outstanding_op_ != kNoOutstandingOp;
}
......@@ -6135,7 +6160,8 @@ WasmCompilationResult ExecuteLiftoffCompilation(
AccountingAllocator* allocator, CompilationEnv* env,
const FunctionBody& func_body, int func_index, ForDebugging for_debugging,
Counters* counters, WasmFeatures* detected, Vector<const int> breakpoints,
std::unique_ptr<DebugSideTable>* debug_sidetable, int dead_breakpoint) {
std::unique_ptr<DebugSideTable>* debug_sidetable, int dead_breakpoint,
int* max_steps) {
int func_body_size = static_cast<int>(func_body.end - func_body.start);
TRACE_EVENT2(TRACE_DISABLED_BY_DEFAULT("v8.wasm.detailed"),
"wasm.CompileBaseline", "funcIndex", func_index, "bodySize",
......@@ -6153,11 +6179,12 @@ WasmCompilationResult ExecuteLiftoffCompilation(
if (debug_sidetable) {
debug_sidetable_builder = std::make_unique<DebugSideTableBuilder>();
}
DCHECK_IMPLIES(max_steps, for_debugging == kForDebugging);
WasmFullDecoder<Decoder::kBooleanValidation, LiftoffCompiler> decoder(
&zone, env->module, env->enabled_features, detected, func_body,
call_descriptor, env, &zone, instruction_buffer->CreateView(),
debug_sidetable_builder.get(), for_debugging, func_index, breakpoints,
dead_breakpoint);
dead_breakpoint, max_steps);
decoder.Decode();
LiftoffCompiler* compiler = &decoder.interface();
if (decoder.failed()) compiler->OnFirstError(&decoder);
......
......@@ -57,7 +57,8 @@ V8_EXPORT_PRIVATE WasmCompilationResult ExecuteLiftoffCompilation(
AccountingAllocator*, CompilationEnv*, const FunctionBody&, int func_index,
ForDebugging, Counters*, WasmFeatures* detected_features,
Vector<const int> breakpoints = {},
std::unique_ptr<DebugSideTable>* = nullptr, int dead_breakpoint = 0);
std::unique_ptr<DebugSideTable>* = nullptr, int dead_breakpoint = 0,
int* max_steps = nullptr);
V8_EXPORT_PRIVATE std::unique_ptr<DebugSideTable> GenerateLiftoffDebugSideTable(
const WasmCode*);
......
......@@ -430,6 +430,7 @@ v8_source_set("cctest_sources") {
"wasm/test-gc.cc",
"wasm/test-grow-memory.cc",
"wasm/test-jump-table-assembler.cc",
"wasm/test-liftoff-for-fuzzing.cc",
"wasm/test-liftoff-inspection.cc",
"wasm/test-run-wasm-64.cc",
"wasm/test-run-wasm-asmjs.cc",
......
......@@ -586,6 +586,7 @@
'test-gc/*': [SKIP],
'test-grow-memory/*': [SKIP],
'test-js-to-wasm/*': [SKIP],
'test-liftoff-for-fuzzing/*': [SKIP],
'test-liftoff-inspection/*': [SKIP],
'test-run-wasm*': [SKIP],
'test-streaming-compilation/*': [SKIP],
......
// Copyright 2021 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// #include "src/api/api-inl.h"
// #include "test/cctest/wasm/wasm-atomics-utils.h"
#include "test/cctest/cctest.h"
#include "test/cctest/wasm/wasm-run-utils.h"
#include "test/common/wasm/test-signatures.h"
#include "test/common/wasm/wasm-macro-gen.h"
namespace v8 {
namespace internal {
namespace wasm {
namespace test_liftoff_for_fuzzing {
TEST(MaxSteps) {
WasmRunner<uint32_t> r(TestExecutionTier::kLiftoffForFuzzing);
BUILD(r, WASM_LOOP(WASM_BR(0)), WASM_I32V(23));
r.SetMaxSteps(10);
r.CheckCallViaJSTraps();
}
} // namespace test_liftoff_for_fuzzing
} // namespace wasm
} // namespace internal
} // namespace v8
......@@ -4,9 +4,11 @@
#include "test/cctest/wasm/wasm-run-utils.h"
#include "src/base/optional.h"
#include "src/codegen/assembler-inl.h"
#include "src/diagnostics/code-tracer.h"
#include "src/heap/heap-inl.h"
#include "src/wasm/baseline/liftoff-compiler.h"
#include "src/wasm/graph-builder-interface.h"
#include "src/wasm/leb-helper.h"
#include "src/wasm/module-compiler.h"
......@@ -547,15 +549,26 @@ void WasmFunctionCompiler::Build(const byte* start, const byte* end) {
builder_->instance_object()->module_object().native_module();
ForDebugging for_debugging =
native_module->IsTieredDown() ? kForDebugging : kNoDebugging;
WasmCompilationUnit unit(function_->func_index, builder_->execution_tier(),
for_debugging);
WasmFeatures unused_detected_features;
WasmCompilationResult result = unit.ExecuteCompilation(
isolate()->wasm_engine(), &env,
native_module->compilation_state()->GetWireBytesStorage(),
isolate()->counters(), &unused_detected_features);
base::Optional<WasmCompilationResult> result;
if (builder_->test_execution_tier() ==
TestExecutionTier::kLiftoffForFuzzing) {
result.emplace(ExecuteLiftoffCompilation(
isolate()->wasm_engine()->allocator(), &env, func_body,
function_->func_index, kForDebugging, isolate()->counters(),
&unused_detected_features, {}, nullptr, 0, builder_->max_steps_ptr()));
} else {
WasmCompilationUnit unit(function_->func_index, builder_->execution_tier(),
for_debugging);
result.emplace(unit.ExecuteCompilation(
isolate()->wasm_engine(), &env,
native_module->compilation_state()->GetWireBytesStorage(),
isolate()->counters(), &unused_detected_features));
}
WasmCode* code = native_module->PublishCode(
native_module->AddCompiledCode(std::move(result)));
native_module->AddCompiledCode(std::move(*result)));
DCHECK_NOT_NULL(code);
DisallowGarbageCollection no_gc;
Script script = builder_->instance_object()->module_object().script();
......
......@@ -50,7 +50,8 @@ namespace wasm {
enum class TestExecutionTier : int8_t {
kLiftoff = static_cast<int8_t>(ExecutionTier::kLiftoff),
kTurbofan = static_cast<int8_t>(ExecutionTier::kTurbofan),
kInterpreter
kInterpreter,
kLiftoffForFuzzing
};
static_assert(
std::is_same<std::underlying_type<ExecutionTier>::type,
......@@ -242,6 +243,8 @@ class TestingModuleBuilder {
CompilationEnv CreateCompilationEnv();
TestExecutionTier test_execution_tier() const { return execution_tier_; }
ExecutionTier execution_tier() const {
switch (execution_tier_) {
case TestExecutionTier::kTurbofan:
......@@ -257,6 +260,9 @@ class TestingModuleBuilder {
return runtime_exception_support_;
}
void set_max_steps(int n) { max_steps_ = n; }
int* max_steps_ptr() { return &max_steps_; }
void EnableFeature(WasmFeature feature) { enabled_features_.Add(feature); }
private:
......@@ -272,6 +278,7 @@ class TestingModuleBuilder {
Handle<WasmInstanceObject> instance_object_;
NativeModule* native_module_ = nullptr;
RuntimeExceptionSupport runtime_exception_support_;
int max_steps_ = 0;
// Data segment arrays that are normally allocated on the instance.
std::vector<byte> data_segment_data_;
......@@ -626,6 +633,8 @@ class WasmRunner : public WasmRunnerBase {
void CheckCallViaJSTraps(ParamTypes... p) {
CheckCallViaJS(static_cast<double>(0xDEADBEEF), p...);
}
void SetMaxSteps(int n) { builder_.set_max_steps(n); }
};
// A macro to define tests that run in different engine configurations.
......
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