Commit 6361f133 authored by clemensh's avatar clemensh Committed by Commit bot

[wasm] Add iterators for opcodes or offsets of one function

We have the BytecodeIterator with next() and has_next() methods, and
pc_offset() and current() accessors.
This CL adds an interface to iterate over the opcodes or offsets in a
C++ foreach loop.

R=titzer@chromium.org

Review-Url: https://codereview.chromium.org/2587143002
Cr-Commit-Position: refs/heads/master@{#41851}
parent e797e0ea
......@@ -7,8 +7,6 @@
#include <iterator>
#include "src/base/macros.h"
namespace v8 {
namespace base {
......
......@@ -5,7 +5,10 @@
#ifndef V8_WASM_AST_DECODER_H_
#define V8_WASM_AST_DECODER_H_
#include <iterator>
#include "src/base/compiler-specific.h"
#include "src/base/iterator.h"
#include "src/globals.h"
#include "src/signature.h"
#include "src/wasm/decoder.h"
......@@ -382,31 +385,59 @@ V8_EXPORT_PRIVATE unsigned OpcodeLength(const byte* pc, const byte* end);
// A simple forward iterator for bytecodes.
class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
public:
// If one wants to iterate over the bytecode without looking at {pc_offset()}.
class iterator {
// Base class for both iterators defined below.
class iterator_base {
public:
inline iterator& operator++() {
inline iterator_base& operator++() {
DCHECK_LT(ptr_, end_);
ptr_ += OpcodeLength(ptr_, end_);
return *this;
}
inline bool operator==(const iterator_base& that) {
return this->ptr_ == that.ptr_;
}
inline bool operator!=(const iterator_base& that) {
return this->ptr_ != that.ptr_;
}
protected:
const byte* ptr_;
const byte* end_;
iterator_base(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
};
public:
// If one wants to iterate over the bytecode without looking at {pc_offset()}.
class opcode_iterator
: public iterator_base,
public std::iterator<std::input_iterator_tag, WasmOpcode> {
public:
inline WasmOpcode operator*() {
DCHECK_LT(ptr_, end_);
return static_cast<WasmOpcode>(*ptr_);
}
inline bool operator==(const iterator& that) {
return this->ptr_ == that.ptr_;
}
inline bool operator!=(const iterator& that) {
return this->ptr_ != that.ptr_;
private:
friend class BytecodeIterator;
opcode_iterator(const byte* ptr, const byte* end)
: iterator_base(ptr, end) {}
};
// If one wants to iterate over the instruction offsets without looking at
// opcodes.
class offset_iterator
: public iterator_base,
public std::iterator<std::input_iterator_tag, uint32_t> {
public:
inline uint32_t operator*() {
DCHECK_LT(ptr_, end_);
return static_cast<uint32_t>(ptr_ - start_);
}
private:
const byte* start_;
friend class BytecodeIterator;
const byte* ptr_;
const byte* end_;
iterator(const byte* ptr, const byte* end) : ptr_(ptr), end_(end) {}
offset_iterator(const byte* start, const byte* ptr, const byte* end)
: iterator_base(ptr, end), start_(start) {}
};
// Create a new {BytecodeIterator}. If the {decls} pointer is non-null,
......@@ -415,8 +446,16 @@ class V8_EXPORT_PRIVATE BytecodeIterator : public NON_EXPORTED_BASE(Decoder) {
BytecodeIterator(const byte* start, const byte* end,
AstLocalDecls* decls = nullptr);
inline iterator begin() const { return iterator(pc_, end_); }
inline iterator end() const { return iterator(end_, end_); }
base::iterator_range<opcode_iterator> opcodes() {
return base::iterator_range<opcode_iterator>(opcode_iterator(pc_, end_),
opcode_iterator(end_, end_));
}
base::iterator_range<offset_iterator> offsets() {
return base::iterator_range<offset_iterator>(
offset_iterator(start_, pc_, end_),
offset_iterator(start_, end_, end_));
}
WasmOpcode current() {
return static_cast<WasmOpcode>(
......
......@@ -711,14 +711,14 @@ bool WasmCompiledModule::GetPossibleBreakpoints(
BytecodeIterator iterator(module_start + func.code_start_offset,
module_start + func.code_end_offset, &locals);
DCHECK_LT(0u, locals.decls_encoded_size);
for (; iterator.has_next(); iterator.next()) {
uint32_t offset = func.code_start_offset + iterator.pc_offset();
if (offset >= end_offset) {
for (uint32_t offset : iterator.offsets()) {
uint32_t total_offset = func.code_start_offset + offset;
if (total_offset >= end_offset) {
DCHECK_EQ(end_func_index, func_idx);
break;
}
if (offset < start_offset) continue;
locations->push_back(v8::debug::Location(func_idx, iterator.pc_offset()));
if (total_offset < start_offset) continue;
locations->push_back(v8::debug::Location(func_idx, offset));
}
}
return true;
......
......@@ -2669,7 +2669,7 @@ TEST_F(BytecodeIteratorTest, SimpleForeach) {
WasmOpcode expected[] = {kExprI8Const, kExprIf, kExprI8Const,
kExprElse, kExprI8Const, kExprEnd};
size_t pos = 0;
for (WasmOpcode opcode : iter) {
for (WasmOpcode opcode : iter.opcodes()) {
if (pos >= arraysize(expected)) {
EXPECT_TRUE(false);
break;
......@@ -2685,20 +2685,40 @@ TEST_F(BytecodeIteratorTest, ForeachTwice) {
int count = 0;
count = 0;
for (WasmOpcode opcode : iter) {
for (WasmOpcode opcode : iter.opcodes()) {
USE(opcode);
count++;
}
EXPECT_EQ(6, count);
count = 0;
for (WasmOpcode opcode : iter) {
for (WasmOpcode opcode : iter.opcodes()) {
USE(opcode);
count++;
}
EXPECT_EQ(6, count);
}
TEST_F(BytecodeIteratorTest, ForeachOffset) {
byte code[] = {WASM_IF_ELSE(WASM_ZERO, WASM_ZERO, WASM_ZERO)};
BytecodeIterator iter(code, code + sizeof(code));
int count = 0;
count = 0;
for (auto offset : iter.offsets()) {
USE(offset);
count++;
}
EXPECT_EQ(6, count);
count = 0;
for (auto offset : iter.offsets()) {
USE(offset);
count++;
}
EXPECT_EQ(6, count);
}
TEST_F(BytecodeIteratorTest, WithAstDecls) {
byte code[] = {1, 1, kLocalI32, WASM_I8(9), WASM_I8(11)};
AstLocalDecls decls(zone());
......
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