// 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 "src/base/compiler-specific.h" #include "src/base/iterator.h" #include "src/common/globals.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 wasm { struct WasmModule; // forward declaration of module interface. struct WasmFeatures; // A wrapper around the signature and bytes of a function. struct FunctionBody { FunctionSig* sig; // function signature uint32_t offset; // offset in the module bytes, for error reporting const byte* start; // start of the function body const byte* end; // end of the function body FunctionBody(FunctionSig* sig, uint32_t offset, const byte* start, const byte* end) : sig(sig), offset(offset), start(start), end(end) {} }; V8_EXPORT_PRIVATE DecodeResult VerifyWasmCode(AccountingAllocator* allocator, const WasmFeatures& enabled, const WasmModule* module, WasmFeatures* detected, const FunctionBody& body); enum PrintLocals { kPrintLocals, kOmitLocals }; V8_EXPORT_PRIVATE bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, const WasmModule* module, PrintLocals print_locals); V8_EXPORT_PRIVATE bool PrintRawWasmCode(AccountingAllocator* allocator, const FunctionBody& body, const WasmModule* module, PrintLocals print_locals, std::ostream& out, std::vector* line_numbers = nullptr); // A simplified form of AST printing, e.g. from a debugger. void PrintRawWasmCode(const byte* start, const byte* end); struct BodyLocalDecls { // The size of the encoded declarations. uint32_t encoded_size = 0; // size of encoded declarations ZoneVector type_list; explicit BodyLocalDecls(Zone* zone) : type_list(zone) {} }; V8_EXPORT_PRIVATE bool DecodeLocalDecls(const WasmFeatures& enabled, 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); // Computes the stack effect of the opcode at the given address. // Returns . // Be cautious with control opcodes: This function only covers their immediate, // local stack effect (e.g. BrIf pops 1, Br pops 0). Those opcodes can have // non-local stack effect though, which are not covered here. std::pair StackEffect(const WasmModule* module, FunctionSig* sig, 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 base::iterator { public: inline WasmOpcode operator*() { DCHECK_LT(ptr_, end_); return static_cast(*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 base::iterator { public: inline uint32_t operator*() { DCHECK_LT(ptr_, end_); return static_cast(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 opcodes() { return base::iterator_range(opcode_iterator(pc_, end_), opcode_iterator(end_, end_)); } base::iterator_range offsets() { return base::iterator_range( offset_iterator(start_, pc_, end_), offset_iterator(start_, end_, end_)); } WasmOpcode current() { return static_cast( read_u8(pc_, "expected bytecode")); } void next() { if (pc_ < end_) { pc_ += OpcodeLength(pc_, end_); if (pc_ >= end_) pc_ = end_; } } bool has_next() { return pc_ < end_; } WasmOpcode prefixed_opcode() { byte prefix = read_u8(pc_, "expected prefix"); byte index = read_u8(pc_ + 1, "expected index"); return static_cast(prefix << 8 | index); } }; } // namespace wasm } // namespace internal } // namespace v8 #endif // V8_WASM_FUNCTION_BODY_DECODER_H_