2016-12-19 17:22:55 +00:00
|
|
|
// Copyright 2016 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.
|
|
|
|
|
2019-05-21 09:30:15 +00:00
|
|
|
#include "src/codegen/assembler-inl.h"
|
2016-12-19 17:22:55 +00:00
|
|
|
#include "src/debug/debug-interface.h"
|
2019-05-22 07:55:37 +00:00
|
|
|
#include "src/execution/frames-inl.h"
|
2019-05-20 08:54:18 +00:00
|
|
|
#include "src/objects/property-descriptor.h"
|
2019-05-23 13:27:57 +00:00
|
|
|
#include "src/utils/utils.h"
|
2020-04-23 15:56:48 +00:00
|
|
|
#include "src/wasm/wasm-debug.h"
|
2017-09-08 08:39:19 +00:00
|
|
|
#include "src/wasm/wasm-objects-inl.h"
|
2016-12-19 17:22:55 +00:00
|
|
|
#include "test/cctest/cctest.h"
|
|
|
|
#include "test/cctest/compiler/value-helper.h"
|
|
|
|
#include "test/cctest/wasm/wasm-run-utils.h"
|
|
|
|
#include "test/common/wasm/test-signatures.h"
|
2017-04-25 11:29:17 +00:00
|
|
|
#include "test/common/wasm/wasm-macro-gen.h"
|
2016-12-19 17:22:55 +00:00
|
|
|
|
2017-09-01 12:57:34 +00:00
|
|
|
namespace v8 {
|
|
|
|
namespace internal {
|
|
|
|
namespace wasm {
|
2016-12-19 17:22:55 +00:00
|
|
|
|
|
|
|
namespace {
|
|
|
|
|
2019-11-05 13:15:28 +00:00
|
|
|
debug::Location TranslateLocation(WasmRunnerBase* runner,
|
|
|
|
const debug::Location& loc) {
|
|
|
|
// Convert locations from {func_index, offset_in_func} to
|
|
|
|
// {0, offset_in_module}.
|
|
|
|
int func_index = loc.GetLineNumber();
|
|
|
|
int func_offset = runner->builder().GetFunctionAt(func_index)->code.offset();
|
|
|
|
int offset = loc.GetColumnNumber() + func_offset;
|
|
|
|
return {0, offset};
|
|
|
|
}
|
|
|
|
|
2016-12-19 17:22:55 +00:00
|
|
|
void CheckLocations(
|
2019-11-05 13:15:28 +00:00
|
|
|
WasmRunnerBase* runner, NativeModule* native_module, debug::Location start,
|
|
|
|
debug::Location end,
|
2016-12-19 17:22:55 +00:00
|
|
|
std::initializer_list<debug::Location> expected_locations_init) {
|
2017-03-06 20:47:55 +00:00
|
|
|
std::vector<debug::BreakLocation> locations;
|
2019-11-05 13:15:28 +00:00
|
|
|
std::vector<debug::Location> expected_locations;
|
|
|
|
for (auto loc : expected_locations_init) {
|
|
|
|
expected_locations.push_back(TranslateLocation(runner, loc));
|
|
|
|
}
|
|
|
|
|
|
|
|
bool success = WasmScript::GetPossibleBreakpoints(
|
|
|
|
native_module, TranslateLocation(runner, start),
|
|
|
|
TranslateLocation(runner, end), &locations);
|
2016-12-19 17:22:55 +00:00
|
|
|
CHECK(success);
|
|
|
|
|
|
|
|
printf("got %d locations: ", static_cast<int>(locations.size()));
|
|
|
|
for (size_t i = 0, e = locations.size(); i != e; ++i) {
|
|
|
|
printf("%s<%d,%d>", i == 0 ? "" : ", ", locations[i].GetLineNumber(),
|
|
|
|
locations[i].GetColumnNumber());
|
|
|
|
}
|
|
|
|
printf("\n");
|
|
|
|
|
|
|
|
CHECK_EQ(expected_locations.size(), locations.size());
|
|
|
|
for (size_t i = 0, e = locations.size(); i != e; ++i) {
|
|
|
|
CHECK_EQ(expected_locations[i].GetLineNumber(),
|
|
|
|
locations[i].GetLineNumber());
|
|
|
|
CHECK_EQ(expected_locations[i].GetColumnNumber(),
|
|
|
|
locations[i].GetColumnNumber());
|
|
|
|
}
|
|
|
|
}
|
2017-12-17 19:08:07 +00:00
|
|
|
|
2019-11-05 13:15:28 +00:00
|
|
|
void CheckLocationsFail(WasmRunnerBase* runner, NativeModule* native_module,
|
|
|
|
debug::Location start, debug::Location end) {
|
2017-03-06 20:47:55 +00:00
|
|
|
std::vector<debug::BreakLocation> locations;
|
2019-11-05 13:15:28 +00:00
|
|
|
bool success = WasmScript::GetPossibleBreakpoints(
|
|
|
|
native_module, TranslateLocation(runner, start),
|
|
|
|
TranslateLocation(runner, end), &locations);
|
2016-12-19 17:22:55 +00:00
|
|
|
CHECK(!success);
|
|
|
|
}
|
|
|
|
|
2017-03-10 07:06:25 +00:00
|
|
|
class BreakHandler : public debug::DebugDelegate {
|
2017-01-20 13:50:09 +00:00
|
|
|
public:
|
2017-01-24 10:13:33 +00:00
|
|
|
enum Action {
|
|
|
|
Continue = StepAction::LastStepAction + 1,
|
|
|
|
StepNext = StepAction::StepNext,
|
|
|
|
StepIn = StepAction::StepIn,
|
2017-01-25 23:50:57 +00:00
|
|
|
StepOut = StepAction::StepOut
|
2017-01-24 10:13:33 +00:00
|
|
|
};
|
|
|
|
struct BreakPoint {
|
|
|
|
int position;
|
|
|
|
Action action;
|
2019-10-02 15:20:08 +00:00
|
|
|
std::function<void(void)> pre_action;
|
2017-01-24 10:13:33 +00:00
|
|
|
BreakPoint(int position, Action action)
|
2019-10-02 15:20:08 +00:00
|
|
|
: position(position), action(action), pre_action([]() {}) {}
|
|
|
|
BreakPoint(int position, Action action,
|
|
|
|
std::function<void(void)> pre_action)
|
|
|
|
: position(position), action(action), pre_action(pre_action) {}
|
2017-01-24 10:13:33 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
explicit BreakHandler(Isolate* isolate,
|
|
|
|
std::initializer_list<BreakPoint> expected_breaks)
|
|
|
|
: isolate_(isolate), expected_breaks_(expected_breaks) {
|
2017-03-10 07:06:25 +00:00
|
|
|
v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_), this);
|
2017-01-20 13:50:09 +00:00
|
|
|
}
|
2018-09-14 14:54:08 +00:00
|
|
|
~BreakHandler() override {
|
2017-01-24 10:13:33 +00:00
|
|
|
// Check that all expected breakpoints have been hit.
|
|
|
|
CHECK_EQ(count_, expected_breaks_.size());
|
2017-03-10 07:06:25 +00:00
|
|
|
v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_),
|
|
|
|
nullptr);
|
2017-01-20 13:50:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int count() const { return count_; }
|
|
|
|
|
|
|
|
private:
|
|
|
|
Isolate* isolate_;
|
|
|
|
int count_ = 0;
|
2017-01-24 10:13:33 +00:00
|
|
|
std::vector<BreakPoint> expected_breaks_;
|
2017-01-20 13:50:09 +00:00
|
|
|
|
2017-03-10 07:06:25 +00:00
|
|
|
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
|
2017-08-01 16:41:20 +00:00
|
|
|
const std::vector<int>&) override {
|
2017-01-24 10:13:33 +00:00
|
|
|
printf("Break #%d\n", count_);
|
|
|
|
CHECK_GT(expected_breaks_.size(), count_);
|
|
|
|
|
|
|
|
// Check the current position.
|
|
|
|
StackTraceFrameIterator frame_it(isolate_);
|
2020-05-07 09:24:56 +00:00
|
|
|
auto summ = FrameSummary::GetTop(frame_it.frame()).AsWasm();
|
2017-01-24 10:13:33 +00:00
|
|
|
CHECK_EQ(expected_breaks_[count_].position, summ.byte_offset());
|
|
|
|
|
2019-10-02 15:20:08 +00:00
|
|
|
expected_breaks_[count_].pre_action();
|
2017-01-24 10:13:33 +00:00
|
|
|
Action next_action = expected_breaks_[count_].action;
|
|
|
|
switch (next_action) {
|
|
|
|
case Continue:
|
|
|
|
break;
|
|
|
|
case StepNext:
|
|
|
|
case StepIn:
|
|
|
|
case StepOut:
|
|
|
|
isolate_->debug()->PrepareStep(static_cast<StepAction>(next_action));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNREACHABLE();
|
|
|
|
}
|
|
|
|
++count_;
|
|
|
|
}
|
2017-01-20 13:50:09 +00:00
|
|
|
};
|
|
|
|
|
2019-10-02 15:20:08 +00:00
|
|
|
Handle<BreakPoint> SetBreakpoint(WasmRunnerBase* runner, int function_index,
|
|
|
|
int byte_offset,
|
|
|
|
int expected_set_byte_offset = -1) {
|
2020-03-26 17:44:50 +00:00
|
|
|
runner->TierDown();
|
2017-01-20 13:50:09 +00:00
|
|
|
int func_offset =
|
2019-09-10 01:19:59 +00:00
|
|
|
runner->builder().GetFunctionAt(function_index)->code.offset();
|
2017-01-20 13:50:09 +00:00
|
|
|
int code_offset = func_offset + byte_offset;
|
|
|
|
if (expected_set_byte_offset == -1) expected_set_byte_offset = byte_offset;
|
2019-09-10 01:19:59 +00:00
|
|
|
Handle<WasmInstanceObject> instance = runner->builder().instance_object();
|
2019-10-10 10:23:45 +00:00
|
|
|
Handle<Script> script(instance->module_object().script(),
|
|
|
|
runner->main_isolate());
|
2018-02-26 09:20:45 +00:00
|
|
|
static int break_index = 0;
|
|
|
|
Handle<BreakPoint> break_point =
|
2019-09-10 01:19:59 +00:00
|
|
|
runner->main_isolate()->factory()->NewBreakPoint(
|
|
|
|
break_index++, runner->main_isolate()->factory()->empty_string());
|
2019-10-15 14:33:12 +00:00
|
|
|
CHECK(WasmScript::SetBreakPoint(script, &code_offset, break_point));
|
2019-10-02 15:20:08 +00:00
|
|
|
return break_point;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClearBreakpoint(WasmRunnerBase* runner, int function_index,
|
|
|
|
int byte_offset, Handle<BreakPoint> break_point) {
|
|
|
|
int func_offset =
|
|
|
|
runner->builder().GetFunctionAt(function_index)->code.offset();
|
|
|
|
int code_offset = func_offset + byte_offset;
|
|
|
|
Handle<WasmInstanceObject> instance = runner->builder().instance_object();
|
2019-10-10 10:23:45 +00:00
|
|
|
Handle<Script> script(instance->module_object().script(),
|
|
|
|
runner->main_isolate());
|
2019-10-15 14:33:12 +00:00
|
|
|
CHECK(WasmScript::ClearBreakPoint(script, code_offset, break_point));
|
2017-01-20 13:50:09 +00:00
|
|
|
}
|
|
|
|
|
2017-04-12 09:33:35 +00:00
|
|
|
// Wrapper with operator<<.
|
|
|
|
struct WasmValWrapper {
|
2017-07-14 13:49:01 +00:00
|
|
|
WasmValue val;
|
2017-04-12 09:33:35 +00:00
|
|
|
|
|
|
|
bool operator==(const WasmValWrapper& other) const {
|
|
|
|
return val == other.val;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// Only needed in debug builds. Avoid unused warning otherwise.
|
|
|
|
#ifdef DEBUG
|
|
|
|
std::ostream& operator<<(std::ostream& out, const WasmValWrapper& wrapper) {
|
2020-03-12 14:29:51 +00:00
|
|
|
switch (wrapper.val.type().kind()) {
|
|
|
|
case ValueType::kI32:
|
2017-04-12 09:33:35 +00:00
|
|
|
out << "i32: " << wrapper.val.to<int32_t>();
|
|
|
|
break;
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kI64:
|
2017-04-12 09:33:35 +00:00
|
|
|
out << "i64: " << wrapper.val.to<int64_t>();
|
|
|
|
break;
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kF32:
|
2017-04-12 09:33:35 +00:00
|
|
|
out << "f32: " << wrapper.val.to<float>();
|
|
|
|
break;
|
2020-03-12 14:29:51 +00:00
|
|
|
case ValueType::kF64:
|
2017-04-12 09:33:35 +00:00
|
|
|
out << "f64: " << wrapper.val.to<double>();
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
UNIMPLEMENTED();
|
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
class CollectValuesBreakHandler : public debug::DebugDelegate {
|
|
|
|
public:
|
|
|
|
struct BreakpointValues {
|
2017-07-14 13:49:01 +00:00
|
|
|
std::vector<WasmValue> locals;
|
|
|
|
std::vector<WasmValue> stack;
|
2017-04-12 09:33:35 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
explicit CollectValuesBreakHandler(
|
|
|
|
Isolate* isolate, std::initializer_list<BreakpointValues> expected_values)
|
|
|
|
: isolate_(isolate), expected_values_(expected_values) {
|
|
|
|
v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_), this);
|
|
|
|
}
|
2018-09-14 14:54:08 +00:00
|
|
|
~CollectValuesBreakHandler() override {
|
2017-04-12 09:33:35 +00:00
|
|
|
v8::debug::SetDebugDelegate(reinterpret_cast<v8::Isolate*>(isolate_),
|
|
|
|
nullptr);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
Isolate* isolate_;
|
|
|
|
int count_ = 0;
|
|
|
|
std::vector<BreakpointValues> expected_values_;
|
|
|
|
|
|
|
|
void BreakProgramRequested(v8::Local<v8::Context> paused_context,
|
2017-08-01 16:41:20 +00:00
|
|
|
const std::vector<int>&) override {
|
2017-04-12 09:33:35 +00:00
|
|
|
printf("Break #%d\n", count_);
|
|
|
|
CHECK_GT(expected_values_.size(), count_);
|
|
|
|
auto& expected = expected_values_[count_];
|
|
|
|
++count_;
|
|
|
|
|
|
|
|
HandleScope handles(isolate_);
|
|
|
|
|
|
|
|
StackTraceFrameIterator frame_it(isolate_);
|
2020-05-07 12:29:48 +00:00
|
|
|
WasmFrame* frame = WasmFrame::cast(frame_it.frame());
|
2020-04-23 15:56:48 +00:00
|
|
|
DebugInfo* debug_info = frame->native_module()->GetDebugInfo();
|
|
|
|
|
2020-05-25 16:56:16 +00:00
|
|
|
int num_locals = debug_info->GetNumLocals(frame->pc());
|
2020-04-23 15:56:48 +00:00
|
|
|
CHECK_EQ(expected.locals.size(), num_locals);
|
|
|
|
for (int i = 0; i < num_locals; ++i) {
|
|
|
|
WasmValue local_value = debug_info->GetLocalValue(
|
2020-05-25 16:56:16 +00:00
|
|
|
i, frame->pc(), frame->fp(), frame->callee_fp());
|
2020-04-23 15:56:48 +00:00
|
|
|
CHECK_EQ(WasmValWrapper{expected.locals[i]}, WasmValWrapper{local_value});
|
2017-04-12 09:33:35 +00:00
|
|
|
}
|
|
|
|
|
2020-05-25 16:56:16 +00:00
|
|
|
int stack_depth = debug_info->GetStackDepth(frame->pc());
|
2020-04-23 15:56:48 +00:00
|
|
|
CHECK_EQ(expected.stack.size(), stack_depth);
|
|
|
|
for (int i = 0; i < stack_depth; ++i) {
|
|
|
|
WasmValue stack_value = debug_info->GetStackValue(
|
2020-05-25 16:56:16 +00:00
|
|
|
i, frame->pc(), frame->fp(), frame->callee_fp());
|
2020-04-23 15:56:48 +00:00
|
|
|
CHECK_EQ(WasmValWrapper{expected.stack[i]}, WasmValWrapper{stack_value});
|
2017-04-12 09:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
isolate_->debug()->PrepareStep(StepAction::StepIn);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2017-07-14 13:49:01 +00:00
|
|
|
// Special template to explicitly cast to WasmValue.
|
2017-04-12 09:33:35 +00:00
|
|
|
template <typename Arg>
|
2017-07-14 13:49:01 +00:00
|
|
|
WasmValue MakeWasmVal(Arg arg) {
|
|
|
|
return WasmValue(arg);
|
2017-04-12 09:33:35 +00:00
|
|
|
}
|
|
|
|
// Translate long to i64 (ambiguous otherwise).
|
|
|
|
template <>
|
2017-07-14 13:49:01 +00:00
|
|
|
WasmValue MakeWasmVal(long arg) { // NOLINT: allow long parameter
|
|
|
|
return WasmValue(static_cast<int64_t>(arg));
|
2017-04-12 09:33:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
template <typename... Args>
|
2017-07-14 13:49:01 +00:00
|
|
|
std::vector<WasmValue> wasmVec(Args... args) {
|
|
|
|
std::array<WasmValue, sizeof...(args)> arr{{MakeWasmVal(args)...}};
|
|
|
|
return std::vector<WasmValue>{arr.begin(), arr.end()};
|
2017-04-12 09:33:35 +00:00
|
|
|
}
|
|
|
|
|
2019-11-20 11:27:40 +00:00
|
|
|
int GetIntReturnValue(MaybeHandle<Object> retval) {
|
|
|
|
CHECK(!retval.is_null());
|
|
|
|
int result;
|
|
|
|
CHECK(retval.ToHandleChecked()->ToInt32(&result));
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2016-12-19 17:22:55 +00:00
|
|
|
} // namespace
|
|
|
|
|
2017-10-25 12:46:43 +00:00
|
|
|
WASM_COMPILED_EXEC_TEST(WasmCollectPossibleBreakpoints) {
|
2018-08-21 15:01:31 +00:00
|
|
|
WasmRunner<int> runner(execution_tier);
|
2016-12-19 17:22:55 +00:00
|
|
|
|
|
|
|
BUILD(runner, WASM_NOP, WASM_I32_ADD(WASM_ZERO, WASM_ONE));
|
|
|
|
|
2018-12-08 02:59:17 +00:00
|
|
|
WasmInstanceObject instance = *runner.builder().instance_object();
|
2019-10-10 10:23:45 +00:00
|
|
|
NativeModule* native_module = instance.module_object().native_module();
|
2017-12-17 19:08:07 +00:00
|
|
|
|
2016-12-19 17:22:55 +00:00
|
|
|
std::vector<debug::Location> locations;
|
2017-01-20 13:50:09 +00:00
|
|
|
// Check all locations for function 0.
|
2019-11-05 13:15:28 +00:00
|
|
|
CheckLocations(&runner, native_module, {0, 0}, {0, 10},
|
2017-01-15 21:18:53 +00:00
|
|
|
{{0, 1}, {0, 2}, {0, 4}, {0, 6}, {0, 7}});
|
2017-01-20 13:50:09 +00:00
|
|
|
// Check a range ending at an instruction.
|
2019-11-05 13:15:28 +00:00
|
|
|
CheckLocations(&runner, native_module, {0, 2}, {0, 4}, {{0, 2}});
|
2017-01-20 13:50:09 +00:00
|
|
|
// Check a range ending one behind an instruction.
|
2019-11-05 13:15:28 +00:00
|
|
|
CheckLocations(&runner, native_module, {0, 2}, {0, 5}, {{0, 2}, {0, 4}});
|
2017-01-20 13:50:09 +00:00
|
|
|
// Check a range starting at an instruction.
|
2019-11-05 13:15:28 +00:00
|
|
|
CheckLocations(&runner, native_module, {0, 7}, {0, 8}, {{0, 7}});
|
2017-01-20 13:50:09 +00:00
|
|
|
// Check from an instruction to beginning of next function.
|
2019-11-05 13:15:28 +00:00
|
|
|
CheckLocations(&runner, native_module, {0, 7}, {0, 10}, {{0, 7}});
|
2017-01-20 13:50:09 +00:00
|
|
|
// Check from end of one function (no valid instruction position) to beginning
|
|
|
|
// of next function. Must be empty, but not fail.
|
2019-11-05 13:15:28 +00:00
|
|
|
CheckLocations(&runner, native_module, {0, 8}, {0, 10}, {});
|
2017-01-20 13:50:09 +00:00
|
|
|
// Check from one after the end of the function. Must fail.
|
2019-11-05 13:15:28 +00:00
|
|
|
CheckLocationsFail(&runner, native_module, {0, 9}, {0, 10});
|
2016-12-19 17:22:55 +00:00
|
|
|
}
|
2017-01-20 13:50:09 +00:00
|
|
|
|
2017-10-25 12:46:43 +00:00
|
|
|
WASM_COMPILED_EXEC_TEST(WasmSimpleBreak) {
|
2018-08-21 15:01:31 +00:00
|
|
|
WasmRunner<int> runner(execution_tier);
|
2017-01-20 13:50:09 +00:00
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
|
|
|
|
BUILD(runner, WASM_NOP, WASM_I32_ADD(WASM_I32V_1(11), WASM_I32V_1(3)));
|
|
|
|
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
2017-08-19 16:34:11 +00:00
|
|
|
runner.builder().WrapCode(runner.function_index());
|
2019-09-10 01:19:59 +00:00
|
|
|
SetBreakpoint(&runner, runner.function_index(), 4, 4);
|
2017-01-20 13:50:09 +00:00
|
|
|
|
2017-01-24 10:13:33 +00:00
|
|
|
BreakHandler count_breaks(isolate, {{4, BreakHandler::Continue}});
|
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
MaybeHandle<Object> retval =
|
|
|
|
Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
|
2019-11-20 11:27:40 +00:00
|
|
|
CHECK_EQ(14, GetIntReturnValue(retval));
|
|
|
|
}
|
|
|
|
|
|
|
|
WASM_COMPILED_EXEC_TEST(WasmNonBreakablePosition) {
|
|
|
|
WasmRunner<int> runner(execution_tier);
|
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
|
|
|
|
BUILD(runner, WASM_RETURN1(WASM_I32V_2(1024)));
|
|
|
|
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
|
|
|
runner.builder().WrapCode(runner.function_index());
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 2, 4);
|
|
|
|
|
|
|
|
BreakHandler count_breaks(isolate, {{4, BreakHandler::Continue}});
|
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
MaybeHandle<Object> retval =
|
|
|
|
Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
|
|
|
|
CHECK_EQ(1024, GetIntReturnValue(retval));
|
2017-01-24 10:13:33 +00:00
|
|
|
}
|
|
|
|
|
2017-10-25 12:46:43 +00:00
|
|
|
WASM_COMPILED_EXEC_TEST(WasmSimpleStepping) {
|
2018-08-21 15:01:31 +00:00
|
|
|
WasmRunner<int> runner(execution_tier);
|
2017-01-24 10:13:33 +00:00
|
|
|
BUILD(runner, WASM_I32_ADD(WASM_I32V_1(11), WASM_I32V_1(3)));
|
|
|
|
|
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
2017-08-19 16:34:11 +00:00
|
|
|
runner.builder().WrapCode(runner.function_index());
|
2017-01-24 10:13:33 +00:00
|
|
|
|
|
|
|
// Set breakpoint at the first I32Const.
|
2019-09-10 01:19:59 +00:00
|
|
|
SetBreakpoint(&runner, runner.function_index(), 1, 1);
|
2017-01-24 10:13:33 +00:00
|
|
|
|
|
|
|
BreakHandler count_breaks(isolate,
|
|
|
|
{
|
|
|
|
{1, BreakHandler::StepNext}, // I32Const
|
|
|
|
{3, BreakHandler::StepNext}, // I32Const
|
|
|
|
{5, BreakHandler::Continue} // I32Add
|
|
|
|
});
|
2017-01-20 13:50:09 +00:00
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
MaybeHandle<Object> retval =
|
|
|
|
Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
|
2019-11-20 11:27:40 +00:00
|
|
|
CHECK_EQ(14, GetIntReturnValue(retval));
|
2017-01-24 10:13:33 +00:00
|
|
|
}
|
|
|
|
|
2017-10-25 12:46:43 +00:00
|
|
|
WASM_COMPILED_EXEC_TEST(WasmStepInAndOut) {
|
2018-08-21 15:01:31 +00:00
|
|
|
WasmRunner<int, int> runner(execution_tier);
|
2020-04-23 15:56:48 +00:00
|
|
|
runner.TierDown();
|
2017-01-24 10:13:33 +00:00
|
|
|
WasmFunctionCompiler& f2 = runner.NewFunction<void>();
|
2018-05-07 11:02:21 +00:00
|
|
|
f2.AllocateLocal(kWasmI32);
|
2017-01-20 13:50:09 +00:00
|
|
|
|
2017-01-24 10:13:33 +00:00
|
|
|
// Call f2 via indirect call, because a direct call requires f2 to exist when
|
|
|
|
// we compile main, but we need to compile main first so that the order of
|
|
|
|
// functions in the code section matches the function indexes.
|
|
|
|
|
|
|
|
// return arg0
|
|
|
|
BUILD(runner, WASM_RETURN1(WASM_GET_LOCAL(0)));
|
|
|
|
// for (int i = 0; i < 10; ++i) { f2(i); }
|
|
|
|
BUILD(f2, WASM_LOOP(
|
|
|
|
WASM_BR_IF(0, WASM_BINOP(kExprI32GeU, WASM_GET_LOCAL(0),
|
|
|
|
WASM_I32V_1(10))),
|
|
|
|
WASM_SET_LOCAL(
|
|
|
|
0, WASM_BINOP(kExprI32Sub, WASM_GET_LOCAL(0), WASM_ONE)),
|
|
|
|
WASM_CALL_FUNCTION(runner.function_index(), WASM_GET_LOCAL(0)),
|
2017-02-02 23:06:21 +00:00
|
|
|
WASM_DROP, WASM_BR(1)));
|
2017-01-24 10:13:33 +00:00
|
|
|
|
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
2017-08-19 16:34:11 +00:00
|
|
|
runner.builder().WrapCode(f2.function_index());
|
2017-01-24 10:13:33 +00:00
|
|
|
|
2019-10-08 12:38:48 +00:00
|
|
|
// Set first breakpoint on the LocalGet (offset 19) before the Call.
|
2019-09-10 01:19:59 +00:00
|
|
|
SetBreakpoint(&runner, f2.function_index(), 19, 19);
|
2017-01-24 10:13:33 +00:00
|
|
|
|
|
|
|
BreakHandler count_breaks(isolate,
|
|
|
|
{
|
2019-10-08 12:38:48 +00:00
|
|
|
{19, BreakHandler::StepIn}, // LocalGet
|
2017-01-24 10:13:33 +00:00
|
|
|
{21, BreakHandler::StepIn}, // Call
|
|
|
|
{1, BreakHandler::StepOut}, // in f2
|
|
|
|
{23, BreakHandler::Continue} // After Call
|
|
|
|
});
|
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
CHECK(!Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr)
|
|
|
|
.is_null());
|
2017-01-20 13:50:09 +00:00
|
|
|
}
|
2017-04-12 09:33:35 +00:00
|
|
|
|
2017-10-25 12:46:43 +00:00
|
|
|
WASM_COMPILED_EXEC_TEST(WasmGetLocalsAndStack) {
|
2018-08-21 15:01:31 +00:00
|
|
|
WasmRunner<void, int> runner(execution_tier);
|
2018-05-07 11:02:21 +00:00
|
|
|
runner.AllocateLocal(kWasmI64);
|
|
|
|
runner.AllocateLocal(kWasmF32);
|
|
|
|
runner.AllocateLocal(kWasmF64);
|
2017-04-12 09:33:35 +00:00
|
|
|
|
|
|
|
BUILD(runner,
|
|
|
|
// set [1] to 17
|
|
|
|
WASM_SET_LOCAL(1, WASM_I64V_1(17)),
|
|
|
|
// set [2] to <arg0> = 7
|
|
|
|
WASM_SET_LOCAL(2, WASM_F32_SCONVERT_I32(WASM_GET_LOCAL(0))),
|
|
|
|
// set [3] to <arg1>/2 = 8.5
|
|
|
|
WASM_SET_LOCAL(3, WASM_F64_DIV(WASM_F64_SCONVERT_I64(WASM_GET_LOCAL(1)),
|
|
|
|
WASM_F64(2))));
|
|
|
|
|
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
2017-08-19 16:34:11 +00:00
|
|
|
runner.builder().WrapCode(runner.function_index());
|
2017-04-12 09:33:35 +00:00
|
|
|
|
|
|
|
// Set breakpoint at the first instruction (7 bytes for local decls: num
|
|
|
|
// entries + 3x<count, type>).
|
2019-09-10 01:19:59 +00:00
|
|
|
SetBreakpoint(&runner, runner.function_index(), 7, 7);
|
2017-04-12 09:33:35 +00:00
|
|
|
|
|
|
|
CollectValuesBreakHandler break_handler(
|
|
|
|
isolate,
|
|
|
|
{
|
|
|
|
// params + locals stack
|
|
|
|
{wasmVec(7, 0L, 0.f, 0.), wasmVec()}, // 0: i64.const[17]
|
|
|
|
{wasmVec(7, 0L, 0.f, 0.), wasmVec(17L)}, // 1: set_local[1]
|
|
|
|
{wasmVec(7, 17L, 0.f, 0.), wasmVec()}, // 2: get_local[0]
|
|
|
|
{wasmVec(7, 17L, 0.f, 0.), wasmVec(7)}, // 3: f32.convert_s
|
|
|
|
{wasmVec(7, 17L, 0.f, 0.), wasmVec(7.f)}, // 4: set_local[2]
|
|
|
|
{wasmVec(7, 17L, 7.f, 0.), wasmVec()}, // 5: get_local[1]
|
|
|
|
{wasmVec(7, 17L, 7.f, 0.), wasmVec(17L)}, // 6: f64.convert_s
|
|
|
|
{wasmVec(7, 17L, 7.f, 0.), wasmVec(17.)}, // 7: f64.const[2]
|
|
|
|
{wasmVec(7, 17L, 7.f, 0.), wasmVec(17., 2.)}, // 8: f64.div
|
|
|
|
{wasmVec(7, 17L, 7.f, 0.), wasmVec(8.5)}, // 9: set_local[3]
|
|
|
|
{wasmVec(7, 17L, 7.f, 8.5), wasmVec()}, // 10: end
|
|
|
|
});
|
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
Handle<Object> args[]{handle(Smi::FromInt(7), isolate)};
|
|
|
|
CHECK(!Execution::Call(isolate, main_fun_wrapper, global, 1, args).is_null());
|
|
|
|
}
|
2017-09-01 12:57:34 +00:00
|
|
|
|
2019-10-02 15:20:08 +00:00
|
|
|
WASM_COMPILED_EXEC_TEST(WasmRemoveBreakPoint) {
|
|
|
|
WasmRunner<int> runner(execution_tier);
|
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
|
|
|
|
BUILD(runner, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP,
|
|
|
|
WASM_I32V_1(14));
|
|
|
|
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
|
|
|
runner.builder().WrapCode(runner.function_index());
|
|
|
|
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 1, 1);
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 2, 2);
|
|
|
|
Handle<BreakPoint> to_delete =
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 3, 3);
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 4, 4);
|
|
|
|
|
|
|
|
BreakHandler count_breaks(isolate, {{1, BreakHandler::Continue},
|
|
|
|
{2, BreakHandler::Continue,
|
|
|
|
[&runner, &to_delete]() {
|
|
|
|
ClearBreakpoint(
|
|
|
|
&runner, runner.function_index(),
|
|
|
|
3, to_delete);
|
|
|
|
}},
|
|
|
|
{4, BreakHandler::Continue}});
|
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
MaybeHandle<Object> retval =
|
|
|
|
Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
|
2019-11-20 11:27:40 +00:00
|
|
|
CHECK_EQ(14, GetIntReturnValue(retval));
|
2019-10-02 15:20:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WASM_COMPILED_EXEC_TEST(WasmRemoveLastBreakPoint) {
|
|
|
|
WasmRunner<int> runner(execution_tier);
|
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
|
|
|
|
BUILD(runner, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP,
|
|
|
|
WASM_I32V_1(14));
|
|
|
|
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
|
|
|
runner.builder().WrapCode(runner.function_index());
|
|
|
|
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 1, 1);
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 2, 2);
|
|
|
|
Handle<BreakPoint> to_delete =
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 3, 3);
|
|
|
|
|
|
|
|
BreakHandler count_breaks(
|
|
|
|
isolate, {{1, BreakHandler::Continue},
|
|
|
|
{2, BreakHandler::Continue, [&runner, &to_delete]() {
|
|
|
|
ClearBreakpoint(&runner, runner.function_index(), 3,
|
|
|
|
to_delete);
|
|
|
|
}}});
|
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
MaybeHandle<Object> retval =
|
|
|
|
Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
|
2019-11-20 11:27:40 +00:00
|
|
|
CHECK_EQ(14, GetIntReturnValue(retval));
|
2019-10-02 15:20:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
WASM_COMPILED_EXEC_TEST(WasmRemoveAllBreakPoint) {
|
|
|
|
WasmRunner<int> runner(execution_tier);
|
|
|
|
Isolate* isolate = runner.main_isolate();
|
|
|
|
|
|
|
|
BUILD(runner, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP, WASM_NOP,
|
|
|
|
WASM_I32V_1(14));
|
|
|
|
|
|
|
|
Handle<JSFunction> main_fun_wrapper =
|
|
|
|
runner.builder().WrapCode(runner.function_index());
|
|
|
|
|
|
|
|
Handle<BreakPoint> bp1 =
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 1, 1);
|
|
|
|
Handle<BreakPoint> bp2 =
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 2, 2);
|
|
|
|
Handle<BreakPoint> bp3 =
|
|
|
|
SetBreakpoint(&runner, runner.function_index(), 3, 3);
|
|
|
|
|
|
|
|
BreakHandler count_breaks(
|
|
|
|
isolate, {{1, BreakHandler::Continue, [&runner, &bp1, &bp2, &bp3]() {
|
|
|
|
ClearBreakpoint(&runner, runner.function_index(), 1, bp1);
|
|
|
|
ClearBreakpoint(&runner, runner.function_index(), 3, bp3);
|
|
|
|
ClearBreakpoint(&runner, runner.function_index(), 2, bp2);
|
|
|
|
}}});
|
|
|
|
|
|
|
|
Handle<Object> global(isolate->context().global_object(), isolate);
|
|
|
|
MaybeHandle<Object> retval =
|
|
|
|
Execution::Call(isolate, main_fun_wrapper, global, 0, nullptr);
|
2019-11-20 11:27:40 +00:00
|
|
|
CHECK_EQ(14, GetIntReturnValue(retval));
|
2019-10-02 15:20:08 +00:00
|
|
|
}
|
|
|
|
|
2017-09-01 12:57:34 +00:00
|
|
|
} // namespace wasm
|
|
|
|
} // namespace internal
|
|
|
|
} // namespace v8
|