/* * Copyright 2017 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/opcode.h" #include "wabt/feature.h" namespace wabt { // static Opcode::Info Opcode::infos_[] = { #define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \ text, decomp) \ {text, decomp, Type::rtype, {Type::type1, Type::type2, Type::type3}, \ mem_size, prefix, code, PrefixCode(prefix, code)}, #include "wabt/opcode.def" #undef WABT_OPCODE {"", "", Type::Void, {Type::Void, Type::Void, Type::Void}, 0, 0, 0, 0}, }; #define WABT_OPCODE(rtype, type1, type2, type3, mem_size, prefix, code, Name, \ text, decomp) \ /* static */ Opcode Opcode::Name##_Opcode(Opcode::Name); #include "wabt/opcode.def" #undef WABT_OPCODE Opcode::Info Opcode::GetInfo() const { if (enum_ < Invalid) { return infos_[enum_]; } Info invalid_info = infos_[Opcode::Invalid]; DecodeInvalidOpcode(enum_, &invalid_info.prefix, &invalid_info.code); invalid_info.prefix_code = PrefixCode(invalid_info.prefix, invalid_info.code); return invalid_info; } bool Opcode::IsNaturallyAligned(Address alignment) const { Address opcode_align = GetMemorySize(); return alignment == WABT_USE_NATURAL_ALIGNMENT || alignment == opcode_align; } Address Opcode::GetAlignment(Address alignment) const { if (alignment == WABT_USE_NATURAL_ALIGNMENT) { return GetMemorySize(); } return alignment; } bool Opcode::IsEnabled(const Features& features) const { switch (enum_) { case Opcode::Try: case Opcode::Catch: case Opcode::Delegate: case Opcode::Throw: case Opcode::Rethrow: return features.exceptions_enabled(); case Opcode::ReturnCallIndirect: case Opcode::ReturnCall: return features.tail_call_enabled(); case Opcode::I32TruncSatF32S: case Opcode::I32TruncSatF32U: case Opcode::I32TruncSatF64S: case Opcode::I32TruncSatF64U: case Opcode::I64TruncSatF32S: case Opcode::I64TruncSatF32U: case Opcode::I64TruncSatF64S: case Opcode::I64TruncSatF64U: return features.sat_float_to_int_enabled(); case Opcode::I32Extend8S: case Opcode::I32Extend16S: case Opcode::I64Extend8S: case Opcode::I64Extend16S: case Opcode::I64Extend32S: return features.sign_extension_enabled(); case Opcode::MemoryAtomicNotify: case Opcode::MemoryAtomicWait32: case Opcode::MemoryAtomicWait64: case Opcode::AtomicFence: case Opcode::I32AtomicLoad: case Opcode::I64AtomicLoad: case Opcode::I32AtomicLoad8U: case Opcode::I32AtomicLoad16U: case Opcode::I64AtomicLoad8U: case Opcode::I64AtomicLoad16U: case Opcode::I64AtomicLoad32U: case Opcode::I32AtomicStore: case Opcode::I64AtomicStore: case Opcode::I32AtomicStore8: case Opcode::I32AtomicStore16: case Opcode::I64AtomicStore8: case Opcode::I64AtomicStore16: case Opcode::I64AtomicStore32: case Opcode::I32AtomicRmwAdd: case Opcode::I64AtomicRmwAdd: case Opcode::I32AtomicRmw8AddU: case Opcode::I32AtomicRmw16AddU: case Opcode::I64AtomicRmw8AddU: case Opcode::I64AtomicRmw16AddU: case Opcode::I64AtomicRmw32AddU: case Opcode::I32AtomicRmwSub: case Opcode::I64AtomicRmwSub: case Opcode::I32AtomicRmw8SubU: case Opcode::I32AtomicRmw16SubU: case Opcode::I64AtomicRmw8SubU: case Opcode::I64AtomicRmw16SubU: case Opcode::I64AtomicRmw32SubU: case Opcode::I32AtomicRmwAnd: case Opcode::I64AtomicRmwAnd: case Opcode::I32AtomicRmw8AndU: case Opcode::I32AtomicRmw16AndU: case Opcode::I64AtomicRmw8AndU: case Opcode::I64AtomicRmw16AndU: case Opcode::I64AtomicRmw32AndU: case Opcode::I32AtomicRmwOr: case Opcode::I64AtomicRmwOr: case Opcode::I32AtomicRmw8OrU: case Opcode::I32AtomicRmw16OrU: case Opcode::I64AtomicRmw8OrU: case Opcode::I64AtomicRmw16OrU: case Opcode::I64AtomicRmw32OrU: case Opcode::I32AtomicRmwXor: case Opcode::I64AtomicRmwXor: case Opcode::I32AtomicRmw8XorU: case Opcode::I32AtomicRmw16XorU: case Opcode::I64AtomicRmw8XorU: case Opcode::I64AtomicRmw16XorU: case Opcode::I64AtomicRmw32XorU: case Opcode::I32AtomicRmwXchg: case Opcode::I64AtomicRmwXchg: case Opcode::I32AtomicRmw8XchgU: case Opcode::I32AtomicRmw16XchgU: case Opcode::I64AtomicRmw8XchgU: case Opcode::I64AtomicRmw16XchgU: case Opcode::I64AtomicRmw32XchgU: case Opcode::I32AtomicRmwCmpxchg: case Opcode::I64AtomicRmwCmpxchg: case Opcode::I32AtomicRmw8CmpxchgU: case Opcode::I32AtomicRmw16CmpxchgU: case Opcode::I64AtomicRmw8CmpxchgU: case Opcode::I64AtomicRmw16CmpxchgU: case Opcode::I64AtomicRmw32CmpxchgU: return features.threads_enabled(); case Opcode::V128Const: case Opcode::V128Load: case Opcode::V128Store: case Opcode::I8X16Splat: case Opcode::I16X8Splat: case Opcode::I32X4Splat: case Opcode::I64X2Splat: case Opcode::F32X4Splat: case Opcode::F64X2Splat: case Opcode::I8X16ExtractLaneS: case Opcode::I8X16ExtractLaneU: case Opcode::I16X8ExtractLaneS: case Opcode::I16X8ExtractLaneU: case Opcode::I32X4ExtractLane: case Opcode::I64X2ExtractLane: case Opcode::F32X4ExtractLane: case Opcode::F64X2ExtractLane: case Opcode::I8X16ReplaceLane: case Opcode::I16X8ReplaceLane: case Opcode::I32X4ReplaceLane: case Opcode::I64X2ReplaceLane: case Opcode::F32X4ReplaceLane: case Opcode::F64X2ReplaceLane: case Opcode::I8X16Add: case Opcode::I16X8Add: case Opcode::I32X4Add: case Opcode::I64X2Add: case Opcode::I8X16Sub: case Opcode::I16X8Sub: case Opcode::I32X4Sub: case Opcode::I64X2Sub: case Opcode::I16X8Mul: case Opcode::I32X4Mul: case Opcode::I8X16Neg: case Opcode::I16X8Neg: case Opcode::I32X4Neg: case Opcode::I64X2Neg: case Opcode::I8X16AddSatS: case Opcode::I8X16AddSatU: case Opcode::I16X8AddSatS: case Opcode::I16X8AddSatU: case Opcode::I8X16SubSatS: case Opcode::I8X16SubSatU: case Opcode::I16X8SubSatS: case Opcode::I16X8SubSatU: case Opcode::I8X16Shl: case Opcode::I16X8Shl: case Opcode::I32X4Shl: case Opcode::I64X2Shl: case Opcode::I8X16ShrS: case Opcode::I8X16ShrU: case Opcode::I16X8ShrS: case Opcode::I16X8ShrU: case Opcode::I32X4ShrS: case Opcode::I32X4ShrU: case Opcode::I64X2ShrS: case Opcode::I64X2ShrU: case Opcode::V128And: case Opcode::V128Or: case Opcode::V128Xor: case Opcode::V128Not: case Opcode::V128BitSelect: case Opcode::V128AnyTrue: case Opcode::I8X16Bitmask: case Opcode::I16X8Bitmask: case Opcode::I32X4Bitmask: case Opcode::I64X2Bitmask: case Opcode::I8X16AllTrue: case Opcode::I16X8AllTrue: case Opcode::I32X4AllTrue: case Opcode::I64X2AllTrue: case Opcode::I8X16Eq: case Opcode::I16X8Eq: case Opcode::I32X4Eq: case Opcode::F32X4Eq: case Opcode::F64X2Eq: case Opcode::I8X16Ne: case Opcode::I16X8Ne: case Opcode::I32X4Ne: case Opcode::F32X4Ne: case Opcode::F64X2Ne: case Opcode::I8X16LtS: case Opcode::I8X16LtU: case Opcode::I16X8LtS: case Opcode::I16X8LtU: case Opcode::I32X4LtS: case Opcode::I32X4LtU: case Opcode::F32X4Lt: case Opcode::F64X2Lt: case Opcode::I8X16LeS: case Opcode::I8X16LeU: case Opcode::I16X8LeS: case Opcode::I16X8LeU: case Opcode::I32X4LeS: case Opcode::I32X4LeU: case Opcode::F32X4Le: case Opcode::F64X2Le: case Opcode::I8X16GtS: case Opcode::I8X16GtU: case Opcode::I16X8GtS: case Opcode::I16X8GtU: case Opcode::I32X4GtS: case Opcode::I32X4GtU: case Opcode::F32X4Gt: case Opcode::F64X2Gt: case Opcode::I8X16GeS: case Opcode::I8X16GeU: case Opcode::I16X8GeS: case Opcode::I16X8GeU: case Opcode::I32X4GeS: case Opcode::I32X4GeU: case Opcode::F32X4Ge: case Opcode::F64X2Ge: case Opcode::F32X4Neg: case Opcode::F64X2Neg: case Opcode::F32X4Abs: case Opcode::F64X2Abs: case Opcode::F32X4Min: case Opcode::F32X4PMin: case Opcode::F64X2Min: case Opcode::F64X2PMin: case Opcode::F32X4Max: case Opcode::F32X4PMax: case Opcode::F64X2Max: case Opcode::F64X2PMax: case Opcode::F32X4Add: case Opcode::F64X2Add: case Opcode::F32X4Sub: case Opcode::F64X2Sub: case Opcode::F32X4Div: case Opcode::F64X2Div: case Opcode::F32X4Mul: case Opcode::F64X2Mul: case Opcode::F32X4Sqrt: case Opcode::F64X2Sqrt: case Opcode::F32X4ConvertI32X4S: case Opcode::F32X4ConvertI32X4U: case Opcode::I32X4TruncSatF32X4S: case Opcode::I32X4TruncSatF32X4U: case Opcode::I8X16Swizzle: case Opcode::I8X16Shuffle: case Opcode::V128Load8Splat: case Opcode::V128Load16Splat: case Opcode::V128Load32Splat: case Opcode::V128Load64Splat: case Opcode::V128Load8Lane: case Opcode::V128Load16Lane: case Opcode::V128Load32Lane: case Opcode::V128Load64Lane: case Opcode::V128Store8Lane: case Opcode::V128Store16Lane: case Opcode::V128Store32Lane: case Opcode::V128Store64Lane: case Opcode::I8X16Abs: case Opcode::I16X8Abs: case Opcode::I32X4Abs: return features.simd_enabled(); case Opcode::I8X16RelaxedSwizzle: case Opcode::I32X4RelaxedTruncF32X4S: case Opcode::I32X4RelaxedTruncF32X4U: case Opcode::I32X4RelaxedTruncF64X2SZero: case Opcode::I32X4RelaxedTruncF64X2UZero: case Opcode::F32X4RelaxedMadd: case Opcode::F32X4RelaxedNmadd: case Opcode::F64X2RelaxedMadd: case Opcode::F64X2RelaxedNmadd: case Opcode::I8X16RelaxedLaneSelect: case Opcode::I16X8RelaxedLaneSelect: case Opcode::I32X4RelaxedLaneSelect: case Opcode::I64X2RelaxedLaneSelect: case Opcode::F32X4RelaxedMin: case Opcode::F32X4RelaxedMax: case Opcode::F64X2RelaxedMin: case Opcode::F64X2RelaxedMax: case Opcode::I16X8RelaxedQ15mulrS: case Opcode::I16X8DotI8X16I7X16S: case Opcode::I32X4DotI8X16I7X16AddS: return features.relaxed_simd_enabled(); case Opcode::MemoryInit: case Opcode::DataDrop: case Opcode::MemoryCopy: case Opcode::MemoryFill: case Opcode::TableInit: case Opcode::ElemDrop: case Opcode::TableCopy: return features.bulk_memory_enabled(); case Opcode::TableGet: case Opcode::TableSet: case Opcode::TableGrow: case Opcode::TableSize: case Opcode::RefNull: case Opcode::RefIsNull: return features.reference_types_enabled(); case Opcode::CallRef: return features.function_references_enabled(); // Interpreter opcodes are never "enabled". case Opcode::InterpAlloca: case Opcode::InterpBrUnless: case Opcode::InterpCallImport: case Opcode::InterpData: case Opcode::InterpDropKeep: return false; default: return true; } } uint32_t Opcode::GetSimdLaneCount() const { switch (enum_) { case Opcode::I8X16ExtractLaneS: case Opcode::I8X16ExtractLaneU: case Opcode::I8X16ReplaceLane: case Opcode::V128Load8Lane: case Opcode::V128Store8Lane: return 16; break; case Opcode::I16X8ExtractLaneS: case Opcode::I16X8ExtractLaneU: case Opcode::I16X8ReplaceLane: case Opcode::V128Load16Lane: case Opcode::V128Store16Lane: return 8; break; case Opcode::F32X4ExtractLane: case Opcode::F32X4ReplaceLane: case Opcode::I32X4ExtractLane: case Opcode::I32X4ReplaceLane: case Opcode::V128Load32Lane: case Opcode::V128Store32Lane: return 4; break; case Opcode::F64X2ExtractLane: case Opcode::F64X2ReplaceLane: case Opcode::I64X2ExtractLane: case Opcode::I64X2ReplaceLane: case Opcode::V128Load64Lane: case Opcode::V128Store64Lane: return 2; break; default: WABT_UNREACHABLE; } } // Get the byte sequence for this opcode, including prefix. std::vector Opcode::GetBytes() const { std::vector result; if (HasPrefix()) { result.push_back(GetPrefix()); uint8_t buffer[5]; Offset length = WriteU32Leb128Raw(buffer, buffer + sizeof(buffer), GetCode()); assert(length != 0); result.insert(result.end(), buffer, buffer + length); } else { result.push_back(GetCode()); } return result; } } // namespace wabt