/* * Copyright 2016 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. */ #include "wabt/binary-reader-opcnt.h" #include #include #include #include #include #include "wabt/binary-reader-nop.h" #include "wabt/common.h" #include "wabt/literal.h" #include "wabt/stream.h" namespace wabt { OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind) : opcode_(opcode), kind_(kind) {} template OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count) : OpcodeInfo(opcode, kind) { if (count > 0) { data_.resize(sizeof(T) * count); memcpy(data_.data(), data, data_.size()); } } template OpcodeInfo::OpcodeInfo(Opcode opcode, Kind kind, T* data, size_t count, T extra) : OpcodeInfo(opcode, kind, data, count) { data_.resize(data_.size() + sizeof(T)); memcpy(data_.data() + data_.size() - sizeof(T), &extra, sizeof(T)); } template std::pair OpcodeInfo::GetDataArray() const { if (data_.empty()) { return std::pair(nullptr, 0); } assert(data_.size() % sizeof(T) == 0); return std::make_pair(reinterpret_cast(data_.data()), data_.size() / sizeof(T)); } template const T* OpcodeInfo::GetData(size_t expected_size) const { auto [data, size] = GetDataArray(); assert(size == expected_size); return data; } template void OpcodeInfo::WriteArray(Stream& stream, F&& write_func) { auto [data, size] = GetDataArray(); for (size_t i = 0; i < size; ++i) { // Write an initial space (to separate from the opcode name) first, then // comma-separate. stream.Writef("%s", i == 0 ? " " : ", "); write_func(data[i]); } } void OpcodeInfo::Write(Stream& stream) { stream.Writef("%s", opcode_.GetName()); switch (kind_) { case Kind::Bare: break; case Kind::Uint32: stream.Writef(" %u (0x%x)", *GetData(), *GetData()); break; case Kind::Uint64: stream.Writef(" %" PRIu64 " (0x%" PRIx64 ")", *GetData(), *GetData()); break; case Kind::Index: stream.Writef(" %" PRIindex, *GetData()); break; case Kind::Float32: { stream.Writef(" %g", *GetData()); char buffer[WABT_MAX_FLOAT_HEX + 1]; WriteFloatHex(buffer, sizeof(buffer), *GetData()); stream.Writef(" (%s)", buffer); break; } case Kind::Float64: { stream.Writef(" %g", *GetData()); char buffer[WABT_MAX_DOUBLE_HEX + 1]; WriteDoubleHex(buffer, sizeof(buffer), *GetData()); stream.Writef(" (%s)", buffer); break; } case Kind::V128: { auto data = *GetData(); auto l0 = data.u32(0); auto l1 = data.u32(1); auto l2 = data.u32(2); auto l3 = data.u32(3); stream.Writef(" %u %u %u %u (0x%x 0x%x 0x%x 0x%x)", l0, l1, l2, l3, l0, l1, l2, l3); break; } case Kind::Uint32Uint32: case Kind::Uint32Uint32Uint32: case Kind::Uint32Uint32Uint32Uint32: WriteArray( stream, [&stream](uint32_t value) { stream.Writef("%u", value); }); break; case Kind::BlockSig: { auto type = *GetData(); if (type.IsIndex()) { stream.Writef(" type:%d", type.GetIndex()); } else if (type != Type::Void) { stream.Writef(" %s", type.GetName().c_str()); } break; } case Kind::BrTable: { WriteArray(stream, [&stream](Index index) { stream.Writef("%" PRIindex, index); }); break; } } } bool operator==(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { return lhs.opcode_ == rhs.opcode_ && lhs.kind_ == rhs.kind_ && lhs.data_ == rhs.data_; } bool operator!=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { return !(lhs == rhs); } bool operator<(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { if (lhs.opcode_ < rhs.opcode_) { return true; } if (lhs.opcode_ > rhs.opcode_) { return false; } if (lhs.kind_ < rhs.kind_) { return true; } if (lhs.kind_ > rhs.kind_) { return false; } if (lhs.data_ < rhs.data_) { return true; } if (lhs.data_ > rhs.data_) { return false; } return false; } bool operator<=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { return lhs < rhs || lhs == rhs; } bool operator>(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { return !(lhs <= rhs); } bool operator>=(const OpcodeInfo& lhs, const OpcodeInfo& rhs) { return !(lhs < rhs); } namespace { class BinaryReaderOpcnt : public BinaryReaderNop { public: explicit BinaryReaderOpcnt(OpcodeInfoCounts* counts); Result OnOpcode(Opcode opcode) override; Result OnOpcodeBare() override; Result OnOpcodeUint32(uint32_t value) override; Result OnOpcodeIndex(Index value) override; Result OnOpcodeUint32Uint32(uint32_t value, uint32_t value2) override; Result OnOpcodeUint32Uint32Uint32(uint32_t value, uint32_t value2, uint32_t value3) override; Result OnOpcodeUint64(uint64_t value) override; Result OnOpcodeF32(uint32_t value) override; Result OnOpcodeF64(uint64_t value) override; Result OnOpcodeV128(v128 value) override; Result OnOpcodeBlockSig(Type sig_type) override; Result OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) override; Result OnEndExpr() override; private: template Result Emplace(Args&&... args); OpcodeInfoCounts* opcode_counts_; Opcode current_opcode_; }; template Result BinaryReaderOpcnt::Emplace(Args&&... args) { auto pair = opcode_counts_->emplace( std::piecewise_construct, std::make_tuple(std::forward(args)...), std::make_tuple(0)); auto& count = pair.first->second; count++; return Result::Ok; } BinaryReaderOpcnt::BinaryReaderOpcnt(OpcodeInfoCounts* counts) : opcode_counts_(counts) {} Result BinaryReaderOpcnt::OnOpcode(Opcode opcode) { current_opcode_ = opcode; return Result::Ok; } Result BinaryReaderOpcnt::OnOpcodeBare() { return Emplace(current_opcode_, OpcodeInfo::Kind::Bare); } Result BinaryReaderOpcnt::OnOpcodeUint32(uint32_t value) { return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32, &value); } Result BinaryReaderOpcnt::OnOpcodeIndex(Index value) { return Emplace(current_opcode_, OpcodeInfo::Kind::Index, &value); } Result BinaryReaderOpcnt::OnOpcodeUint32Uint32(uint32_t value0, uint32_t value1) { uint32_t array[2] = {value0, value1}; return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32, array, 2); } Result BinaryReaderOpcnt::OnOpcodeUint32Uint32Uint32(uint32_t value0, uint32_t value1, uint32_t value2) { uint32_t array[3] = {value0, value1, value2}; return Emplace(current_opcode_, OpcodeInfo::Kind::Uint32Uint32Uint32, array, 3); } Result BinaryReaderOpcnt::OnOpcodeUint64(uint64_t value) { return Emplace(current_opcode_, OpcodeInfo::Kind::Uint64, &value); } Result BinaryReaderOpcnt::OnOpcodeF32(uint32_t value) { return Emplace(current_opcode_, OpcodeInfo::Kind::Float32, &value); } Result BinaryReaderOpcnt::OnOpcodeF64(uint64_t value) { return Emplace(current_opcode_, OpcodeInfo::Kind::Float64, &value); } Result BinaryReaderOpcnt::OnOpcodeV128(v128 value) { return Emplace(current_opcode_, OpcodeInfo::Kind::V128, &value); } Result BinaryReaderOpcnt::OnOpcodeBlockSig(Type sig_type) { return Emplace(current_opcode_, OpcodeInfo::Kind::BlockSig, &sig_type); } Result BinaryReaderOpcnt::OnBrTableExpr(Index num_targets, Index* target_depths, Index default_target_depth) { return Emplace(current_opcode_, OpcodeInfo::Kind::BrTable, target_depths, num_targets, default_target_depth); } Result BinaryReaderOpcnt::OnEndExpr() { return Emplace(Opcode::End, OpcodeInfo::Kind::Bare); } } // end anonymous namespace Result ReadBinaryOpcnt(const void* data, size_t size, const ReadBinaryOptions& options, OpcodeInfoCounts* counts) { BinaryReaderOpcnt reader(counts); return ReadBinary(data, size, &reader, options); } } // namespace wabt