diff options
author | Alex Reinking <reinking@google.com> | 2022-09-28 07:24:49 -0700 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-09-28 07:24:49 -0700 |
commit | a4a77c18df16d6ee672f2a2564969bc9b2beef3a (patch) | |
tree | e4368558b4b44a7421761341e3b18edbd93f9785 /include/wabt/interp/istream.h | |
parent | 520614a5f83878a4d26702a3ad67c44302c2b073 (diff) | |
download | wabt-a4a77c18df16d6ee672f2a2564969bc9b2beef3a.tar.gz wabt-a4a77c18df16d6ee672f2a2564969bc9b2beef3a.tar.bz2 wabt-a4a77c18df16d6ee672f2a2564969bc9b2beef3a.zip |
Move headers to include/wabt/ (#1998)
This makes things easier for users and packagers of libwabt.
Diffstat (limited to 'include/wabt/interp/istream.h')
-rw-r--r-- | include/wabt/interp/istream.h | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/include/wabt/interp/istream.h b/include/wabt/interp/istream.h new file mode 100644 index 00000000..06e1cfca --- /dev/null +++ b/include/wabt/interp/istream.h @@ -0,0 +1,165 @@ +/* + * Copyright 2020 WebAssembly Community Group participants + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef WABT_INTERP_ISTREAM_H_ +#define WABT_INTERP_ISTREAM_H_ + +#include <cstdint> +#include <string> +#include <vector> + +#include "wabt/common.h" +#include "wabt/opcode.h" +#include "wabt/stream.h" + +namespace wabt { +namespace interp { + +using u8 = uint8_t; +using u16 = uint16_t; +using u32 = uint32_t; +using u64 = uint64_t; +using f32 = float; +using f64 = double; + +using Buffer = std::vector<u8>; + +using ValueType = wabt::Type; + +// Group instructions based on their immediates their operands. This way we can +// simplify instruction decoding, disassembling, and tracing. There is an +// example of an instruction that uses this encoding on the right. +enum class InstrKind { + Imm_0_Op_0, // Nop + Imm_0_Op_1, // i32.eqz + Imm_0_Op_2, // i32.add + Imm_0_Op_3, // select + Imm_Jump_Op_0, // br + Imm_Jump_Op_1, // br_if + Imm_Index_Op_0, // global.get + Imm_Index_Op_1, // global.set + Imm_Index_Op_2, // table.set + Imm_Index_Op_3, // memory.fill + Imm_Index_Op_N, // call + Imm_Index_Index_Op_3, // memory.init + Imm_Index_Index_Op_N, // call_indirect + Imm_Index_Offset_Op_1, // i32.load + Imm_Index_Offset_Op_2, // i32.store + Imm_Index_Offset_Op_3, // i32.atomic.rmw.cmpxchg + Imm_Index_Offset_Lane_Op_2, // v128.load8_lane + Imm_I32_Op_0, // i32.const + Imm_I64_Op_0, // i64.const + Imm_F32_Op_0, // f32.const + Imm_F64_Op_0, // f64.const + Imm_I32_I32_Op_0, // drop_keep + Imm_I8_Op_1, // i32x4.extract_lane + Imm_I8_Op_2, // i32x4.replace_lane + Imm_V128_Op_0, // v128.const + Imm_V128_Op_2, // i8x16.shuffle +}; + +struct Instr { + Opcode op; + InstrKind kind; + union { + u8 imm_u8; + u32 imm_u32; + f32 imm_f32; + u64 imm_u64; + f64 imm_f64; + v128 imm_v128; + struct { + u32 fst, snd; + } imm_u32x2; + struct { + u32 fst, snd; + u8 idx; + } imm_u32x2_u8; + }; +}; + +class Istream { + public: + using SerializedOpcode = u32; // TODO: change to u16 + using Offset = u32; + static const Offset kInvalidOffset = ~0; + // Each br_table entry is made up of three instructions: + // + // interp_drop_keep $drop $keep + // interp_catch_drop $catches + // br $label + // + // Each opcode is a SerializedOpcode, and each immediate is a u32. + static const Offset kBrTableEntrySize = + sizeof(SerializedOpcode) * 3 + 4 * sizeof(u32); + + // Emit API. + void Emit(u32); + void Emit(Opcode::Enum); + void Emit(Opcode::Enum, u8); + void Emit(Opcode::Enum, u32); + void Emit(Opcode::Enum, u64); + void Emit(Opcode::Enum, v128); + void Emit(Opcode::Enum, u32, u32); + void Emit(Opcode::Enum, u32, u32, u8); + void EmitDropKeep(u32 drop, u32 keep); + void EmitCatchDrop(u32 drop); + + Offset EmitFixupU32(); + void ResolveFixupU32(Offset); + + Offset end() const; + + // Read API. + Instr Read(Offset*) const; + + // Disassemble/Trace API. + // TODO separate out disassembly/tracing? + struct TraceSource { + virtual ~TraceSource() {} + // Whatever content should go before the instruction on each line, e.g. the + // call stack size, value stack size, and istream offset. + virtual std::string Header(Offset) = 0; + virtual std::string Pick(Index, Instr) = 0; + }; + + struct DisassemblySource : TraceSource { + std::string Header(Offset) override; + std::string Pick(Index, Instr) override; + }; + + void Disassemble(Stream*) const; + Offset Disassemble(Stream*, Offset) const; + void Disassemble(Stream*, Offset from, Offset to) const; + + Offset Trace(Stream*, Offset, TraceSource*) const; + + private: + template <typename T> + void WABT_VECTORCALL EmitAt(Offset, T val); + template <typename T> + void WABT_VECTORCALL EmitInternal(T val); + + template <typename T> + T WABT_VECTORCALL ReadAt(Offset*) const; + + Buffer data_; +}; + +} // namespace interp +} // namespace wabt + +#endif // WABT_INTERP_ISTREAM_H_ |