| Index: src/wasm/decoder.h
|
| diff --git a/src/wasm/decoder.h b/src/wasm/decoder.h
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..df07a6d0ebacf5d463bc622567eace2bdbf9fab6
|
| --- /dev/null
|
| +++ b/src/wasm/decoder.h
|
| @@ -0,0 +1,233 @@
|
| +// Copyright 2015 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.
|
| +
|
| +#ifndef V8_WASM_DECODER_H_
|
| +#define V8_WASM_DECODER_H_
|
| +
|
| +#include "src/base/smart-pointers.h"
|
| +#include "src/flags.h"
|
| +#include "src/signature.h"
|
| +#include "src/wasm/wasm-result.h"
|
| +#include "src/zone-containers.h"
|
| +
|
| +namespace v8 {
|
| +namespace internal {
|
| +namespace wasm {
|
| +
|
| +#if DEBUG
|
| +#define TRACE(...) \
|
| + do { \
|
| + if (FLAG_trace_wasm_decoder) PrintF(__VA_ARGS__); \
|
| + } while (false)
|
| +#else
|
| +#define TRACE(...)
|
| +#endif
|
| +
|
| +// A helper utility to decode bytes, integers, fields, varints, etc, from
|
| +// a buffer of bytes.
|
| +class Decoder {
|
| + public:
|
| + Decoder(const byte* start, const byte* end)
|
| + : start_(start),
|
| + pc_(start),
|
| + limit_(end),
|
| + error_pc_(nullptr),
|
| + error_pt_(nullptr) {}
|
| +
|
| + virtual ~Decoder() {}
|
| +
|
| + // Reads a 8-bit unsigned integer (byte) and advances {pc_}.
|
| + uint8_t u8(const char* name = nullptr) {
|
| + TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| + name ? name : "uint8_t");
|
| + if (checkAvailable(1)) {
|
| + byte val = *(pc_++);
|
| + TRACE("%02x = %d\n", val, val);
|
| + return val;
|
| + } else {
|
| + error("expected 1 byte, but fell off end");
|
| + return traceOffEnd<uint8_t>();
|
| + }
|
| + }
|
| +
|
| + // Reads a 16-bit unsigned integer (little endian) and advances {pc_}.
|
| + uint16_t u16(const char* name = nullptr) {
|
| + TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| + name ? name : "uint16_t");
|
| + if (checkAvailable(2)) {
|
| +#ifdef V8_TARGET_LITTLE_ENDIAN
|
| + byte b0 = pc_[0];
|
| + byte b1 = pc_[1];
|
| +#else
|
| + byte b1 = pc_[0];
|
| + byte b0 = pc_[1];
|
| +#endif
|
| + uint16_t val = static_cast<uint16_t>(b1 << 8) | b0;
|
| + TRACE("%02x %02x = %d\n", pc_[0], pc_[1], val);
|
| + pc_ += 2;
|
| + return val;
|
| + } else {
|
| + error("expected 2 bytes, but fell off end");
|
| + return traceOffEnd<uint16_t>();
|
| + }
|
| + }
|
| +
|
| + // Reads a single 32-bit unsigned integer (little endian) and advances {pc_}.
|
| + uint32_t u32(const char* name = nullptr) {
|
| + TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| + name ? name : "uint32_t");
|
| + if (checkAvailable(4)) {
|
| +#ifdef V8_TARGET_LITTLE_ENDIAN
|
| + byte b0 = pc_[0];
|
| + byte b1 = pc_[1];
|
| + byte b2 = pc_[2];
|
| + byte b3 = pc_[3];
|
| +#else
|
| + byte b3 = pc_[0];
|
| + byte b2 = pc_[1];
|
| + byte b1 = pc_[2];
|
| + byte b0 = pc_[3];
|
| +#endif
|
| + uint32_t val = static_cast<uint32_t>(b3 << 24) |
|
| + static_cast<uint32_t>(b2 << 16) |
|
| + static_cast<uint32_t>(b1 << 8) | b0;
|
| + TRACE("%02x %02x %02x %02x = %u\n", pc_[0], pc_[1], pc_[2], pc_[3], val);
|
| + pc_ += 4;
|
| + return val;
|
| + } else {
|
| + error("expected 4 bytes, but fell off end");
|
| + return traceOffEnd<uint32_t>();
|
| + }
|
| + }
|
| +
|
| + // Reads a LEB128 variable-length 32-bit integer and advances {pc_}.
|
| + uint32_t u32v(int* length, const char* name = nullptr) {
|
| + TRACE(" +%d %-20s: ", static_cast<int>(pc_ - start_),
|
| + name ? name : "varint");
|
| +
|
| + if (!checkAvailable(1)) {
|
| + error("expected at least 1 byte, but fell off end");
|
| + return traceOffEnd<uint32_t>();
|
| + }
|
| +
|
| + const byte* pos = pc_;
|
| + const byte* end = pc_ + 5;
|
| + if (end > limit_) end = limit_;
|
| +
|
| + uint32_t result = 0;
|
| + int shift = 0;
|
| + byte b = 0;
|
| + while (pc_ < end) {
|
| + b = *pc_++;
|
| + TRACE("%02x ", b);
|
| + result = result | ((b & 0x7F) << shift);
|
| + if ((b & 0x80) == 0) break;
|
| + shift += 7;
|
| + }
|
| +
|
| + *length = static_cast<int>(pc_ - pos);
|
| + if (pc_ == end && (b & 0x80)) {
|
| + error(pc_ - 1, "varint too large");
|
| + } else {
|
| + TRACE("= %u\n", result);
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + // Check that at least {size} bytes exist between {pc_} and {limit_}.
|
| + bool checkAvailable(int size) {
|
| + if (pc_ < start_ || (pc_ + size) > limit_) {
|
| + error(pc_, nullptr, "expected %d bytes, fell off end", size);
|
| + return false;
|
| + } else {
|
| + return true;
|
| + }
|
| + }
|
| +
|
| + void error(const char* msg) { error(pc_, nullptr, msg); }
|
| +
|
| + void error(const byte* pc, const char* msg) { error(pc, nullptr, msg); }
|
| +
|
| + // Sets internal error state.
|
| + void error(const byte* pc, const byte* pt, const char* format, ...) {
|
| + if (ok()) {
|
| +#if DEBUG
|
| + if (FLAG_wasm_break_on_decoder_error) {
|
| + base::OS::DebugBreak();
|
| + }
|
| +#endif
|
| + const int kMaxErrorMsg = 256;
|
| + char* buffer = new char[kMaxErrorMsg];
|
| + va_list arguments;
|
| + va_start(arguments, format);
|
| + base::OS::VSNPrintF(buffer, kMaxErrorMsg - 1, format, arguments);
|
| + va_end(arguments);
|
| + error_msg_.Reset(buffer);
|
| + error_pc_ = pc;
|
| + error_pt_ = pt;
|
| + onFirstError();
|
| + }
|
| + }
|
| +
|
| + // Behavior triggered on first error, overridden in subclasses.
|
| + virtual void onFirstError() {}
|
| +
|
| + // Debugging helper to print bytes up to the end.
|
| + template <typename T>
|
| + T traceOffEnd() {
|
| + T t = 0;
|
| + for (const byte* ptr = pc_; ptr < limit_; ptr++) {
|
| + TRACE("%02x ", *ptr);
|
| + }
|
| + TRACE("<end>\n");
|
| + pc_ = limit_;
|
| + return t;
|
| + }
|
| +
|
| + // Converts the given value to a {Result}, copying the error if necessary.
|
| + template <typename T>
|
| + Result<T> toResult(T val) {
|
| + Result<T> result;
|
| + if (error_pc_) {
|
| + result.error_code = kError;
|
| + result.start = start_;
|
| + result.error_pc = error_pc_;
|
| + result.error_pt = error_pt_;
|
| + result.error_msg = error_msg_;
|
| + error_msg_.Reset(nullptr);
|
| + } else {
|
| + result.error_code = kSuccess;
|
| + result.val = val;
|
| + }
|
| + return result;
|
| + }
|
| +
|
| + // Resets the boundaries of this decoder.
|
| + void Reset(const byte* start, const byte* end) {
|
| + start_ = start;
|
| + pc_ = start;
|
| + limit_ = end;
|
| + error_pc_ = nullptr;
|
| + error_pt_ = nullptr;
|
| + error_msg_.Reset(nullptr);
|
| + }
|
| +
|
| + bool ok() const { return error_pc_ == nullptr; }
|
| + bool failed() const { return error_pc_ != nullptr; }
|
| +
|
| + protected:
|
| + const byte* start_;
|
| + const byte* pc_;
|
| + const byte* limit_;
|
| + const byte* error_pc_;
|
| + const byte* error_pt_;
|
| + base::SmartArrayPointer<char> error_msg_;
|
| +};
|
| +
|
| +#undef TRACE
|
| +} // namespace wasm
|
| +} // namespace internal
|
| +} // namespace v8
|
| +
|
| +#endif // V8_WASM_DECODER_H_
|
|
|