// 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_FUNCTION_BODY_DECODER_H_ #define V8_WASM_FUNCTION_BODY_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" #include "src/wasm/wasm-opcodes.h" #include "src/wasm/wasm-result.h" namespace v8 { namespace internal { class BitVector; // forward declaration namespace compiler { // external declarations from compiler. class WasmGraphBuilder; } namespace wasm { typedef compiler::WasmGraphBuilder TFBuilder; struct WasmModule; // forward declaration of module interface. // A wrapper around the signature and bytes of a function. struct FunctionBody { FunctionSig* sig; // function signature const byte* base; // base of the module bytes, for error reporting const byte* start; // start of the function body const byte* end; // end of the function body }; static inline FunctionBody FunctionBodyForTesting(const byte* start, const byte* end) { return {nullptr, start, start, end}; } struct DecodeStruct { int unused; }; typedef Result<DecodeStruct*> DecodeResult; inline std::ostream& operator<<(std::ostream& os, const DecodeStruct& tree) { return os; } V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator, const wasm::WasmModule* module, FunctionBody& body); DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder, FunctionBody& body); bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, const wasm::WasmModule* module); // A simplified form of AST printing, e.g. from a debugger. void PrintRawWasmCode(const byte* start, const byte* end); inline DecodeResult VerifyWasmCode(AccountingAllocator* allocator, const WasmModule* module, FunctionSig* sig, const byte* start, const byte* end) { FunctionBody body = {sig, nullptr, start, end}; return VerifyWasmCode(allocator, module, body); } inline DecodeResult BuildTFGraph(AccountingAllocator* allocator, TFBuilder* builder, FunctionSig* sig, const byte* start, const byte* end) { FunctionBody body = {sig, nullptr, start, end}; return BuildTFGraph(allocator, builder, body); } struct BodyLocalDecls { // The size of the encoded declarations. uint32_t encoded_size; // size of encoded declarations ZoneVector<ValueType> type_list; // Constructor initializes the vector. explicit BodyLocalDecls(Zone* zone) : encoded_size(0), type_list(zone) {} }; V8_EXPORT_PRIVATE bool DecodeLocalDecls(BodyLocalDecls* decls, const byte* start, const byte* end); V8_EXPORT_PRIVATE BitVector* AnalyzeLoopAssignmentForTesting(Zone* zone, size_t num_locals, const byte* start, const byte* end); // Computes the length of the opcode at the given address. 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) { // Base class for both iterators defined below. class iterator_base { public: 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_); } 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; 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, // assume the bytecode starts with local declarations and decode them. // Otherwise, do not decode local decls. BytecodeIterator(const byte* start, const byte* end, BodyLocalDecls* decls = nullptr); 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>( checked_read_u8(pc_, 0, "expected bytecode")); } void next() { if (pc_ < end_) { pc_ += OpcodeLength(pc_, end_); if (pc_ >= end_) pc_ = end_; } } bool has_next() { return pc_ < end_; } }; } // namespace wasm } // namespace internal } // namespace v8 #endif // V8_WASM_FUNCTION_BODY_DECODER_H_