#ifndef V8_WASM_STRING_BUILDER_MULTILINE_H_
#define V8_WASM_STRING_BUILDER_MULTILINE_H_
#if !V8_ENABLE_WEBASSEMBLY
#error This header should only be included if WebAssembly is enabled.
#endif
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include "src/wasm/string-builder.h"
namespace v8 {
namespace debug {
class DisassemblyCollector;
}
namespace internal {
namespace wasm {
inline int GetNumDigits(uint32_t value) {
int digits = 1;
for (uint32_t compare = 10; value >= compare; compare *= 10) digits++;
return digits;
}
struct LabelInfo {
LabelInfo(size_t line_number, size_t offset,
uint32_t index_by_occurrence_order)
: name_section_index(index_by_occurrence_order),
line_number(line_number),
offset(offset) {}
uint32_t name_section_index;
size_t line_number;
size_t offset;
const char* start{nullptr};
size_t length{0};
};
class MultiLineStringBuilder : public StringBuilder {
public:
MultiLineStringBuilder() : StringBuilder(kKeepOldChunks) {}
void NextLine(uint32_t byte_offset) {
*allocate(1) = '\n';
size_t len = length();
lines_.emplace_back(start(), len, pending_bytecode_offset_);
start_here();
pending_bytecode_offset_ = byte_offset;
}
size_t line_number() { return lines_.size(); }
void set_current_line_bytecode_offset(uint32_t offset) {
pending_bytecode_offset_ = offset;
}
uint32_t current_line_bytecode_offset() { return pending_bytecode_offset_; }
void PatchLabel(LabelInfo& label, const char* label_source) {
DCHECK_GT(label.length, 0);
DCHECK_LT(label.line_number, lines_.size());
char* patched_line;
Line& l = lines_[label.line_number];
size_t patched_length = l.len + label.length + 1;
if (length() == 0) {
patched_line = allocate(patched_length);
start_here();
} else {
const char* unfinished_start = start();
size_t unfinished_length = length();
rewind_to_start();
patched_line = allocate(patched_length);
start_here();
char* new_location = allocate(unfinished_length);
memmove(new_location, unfinished_start, unfinished_length);
if (label_source >= unfinished_start &&
label_source < unfinished_start + unfinished_length) {
label_source = new_location + (label_source - unfinished_start);
}
}
char* cursor = patched_line;
memcpy(cursor, l.data, label.offset);
cursor += label.offset;
*(cursor++) = ' ';
label.start = cursor;
memcpy(cursor, label_source, label.length);
cursor += label.length;
memcpy(cursor, l.data + label.offset, l.len - label.offset);
l.data = patched_line;
l.len = patched_length;
}
void ToDisassemblyCollector(v8::debug::DisassemblyCollector* collector);
void WriteTo(std::ostream& out, bool print_offsets,
std::vector<uint32_t>* collect_offsets = nullptr) {
if (length() != 0) NextLine(0);
if (lines_.size() == 0) return;
if (print_offsets) {
uint32_t largest_offset = lines_.back().bytecode_offset;
if (lines_[0].bytecode_offset > largest_offset) {
for (const Line& l : lines_) {
if (l.bytecode_offset > largest_offset) {
largest_offset = l.bytecode_offset;
}
}
}
int width = GetNumDigits(largest_offset);
constexpr int kBufSize = 12;
char buffer[kBufSize] = {32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, '|'};
char* const buffer_end = buffer + kBufSize - 1;
char* const buffer_start = buffer_end - width;
uint32_t prev_offset = 0;
for (const Line& l : lines_) {
uint32_t offset = l.bytecode_offset;
if (offset < prev_offset) {
memset(buffer_start, 32, width);
}
prev_offset = offset;
char* ptr = buffer_end;
do {
*(--ptr) = '0' + (offset % 10);
offset /= 10;
} while (offset > 0);
out.write(buffer_start, width + 1);
out.write(l.data, l.len);
}
return;
}
const Line& first = lines_[0];
const char* last_start = first.data;
size_t len = first.len;
for (size_t i = 1; i < lines_.size(); i++) {
const Line& l = lines_[i];
if (last_start + len == l.data) {
len += l.len;
} else {
out.write(last_start, len);
last_start = l.data;
len = l.len;
}
}
out.write(last_start, len);
if (collect_offsets) {
collect_offsets->reserve(lines_.size());
for (const Line& l : lines_) {
collect_offsets->push_back(l.bytecode_offset);
}
}
}
size_t ApproximateSizeMB() { return approximate_size_mb(); }
private:
struct Line {
Line(const char* d, size_t length, uint32_t bytecode_offset)
: data(d), len(length), bytecode_offset(bytecode_offset) {}
const char* data;
size_t len;
uint32_t bytecode_offset;
};
std::vector<Line> lines_;
uint32_t pending_bytecode_offset_ = 0;
};
}
}
}
#endif