From ac3f3bb121084ce5d8f5da22034d78b3ac63ca12 Mon Sep 17 00:00:00 2001 From: Lars T Hansen Date: Fri, 30 Jun 2017 14:56:07 -0700 Subject: [PATCH] Bug 1377518 - Support wasm opcode prefixes, and use the reserved FF prefix for internal asm.js opcodes. r=sunfish --HG-- extra : rebase_source : 2559f595c3ebd6bd7894bbaeddb24fcc2a4267b8 --- js/src/jit-test/lib/wasm-binary.js | 3 + js/src/jit-test/tests/wasm/binary.js | 20 +- js/src/wasm/AsmJS.cpp | 194 +++++----- js/src/wasm/WasmBaselineCompile.cpp | 16 +- js/src/wasm/WasmBinaryConstants.h | 38 +- js/src/wasm/WasmBinaryIterator.cpp | 538 ++++++++++++++------------- js/src/wasm/WasmBinaryIterator.h | 50 ++- js/src/wasm/WasmBinaryToAST.cpp | 96 ++--- js/src/wasm/WasmIonCompile.cpp | 328 ++++++++-------- js/src/wasm/WasmValidate.cpp | 14 +- js/src/wasm/WasmValidate.h | 30 +- 11 files changed, 716 insertions(+), 611 deletions(-) diff --git a/js/src/jit-test/lib/wasm-binary.js b/js/src/jit-test/lib/wasm-binary.js index 3be70031858f..1f8090b4db5e 100644 --- a/js/src/jit-test/lib/wasm-binary.js +++ b/js/src/jit-test/lib/wasm-binary.js @@ -91,6 +91,9 @@ const I64TruncSF64Code = 0xb0; const I64TruncUF64Code = 0xb1; const FirstInvalidOpcode = 0xc0; +const LastInvalidOpcode = 0xfd; +const AtomicPrefix = 0xfe; +const MozPrefix = 0xff; // DefinitionKind const FunctionCode = 0x00; diff --git a/js/src/jit-test/tests/wasm/binary.js b/js/src/jit-test/tests/wasm/binary.js index ba8da09b2c52..180d65bb3bd2 100644 --- a/js/src/jit-test/tests/wasm/binary.js +++ b/js/src/jit-test/tests/wasm/binary.js @@ -436,9 +436,23 @@ assertEq(arr[0].byteLength, nameSec.body.length - 5 /* 4name */); for (var bad of [0xff, 0, 1, 0x3f]) assertErrorMessage(() => wasmEval(moduleWithSections([sigSection([v2vSig]), declSection([0]), bodySection([funcBody({locals:[], body:[BlockCode, bad, EndCode]})])])), CompileError, /invalid inline block type/); -// Ensure all asm.js opcodes rejected -for (var i = FirstInvalidOpcode; i <= 0xff; i++) { - var binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[i]})])]); +// Ensure all invalid opcodes rejected +for (let i = FirstInvalidOpcode; i <= LastInvalidOpcode; i++) { + let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[i]})])]); + assertErrorMessage(() => wasmEval(binary), CompileError, /unrecognized opcode/); + assertEq(WebAssembly.validate(binary), false); +} + +// Prefixed opcodes +for (let prefix of [AtomicPrefix, MozPrefix]) { + for (let i = 0; i <= 255; i++) { + let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[prefix, i]})])]); + assertErrorMessage(() => wasmEval(binary), CompileError, /unrecognized opcode/); + assertEq(WebAssembly.validate(binary), false); + } + + // Prefix without a subsequent opcode + let binary = moduleWithSections([v2vSigSection, declSection([0]), bodySection([funcBody({locals:[], body:[prefix]})])]); assertErrorMessage(() => wasmEval(binary), CompileError, /unrecognized opcode/); assertEq(WebAssembly.validate(binary), false); } diff --git a/js/src/wasm/AsmJS.cpp b/js/src/wasm/AsmJS.cpp index a375abe74d27..0dc91454f94c 100644 --- a/js/src/wasm/AsmJS.cpp +++ b/js/src/wasm/AsmJS.cpp @@ -2759,7 +2759,7 @@ IsLiteralInt(ModuleValidator& m, ParseNode* pn, uint32_t* u32) namespace { -#define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return Op::TYPE##OP; +#define CASE(TYPE, OP) case SimdOperation::Fn_##OP: return MozOp::TYPE##OP; #define I8x16CASE(OP) CASE(I8x16, OP) #define I16x8CASE(OP) CASE(I16x8, OP) #define I32x4CASE(OP) CASE(I32x4, OP) @@ -2769,36 +2769,36 @@ namespace { #define B32x4CASE(OP) CASE(B32x4, OP) #define ENUMERATE(TYPE, FOR_ALL, DO) \ switch(op) { \ - case SimdOperation::Constructor: return Op::TYPE##Constructor; \ + case SimdOperation::Constructor: return MozOp::TYPE##Constructor;\ FOR_ALL(DO) \ default: break; \ } -static inline Op +static inline MozOp SimdToOp(SimdType type, SimdOperation op) { switch (type) { case SimdType::Uint8x16: // Handle the special unsigned opcodes, then fall through to Int8x16. switch (op) { - case SimdOperation::Fn_addSaturate: return Op::I8x16addSaturateU; - case SimdOperation::Fn_subSaturate: return Op::I8x16subSaturateU; - case SimdOperation::Fn_extractLane: return Op::I8x16extractLaneU; - case SimdOperation::Fn_shiftRightByScalar: return Op::I8x16shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Op::I8x16lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Op::I8x16lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Op::I8x16greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Op::I8x16greaterThanOrEqualU; - case SimdOperation::Fn_fromInt8x16Bits: return Op::Limit; + case SimdOperation::Fn_addSaturate: return MozOp::I8x16addSaturateU; + case SimdOperation::Fn_subSaturate: return MozOp::I8x16subSaturateU; + case SimdOperation::Fn_extractLane: return MozOp::I8x16extractLaneU; + case SimdOperation::Fn_shiftRightByScalar: return MozOp::I8x16shiftRightByScalarU; + case SimdOperation::Fn_lessThan: return MozOp::I8x16lessThanU; + case SimdOperation::Fn_lessThanOrEqual: return MozOp::I8x16lessThanOrEqualU; + case SimdOperation::Fn_greaterThan: return MozOp::I8x16greaterThanU; + case SimdOperation::Fn_greaterThanOrEqual: return MozOp::I8x16greaterThanOrEqualU; + case SimdOperation::Fn_fromInt8x16Bits: return MozOp::Limit; default: break; } MOZ_FALLTHROUGH; case SimdType::Int8x16: // Bitcasts Uint8x16 <--> Int8x16 become noops. switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::Limit; - case SimdOperation::Fn_fromUint16x8Bits: return Op::I8x16fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Op::I8x16fromInt32x4Bits; + case SimdOperation::Fn_fromUint8x16Bits: return MozOp::Limit; + case SimdOperation::Fn_fromUint16x8Bits: return MozOp::I8x16fromInt16x8Bits; + case SimdOperation::Fn_fromUint32x4Bits: return MozOp::I8x16fromInt32x4Bits; default: break; } ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) @@ -2807,24 +2807,24 @@ SimdToOp(SimdType type, SimdOperation op) case SimdType::Uint16x8: // Handle the special unsigned opcodes, then fall through to Int16x8. switch(op) { - case SimdOperation::Fn_addSaturate: return Op::I16x8addSaturateU; - case SimdOperation::Fn_subSaturate: return Op::I16x8subSaturateU; - case SimdOperation::Fn_extractLane: return Op::I16x8extractLaneU; - case SimdOperation::Fn_shiftRightByScalar: return Op::I16x8shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Op::I16x8lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Op::I16x8lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Op::I16x8greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Op::I16x8greaterThanOrEqualU; - case SimdOperation::Fn_fromInt16x8Bits: return Op::Limit; + case SimdOperation::Fn_addSaturate: return MozOp::I16x8addSaturateU; + case SimdOperation::Fn_subSaturate: return MozOp::I16x8subSaturateU; + case SimdOperation::Fn_extractLane: return MozOp::I16x8extractLaneU; + case SimdOperation::Fn_shiftRightByScalar: return MozOp::I16x8shiftRightByScalarU; + case SimdOperation::Fn_lessThan: return MozOp::I16x8lessThanU; + case SimdOperation::Fn_lessThanOrEqual: return MozOp::I16x8lessThanOrEqualU; + case SimdOperation::Fn_greaterThan: return MozOp::I16x8greaterThanU; + case SimdOperation::Fn_greaterThanOrEqual: return MozOp::I16x8greaterThanOrEqualU; + case SimdOperation::Fn_fromInt16x8Bits: return MozOp::Limit; default: break; } MOZ_FALLTHROUGH; case SimdType::Int16x8: // Bitcasts Uint16x8 <--> Int16x8 become noops. switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::I16x8fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Op::Limit; - case SimdOperation::Fn_fromUint32x4Bits: return Op::I16x8fromInt32x4Bits; + case SimdOperation::Fn_fromUint8x16Bits: return MozOp::I16x8fromInt8x16Bits; + case SimdOperation::Fn_fromUint16x8Bits: return MozOp::Limit; + case SimdOperation::Fn_fromUint32x4Bits: return MozOp::I16x8fromInt32x4Bits; default: break; } ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) @@ -2833,22 +2833,22 @@ SimdToOp(SimdType type, SimdOperation op) case SimdType::Uint32x4: // Handle the special unsigned opcodes, then fall through to Int32x4. switch(op) { - case SimdOperation::Fn_shiftRightByScalar: return Op::I32x4shiftRightByScalarU; - case SimdOperation::Fn_lessThan: return Op::I32x4lessThanU; - case SimdOperation::Fn_lessThanOrEqual: return Op::I32x4lessThanOrEqualU; - case SimdOperation::Fn_greaterThan: return Op::I32x4greaterThanU; - case SimdOperation::Fn_greaterThanOrEqual: return Op::I32x4greaterThanOrEqualU; - case SimdOperation::Fn_fromFloat32x4: return Op::I32x4fromFloat32x4U; - case SimdOperation::Fn_fromInt32x4Bits: return Op::Limit; + case SimdOperation::Fn_shiftRightByScalar: return MozOp::I32x4shiftRightByScalarU; + case SimdOperation::Fn_lessThan: return MozOp::I32x4lessThanU; + case SimdOperation::Fn_lessThanOrEqual: return MozOp::I32x4lessThanOrEqualU; + case SimdOperation::Fn_greaterThan: return MozOp::I32x4greaterThanU; + case SimdOperation::Fn_greaterThanOrEqual: return MozOp::I32x4greaterThanOrEqualU; + case SimdOperation::Fn_fromFloat32x4: return MozOp::I32x4fromFloat32x4U; + case SimdOperation::Fn_fromInt32x4Bits: return MozOp::Limit; default: break; } MOZ_FALLTHROUGH; case SimdType::Int32x4: // Bitcasts Uint32x4 <--> Int32x4 become noops. switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::I32x4fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Op::I32x4fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Op::Limit; + case SimdOperation::Fn_fromUint8x16Bits: return MozOp::I32x4fromInt8x16Bits; + case SimdOperation::Fn_fromUint16x8Bits: return MozOp::I32x4fromInt16x8Bits; + case SimdOperation::Fn_fromUint32x4Bits: return MozOp::Limit; default: break; } ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) @@ -2856,9 +2856,9 @@ SimdToOp(SimdType type, SimdOperation op) case SimdType::Float32x4: switch (op) { - case SimdOperation::Fn_fromUint8x16Bits: return Op::F32x4fromInt8x16Bits; - case SimdOperation::Fn_fromUint16x8Bits: return Op::F32x4fromInt16x8Bits; - case SimdOperation::Fn_fromUint32x4Bits: return Op::F32x4fromInt32x4Bits; + case SimdOperation::Fn_fromUint8x16Bits: return MozOp::F32x4fromInt8x16Bits; + case SimdOperation::Fn_fromUint16x8Bits: return MozOp::F32x4fromInt16x8Bits; + case SimdOperation::Fn_fromUint32x4Bits: return MozOp::F32x4fromInt32x4Bits; default: break; } ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) @@ -3195,30 +3195,30 @@ class MOZ_STACK_CLASS FunctionValidator encoder().writeFixedF64(lit.toDouble()); case NumLit::Int8x16: case NumLit::Uint8x16: - return encoder().writeOp(Op::I8x16Const) && + return encoder().writeOp(MozOp::I8x16Const) && encoder().writeFixedI8x16(lit.simdValue().asInt8x16()); case NumLit::Int16x8: case NumLit::Uint16x8: - return encoder().writeOp(Op::I16x8Const) && + return encoder().writeOp(MozOp::I16x8Const) && encoder().writeFixedI16x8(lit.simdValue().asInt16x8()); case NumLit::Int32x4: case NumLit::Uint32x4: - return encoder().writeOp(Op::I32x4Const) && + return encoder().writeOp(MozOp::I32x4Const) && encoder().writeFixedI32x4(lit.simdValue().asInt32x4()); case NumLit::Float32x4: - return encoder().writeOp(Op::F32x4Const) && + return encoder().writeOp(MozOp::F32x4Const) && encoder().writeFixedF32x4(lit.simdValue().asFloat32x4()); case NumLit::Bool8x16: // Boolean vectors use the Int8x16 memory representation. - return encoder().writeOp(Op::B8x16Const) && + return encoder().writeOp(MozOp::B8x16Const) && encoder().writeFixedI8x16(lit.simdValue().asInt8x16()); case NumLit::Bool16x8: // Boolean vectors use the Int16x8 memory representation. - return encoder().writeOp(Op::B16x8Const) && + return encoder().writeOp(MozOp::B16x8Const) && encoder().writeFixedI16x8(lit.simdValue().asInt16x8()); case NumLit::Bool32x4: // Boolean vectors use the Int32x4 memory representation. - return encoder().writeOp(Op::B32x4Const) && + return encoder().writeOp(MozOp::B32x4Const) && encoder().writeFixedI32x4(lit.simdValue().asInt32x4()); case NumLit::OutOfRangeInt: break; @@ -3229,12 +3229,16 @@ class MOZ_STACK_CLASS FunctionValidator return encoder().writeOp(op) && fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); } + MOZ_MUST_USE bool writeCall(ParseNode* pn, MozOp op) { + return encoder().writeOp(op) && + fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); + } MOZ_MUST_USE bool prepareCall(ParseNode* pn) { return fg_.addCallSiteLineNum(m().tokenStream().srcCoords.lineNum(pn->pn_pos.begin)); } MOZ_MUST_USE bool writeSimdOp(SimdType simdType, SimdOperation simdOp) { - Op op = SimdToOp(simdType, simdOp); - if (op == Op::Limit) + MozOp op = SimdToOp(simdType, simdOp); + if (op == MozOp::Limit) return true; return encoder().writeOp(op); } @@ -4237,34 +4241,34 @@ CheckStoreArray(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type switch (viewType) { case Scalar::Int8: case Scalar::Uint8: - if (!f.encoder().writeOp(Op::I32TeeStore8)) + if (!f.encoder().writeOp(MozOp::I32TeeStore8)) return false; break; case Scalar::Int16: case Scalar::Uint16: - if (!f.encoder().writeOp(Op::I32TeeStore16)) + if (!f.encoder().writeOp(MozOp::I32TeeStore16)) return false; break; case Scalar::Int32: case Scalar::Uint32: - if (!f.encoder().writeOp(Op::I32TeeStore)) + if (!f.encoder().writeOp(MozOp::I32TeeStore)) return false; break; case Scalar::Float32: if (rhsType.isFloatish()) { - if (!f.encoder().writeOp(Op::F32TeeStore)) + if (!f.encoder().writeOp(MozOp::F32TeeStore)) return false; } else { - if (!f.encoder().writeOp(Op::F64TeeStoreF32)) + if (!f.encoder().writeOp(MozOp::F64TeeStoreF32)) return false; } break; case Scalar::Float64: if (rhsType.isFloatish()) { - if (!f.encoder().writeOp(Op::F32TeeStoreF64)) + if (!f.encoder().writeOp(MozOp::F32TeeStoreF64)) return false; } else { - if (!f.encoder().writeOp(Op::F64TeeStore)) + if (!f.encoder().writeOp(MozOp::F64TeeStore)) return false; } break; @@ -4312,7 +4316,7 @@ CheckAssignName(FunctionValidator& f, ParseNode* lhs, ParseNode* rhs, Type* type Type globType = global->varOrConstType(); if (!(rhsType <= globType)) return f.failf(lhs, "%s is not a subtype of %s", rhsType.toChars(), globType.toChars()); - if (!f.encoder().writeOp(Op::TeeGlobal)) + if (!f.encoder().writeOp(MozOp::TeeGlobal)) return false; if (!f.encoder().writeVarU32(global->varOrConstIndex())) return false; @@ -4400,7 +4404,7 @@ CheckMathAbs(FunctionValidator& f, ParseNode* call, Type* type) if (argType.isSigned()) { *type = Type::Unsigned; - return f.encoder().writeOp(Op::I32Abs); + return f.encoder().writeOp(MozOp::I32Abs); } if (argType.isMaybeDouble()) { @@ -4452,7 +4456,8 @@ CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* typ if (!CheckExpr(f, firstArg, &firstType)) return false; - Op op; + Op op = Op::Limit; + MozOp mozOp = MozOp::Limit; if (firstType.isMaybeDouble()) { *type = Type::Double; firstType = Type::MaybeDouble; @@ -4464,7 +4469,7 @@ CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* typ } else if (firstType.isSigned()) { *type = Type::Signed; firstType = Type::Signed; - op = isMax ? Op::I32Max : Op::I32Min; + mozOp = isMax ? MozOp::I32Max : MozOp::I32Min; } else { return f.failf(firstArg, "%s is not a subtype of double?, float? or signed", firstType.toChars()); @@ -4479,8 +4484,13 @@ CheckMathMinMax(FunctionValidator& f, ParseNode* callNode, bool isMax, Type* typ if (!(nextType <= firstType)) return f.failf(nextArg, "%s is not a subtype of %s", nextType.toChars(), firstType.toChars()); - if (!f.encoder().writeOp(op)) - return false; + if (op != Op::Limit) { + if (!f.encoder().writeOp(op)) + return false; + } else { + if (!f.encoder().writeOp(mozOp)) + return false; + } } return true; @@ -4516,7 +4526,7 @@ CheckSharedArrayAtomicAccess(FunctionValidator& f, ParseNode* viewName, ParseNod } static bool -WriteAtomicOperator(FunctionValidator& f, Op opcode, Scalar::Type viewType) +WriteAtomicOperator(FunctionValidator& f, MozOp opcode, Scalar::Type viewType) { return f.encoder().writeOp(opcode) && f.encoder().writeFixedU8(viewType); @@ -4535,7 +4545,7 @@ CheckAtomicsLoad(FunctionValidator& f, ParseNode* call, Type* type) if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Op::I32AtomicsLoad, viewType)) + if (!WriteAtomicOperator(f, MozOp::I32AtomicsLoad, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) @@ -4566,7 +4576,7 @@ CheckAtomicsStore(FunctionValidator& f, ParseNode* call, Type* type) if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Op::I32AtomicsStore, viewType)) + if (!WriteAtomicOperator(f, MozOp::I32AtomicsStore, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) @@ -4597,7 +4607,7 @@ CheckAtomicsBinop(FunctionValidator& f, ParseNode* call, Type* type, AtomicOp op if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Op::I32AtomicsBinOp, viewType)) + if (!WriteAtomicOperator(f, MozOp::I32AtomicsBinOp, viewType)) return false; if (!f.encoder().writeFixedU8(uint8_t(op))) return false; @@ -4654,7 +4664,7 @@ CheckAtomicsCompareExchange(FunctionValidator& f, ParseNode* call, Type* type) if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Op::I32AtomicsCompareExchange, viewType)) + if (!WriteAtomicOperator(f, MozOp::I32AtomicsCompareExchange, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) @@ -4685,7 +4695,7 @@ CheckAtomicsExchange(FunctionValidator& f, ParseNode* call, Type* type) if (!CheckSharedArrayAtomicAccess(f, arrayArg, indexArg, &viewType)) return false; - if (!WriteAtomicOperator(f, Op::I32AtomicsExchange, viewType)) + if (!WriteAtomicOperator(f, MozOp::I32AtomicsExchange, viewType)) return false; if (!WriteArrayAccessFlags(f, viewType)) @@ -4901,7 +4911,7 @@ CheckFuncPtrCall(FunctionValidator& f, ParseNode* callNode, Type ret, Type* type if (!CheckFuncPtrTableAgainstExisting(f.m(), tableNode, name, Move(sig), mask, &tableIndex)) return false; - if (!f.writeCall(callNode, Op::OldCallIndirect)) + if (!f.writeCall(callNode, MozOp::OldCallIndirect)) return false; // Call signature @@ -5018,8 +5028,9 @@ CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltin Type* type) { unsigned arity = 0; - Op f32; - Op f64; + Op f32 = Op::Limit; + Op f64 = Op::Limit; + MozOp mozf64 = MozOp::Limit; switch (func) { case AsmJSMathBuiltin_imul: return CheckMathIMul(f, callNode, type); case AsmJSMathBuiltin_clz32: return CheckMathClz32(f, callNode, type); @@ -5028,18 +5039,18 @@ CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltin case AsmJSMathBuiltin_fround: return CheckMathFRound(f, callNode, type); case AsmJSMathBuiltin_min: return CheckMathMinMax(f, callNode, /* isMax = */ false, type); case AsmJSMathBuiltin_max: return CheckMathMinMax(f, callNode, /* isMax = */ true, type); - case AsmJSMathBuiltin_ceil: arity = 1; f64 = Op::F64Ceil; f32 = Op::F32Ceil; break; - case AsmJSMathBuiltin_floor: arity = 1; f64 = Op::F64Floor; f32 = Op::F32Floor; break; - case AsmJSMathBuiltin_sin: arity = 1; f64 = Op::F64Sin; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_cos: arity = 1; f64 = Op::F64Cos; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_tan: arity = 1; f64 = Op::F64Tan; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_asin: arity = 1; f64 = Op::F64Asin; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_acos: arity = 1; f64 = Op::F64Acos; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_atan: arity = 1; f64 = Op::F64Atan; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_exp: arity = 1; f64 = Op::F64Exp; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_log: arity = 1; f64 = Op::F64Log; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_pow: arity = 2; f64 = Op::F64Pow; f32 = Op::Unreachable; break; - case AsmJSMathBuiltin_atan2: arity = 2; f64 = Op::F64Atan2; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_ceil: arity = 1; f64 = Op::F64Ceil; f32 = Op::F32Ceil; break; + case AsmJSMathBuiltin_floor: arity = 1; f64 = Op::F64Floor; f32 = Op::F32Floor; break; + case AsmJSMathBuiltin_sin: arity = 1; mozf64 = MozOp::F64Sin; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_cos: arity = 1; mozf64 = MozOp::F64Cos; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_tan: arity = 1; mozf64 = MozOp::F64Tan; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_asin: arity = 1; mozf64 = MozOp::F64Asin; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_acos: arity = 1; mozf64 = MozOp::F64Acos; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_atan: arity = 1; mozf64 = MozOp::F64Atan; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_exp: arity = 1; mozf64 = MozOp::F64Exp; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_log: arity = 1; mozf64 = MozOp::F64Log; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_pow: arity = 2; mozf64 = MozOp::F64Pow; f32 = Op::Unreachable; break; + case AsmJSMathBuiltin_atan2: arity = 2; mozf64 = MozOp::F64Atan2; f32 = Op::Unreachable; break; default: MOZ_CRASH("unexpected mathBuiltin function"); } @@ -5075,8 +5086,13 @@ CheckMathBuiltinCall(FunctionValidator& f, ParseNode* callNode, AsmJSMathBuiltin } if (opIsDouble) { - if (!f.encoder().writeOp(f64)) - return false; + if (f64 != Op::Limit) { + if (!f.encoder().writeOp(f64)) + return false; + } else { + if (!f.encoder().writeOp(mozf64)) + return false; + } } else { if (!f.encoder().writeOp(f32)) return false; @@ -5933,7 +5949,7 @@ CheckNeg(FunctionValidator& f, ParseNode* expr, Type* type) if (operandType.isInt()) { *type = Type::Intish; - return f.encoder().writeOp(Op::I32Neg); + return f.encoder().writeOp(MozOp::I32Neg); } if (operandType.isMaybeDouble()) { @@ -5988,7 +6004,7 @@ CheckBitNot(FunctionValidator& f, ParseNode* neg, Type* type) if (!operandType.isIntish()) return f.failf(operand, "%s is not a subtype of intish", operandType.toChars()); - if (!f.encoder().writeOp(Op::I32BitNot)) + if (!f.encoder().writeOp(MozOp::I32BitNot)) return false; *type = Type::Signed; @@ -6223,7 +6239,9 @@ CheckDivOrMod(FunctionValidator& f, ParseNode* expr, Type* type) if (lhsType.isMaybeDouble() && rhsType.isMaybeDouble()) { *type = Type::Double; - return f.encoder().writeOp(expr->isKind(PNK_DIV) ? Op::F64Div : Op::F64Mod); + if (expr->isKind(PNK_DIV)) + return f.encoder().writeOp(Op::F64Div); + return f.encoder().writeOp(MozOp::F64Mod); } if (lhsType.isMaybeFloat() && rhsType.isMaybeFloat()) { diff --git a/js/src/wasm/WasmBaselineCompile.cpp b/js/src/wasm/WasmBaselineCompile.cpp index 8c0b1d30aa80..0484b108801b 100644 --- a/js/src/wasm/WasmBaselineCompile.cpp +++ b/js/src/wasm/WasmBaselineCompile.cpp @@ -5146,7 +5146,9 @@ BaseCompiler::sniffConditionalControlCmp(Cond compareOp, ValType operandType) { MOZ_ASSERT(latentOp_ == LatentOp::None, "Latent comparison state not properly reset"); - switch (iter_.peekOp()) { + OpBytes op; + iter_.peekOp(&op); + switch (op.b0) { case uint16_t(Op::Select): #ifdef JS_CODEGEN_X86 // On x86, with only 5 available registers, a latent i64 binary @@ -5169,7 +5171,9 @@ BaseCompiler::sniffConditionalControlEqz(ValType operandType) { MOZ_ASSERT(latentOp_ == LatentOp::None, "Latent comparison state not properly reset"); - switch (iter_.peekOp()) { + OpBytes op; + iter_.peekOp(&op); + switch (op.b0) { case uint16_t(Op::BrIf): case uint16_t(Op::Select): case uint16_t(Op::If): @@ -6885,11 +6889,11 @@ BaseCompiler::emitBody() overhead--; - uint16_t op; + OpBytes op; CHECK(iter_.readOp(&op)); // When debugEnabled_, every operator has breakpoint site but Op::End. - if (debugEnabled_ && op != (uint16_t)Op::End) { + if (debugEnabled_ && op.b0 != (uint16_t)Op::End) { // TODO sync only registers that can be clobbered by the exit // prologue/epilogue or disable these registers for use in // baseline compiler when debugEnabled_ is set. @@ -6898,7 +6902,7 @@ BaseCompiler::emitBody() insertBreakablePoint(CallSiteDesc::Breakpoint); } - switch (op) { + switch (op.b0) { case uint16_t(Op::End): if (!emitEnd()) return false; @@ -7366,7 +7370,7 @@ BaseCompiler::emitBody() CHECK_NEXT(emitCurrentMemory()); default: - return iter_.unrecognizedOpcode(op); + return iter_.unrecognizedOpcode(&op); } #undef CHECK diff --git a/js/src/wasm/WasmBinaryConstants.h b/js/src/wasm/WasmBinaryConstants.h index 4ecadcb18499..ebfcdf9bf638 100644 --- a/js/src/wasm/WasmBinaryConstants.h +++ b/js/src/wasm/WasmBinaryConstants.h @@ -306,12 +306,26 @@ enum class Op F32ReinterpretI32 = 0xbe, F64ReinterpretI64 = 0xbf, - // ------------------------------------------------------------------------ - // The rest of these operators are currently only emitted internally when - // compiling asm.js and are rejected by wasm validation. + AtomicPrefix = 0xfe, + MozPrefix = 0xff, - // asm.js-specific operators - TeeGlobal = 0xc8, + Limit = 0x100 +}; + +inline bool +IsPrefixByte(uint8_t b) { + return b >= uint8_t(Op::AtomicPrefix); +} + +enum class MozOp +{ + // ------------------------------------------------------------------------ + // These operators are emitted internally when compiling asm.js and are + // rejected by wasm validation. They are prefixed by MozPrefix. + + // asm.js-specific operators. They start at 1 so as to check for + // uninitialized (zeroed) storage. + TeeGlobal = 0x01, I32Min, I32Max, I32Neg, @@ -429,6 +443,20 @@ enum class Op Limit }; +struct OpBytes +{ + // The bytes of the opcode have 16-bit representations to allow for a full + // 256-value range plus a sentinel Limit value. + uint16_t b0; + uint16_t b1; + + explicit OpBytes(Op x) { + b0 = uint16_t(x); + b1 = 0; + } + OpBytes() = default; +}; + static const char NameSectionName[] = "name"; static const char SourceMappingURLSectionName[] = "sourceMappingURL"; diff --git a/js/src/wasm/WasmBinaryIterator.cpp b/js/src/wasm/WasmBinaryIterator.cpp index 6bc9b527e4e6..eb688c15b9c7 100644 --- a/js/src/wasm/WasmBinaryIterator.cpp +++ b/js/src/wasm/WasmBinaryIterator.cpp @@ -24,9 +24,9 @@ using namespace js::wasm; #ifdef DEBUG OpKind -wasm::Classify(Op op) +wasm::Classify(OpBytes op) { - switch (op) { + switch (Op(op.b0)) { case Op::Block: return OpKind::Block; case Op::Loop: @@ -43,20 +43,6 @@ wasm::Classify(Op op) return OpKind::F32; case Op::F64Const: return OpKind::F64; - case Op::I8x16Const: - return OpKind::I8x16; - case Op::I16x8Const: - return OpKind::I16x8; - case Op::I32x4Const: - return OpKind::I32x4; - case Op::B8x16Const: - return OpKind::B8x16; - case Op::B16x8Const: - return OpKind::B16x8; - case Op::B32x4Const: - return OpKind::B32x4; - case Op::F32x4Const: - return OpKind::F32x4; case Op::Br: return OpKind::Br; case Op::BrIf: @@ -85,31 +71,6 @@ wasm::Classify(Op op) case Op::F64Trunc: case Op::F64Nearest: case Op::F64Sqrt: - case Op::I32BitNot: - case Op::I32Abs: - case Op::F64Sin: - case Op::F64Cos: - case Op::F64Tan: - case Op::F64Asin: - case Op::F64Acos: - case Op::F64Atan: - case Op::F64Exp: - case Op::F64Log: - case Op::I32Neg: - case Op::I8x16neg: - case Op::I8x16not: - case Op::I16x8neg: - case Op::I16x8not: - case Op::I32x4neg: - case Op::I32x4not: - case Op::F32x4neg: - case Op::F32x4sqrt: - case Op::F32x4abs: - case Op::F32x4reciprocalApproximation: - case Op::F32x4reciprocalSqrtApproximation: - case Op::B8x16not: - case Op::B16x8not: - case Op::B32x4not: return OpKind::Unary; case Op::I32Add: case Op::I32Sub: @@ -155,54 +116,6 @@ wasm::Classify(Op op) case Op::F64Min: case Op::F64Max: case Op::F64CopySign: - case Op::I32Min: - case Op::I32Max: - case Op::F64Mod: - case Op::F64Pow: - case Op::F64Atan2: - case Op::I8x16add: - case Op::I8x16sub: - case Op::I8x16mul: - case Op::I8x16addSaturate: - case Op::I8x16subSaturate: - case Op::I8x16addSaturateU: - case Op::I8x16subSaturateU: - case Op::I8x16and: - case Op::I8x16or: - case Op::I8x16xor: - case Op::I16x8add: - case Op::I16x8sub: - case Op::I16x8mul: - case Op::I16x8addSaturate: - case Op::I16x8subSaturate: - case Op::I16x8addSaturateU: - case Op::I16x8subSaturateU: - case Op::I16x8and: - case Op::I16x8or: - case Op::I16x8xor: - case Op::I32x4add: - case Op::I32x4sub: - case Op::I32x4mul: - case Op::I32x4and: - case Op::I32x4or: - case Op::I32x4xor: - case Op::F32x4add: - case Op::F32x4sub: - case Op::F32x4mul: - case Op::F32x4div: - case Op::F32x4min: - case Op::F32x4max: - case Op::F32x4minNum: - case Op::F32x4maxNum: - case Op::B8x16and: - case Op::B8x16or: - case Op::B8x16xor: - case Op::B16x8and: - case Op::B16x8or: - case Op::B16x8xor: - case Op::B32x4and: - case Op::B32x4or: - case Op::B32x4xor: return OpKind::Binary; case Op::I32Eq: case Op::I32Ne: @@ -264,22 +177,6 @@ wasm::Classify(Op op) case Op::F64ConvertUI64: case Op::F64ReinterpretI64: case Op::F64PromoteF32: - case Op::I32x4fromFloat32x4: - case Op::I32x4fromFloat32x4U: - case Op::F32x4fromInt32x4: - case Op::F32x4fromUint32x4: - case Op::I32x4fromFloat32x4Bits: - case Op::I32x4fromInt8x16Bits: - case Op::I32x4fromInt16x8Bits: - case Op::I16x8fromInt8x16Bits: - case Op::I16x8fromInt32x4Bits: - case Op::I16x8fromFloat32x4Bits: - case Op::I8x16fromInt16x8Bits: - case Op::I8x16fromInt32x4Bits: - case Op::I8x16fromFloat32x4Bits: - case Op::F32x4fromInt8x16Bits: - case Op::F32x4fromInt16x8Bits: - case Op::F32x4fromInt32x4Bits: return OpKind::Conversion; case Op::I32Load8S: case Op::I32Load8U: @@ -295,16 +192,6 @@ wasm::Classify(Op op) case Op::I64Load: case Op::F32Load: case Op::F64Load: - case Op::I8x16load: - case Op::I16x8load: - case Op::I32x4load: - case Op::I32x4load1: - case Op::I32x4load2: - case Op::I32x4load3: - case Op::F32x4load: - case Op::F32x4load1: - case Op::F32x4load2: - case Op::F32x4load3: return OpKind::Load; case Op::I32Store8: case Op::I32Store16: @@ -316,28 +203,6 @@ wasm::Classify(Op op) case Op::F32Store: case Op::F64Store: return OpKind::Store; - case Op::I32TeeStore8: - case Op::I32TeeStore16: - case Op::I64TeeStore8: - case Op::I64TeeStore16: - case Op::I64TeeStore32: - case Op::I32TeeStore: - case Op::I64TeeStore: - case Op::F32TeeStore: - case Op::F64TeeStore: - case Op::F32TeeStoreF64: - case Op::F64TeeStoreF32: - case Op::I8x16store: - case Op::I16x8store: - case Op::I32x4store: - case Op::I32x4store1: - case Op::I32x4store2: - case Op::I32x4store3: - case Op::F32x4store: - case Op::F32x4store1: - case Op::F32x4store2: - case Op::F32x4store3: - return OpKind::TeeStore; case Op::Select: return OpKind::Select; case Op::GetLocal: @@ -350,14 +215,10 @@ wasm::Classify(Op op) return OpKind::GetGlobal; case Op::SetGlobal: return OpKind::SetGlobal; - case Op::TeeGlobal: - return OpKind::TeeGlobal; case Op::Call: return OpKind::Call; case Op::CallIndirect: return OpKind::CallIndirect; - case Op::OldCallIndirect: - return OpKind::OldCallIndirect; case Op::Return: case Op::Limit: // Accept Limit, for use in decoding the end of a function after the body. @@ -368,130 +229,285 @@ wasm::Classify(Op op) return OpKind::Else; case Op::End: return OpKind::End; - case Op::I32AtomicsLoad: - return OpKind::AtomicLoad; - case Op::I32AtomicsStore: - return OpKind::AtomicStore; - case Op::I32AtomicsBinOp: - return OpKind::AtomicBinOp; - case Op::I32AtomicsCompareExchange: - return OpKind::AtomicCompareExchange; - case Op::I32AtomicsExchange: - return OpKind::AtomicExchange; - case Op::I8x16extractLane: - case Op::I8x16extractLaneU: - case Op::I16x8extractLane: - case Op::I16x8extractLaneU: - case Op::I32x4extractLane: - case Op::F32x4extractLane: - case Op::B8x16extractLane: - case Op::B16x8extractLane: - case Op::B32x4extractLane: - return OpKind::ExtractLane; - case Op::I8x16replaceLane: - case Op::I16x8replaceLane: - case Op::I32x4replaceLane: - case Op::F32x4replaceLane: - case Op::B8x16replaceLane: - case Op::B16x8replaceLane: - case Op::B32x4replaceLane: - return OpKind::ReplaceLane; - case Op::I8x16swizzle: - case Op::I16x8swizzle: - case Op::I32x4swizzle: - case Op::F32x4swizzle: - return OpKind::Swizzle; - case Op::I8x16shuffle: - case Op::I16x8shuffle: - case Op::I32x4shuffle: - case Op::F32x4shuffle: - return OpKind::Shuffle; - case Op::I16x8check: - case Op::I16x8splat: - case Op::I32x4check: - case Op::I32x4splat: - case Op::I8x16check: - case Op::I8x16splat: - case Op::F32x4check: - case Op::F32x4splat: - case Op::B16x8check: - case Op::B16x8splat: - case Op::B32x4check: - case Op::B32x4splat: - case Op::B8x16check: - case Op::B8x16splat: - return OpKind::Splat; - case Op::I8x16select: - case Op::I16x8select: - case Op::I32x4select: - case Op::F32x4select: - return OpKind::SimdSelect; - case Op::I8x16Constructor: - case Op::I16x8Constructor: - case Op::I32x4Constructor: - case Op::F32x4Constructor: - case Op::B8x16Constructor: - case Op::B16x8Constructor: - case Op::B32x4Constructor: - return OpKind::SimdCtor; - case Op::B8x16allTrue: - case Op::B8x16anyTrue: - case Op::B16x8allTrue: - case Op::B16x8anyTrue: - case Op::B32x4allTrue: - case Op::B32x4anyTrue: - return OpKind::SimdBooleanReduction; - case Op::I8x16shiftLeftByScalar: - case Op::I8x16shiftRightByScalar: - case Op::I8x16shiftRightByScalarU: - case Op::I16x8shiftLeftByScalar: - case Op::I16x8shiftRightByScalar: - case Op::I16x8shiftRightByScalarU: - case Op::I32x4shiftLeftByScalar: - case Op::I32x4shiftRightByScalar: - case Op::I32x4shiftRightByScalarU: - return OpKind::SimdShiftByScalar; - case Op::I8x16equal: - case Op::I8x16notEqual: - case Op::I8x16greaterThan: - case Op::I8x16greaterThanOrEqual: - case Op::I8x16lessThan: - case Op::I8x16lessThanOrEqual: - case Op::I8x16greaterThanU: - case Op::I8x16greaterThanOrEqualU: - case Op::I8x16lessThanU: - case Op::I8x16lessThanOrEqualU: - case Op::I16x8equal: - case Op::I16x8notEqual: - case Op::I16x8greaterThan: - case Op::I16x8greaterThanOrEqual: - case Op::I16x8lessThan: - case Op::I16x8lessThanOrEqual: - case Op::I16x8greaterThanU: - case Op::I16x8greaterThanOrEqualU: - case Op::I16x8lessThanU: - case Op::I16x8lessThanOrEqualU: - case Op::I32x4equal: - case Op::I32x4notEqual: - case Op::I32x4greaterThan: - case Op::I32x4greaterThanOrEqual: - case Op::I32x4lessThan: - case Op::I32x4lessThanOrEqual: - case Op::I32x4greaterThanU: - case Op::I32x4greaterThanOrEqualU: - case Op::I32x4lessThanU: - case Op::I32x4lessThanOrEqualU: - case Op::F32x4equal: - case Op::F32x4notEqual: - case Op::F32x4greaterThan: - case Op::F32x4greaterThanOrEqual: - case Op::F32x4lessThan: - case Op::F32x4lessThanOrEqual: - return OpKind::SimdComparison; case Op::CurrentMemory: return OpKind::CurrentMemory; case Op::GrowMemory: return OpKind::GrowMemory; + case Op::AtomicPrefix: + break; + case Op::MozPrefix: { + switch (MozOp(op.b1)) { + case MozOp::Limit: + // Reject Limit for the MozPrefix encoding + break; + case MozOp::TeeGlobal: + return OpKind::TeeGlobal; + case MozOp::I8x16Const: + return OpKind::I8x16; + case MozOp::I16x8Const: + return OpKind::I16x8; + case MozOp::I32x4Const: + return OpKind::I32x4; + case MozOp::B8x16Const: + return OpKind::B8x16; + case MozOp::B16x8Const: + return OpKind::B16x8; + case MozOp::B32x4Const: + return OpKind::B32x4; + case MozOp::F32x4Const: + return OpKind::F32x4; + case MozOp::I32BitNot: + case MozOp::I32Abs: + case MozOp::I32Neg: + case MozOp::I8x16neg: + case MozOp::I8x16not: + case MozOp::I16x8neg: + case MozOp::I16x8not: + case MozOp::I32x4neg: + case MozOp::I32x4not: + case MozOp::F32x4neg: + case MozOp::F32x4sqrt: + case MozOp::F32x4abs: + case MozOp::F32x4reciprocalApproximation: + case MozOp::F32x4reciprocalSqrtApproximation: + case MozOp::B8x16not: + case MozOp::B16x8not: + case MozOp::B32x4not: + return OpKind::Unary; + case MozOp::I32Min: + case MozOp::I32Max: + case MozOp::F64Mod: + case MozOp::F64Pow: + case MozOp::F64Atan2: + case MozOp::I8x16add: + case MozOp::I8x16sub: + case MozOp::I8x16mul: + case MozOp::I8x16addSaturate: + case MozOp::I8x16subSaturate: + case MozOp::I8x16addSaturateU: + case MozOp::I8x16subSaturateU: + case MozOp::I8x16and: + case MozOp::I8x16or: + case MozOp::I8x16xor: + case MozOp::I16x8add: + case MozOp::I16x8sub: + case MozOp::I16x8mul: + case MozOp::I16x8addSaturate: + case MozOp::I16x8subSaturate: + case MozOp::I16x8addSaturateU: + case MozOp::I16x8subSaturateU: + case MozOp::I16x8and: + case MozOp::I16x8or: + case MozOp::I16x8xor: + case MozOp::I32x4add: + case MozOp::I32x4sub: + case MozOp::I32x4mul: + case MozOp::I32x4and: + case MozOp::I32x4or: + case MozOp::I32x4xor: + case MozOp::F32x4add: + case MozOp::F32x4sub: + case MozOp::F32x4mul: + case MozOp::F32x4div: + case MozOp::F32x4min: + case MozOp::F32x4max: + case MozOp::F32x4minNum: + case MozOp::F32x4maxNum: + case MozOp::B8x16and: + case MozOp::B8x16or: + case MozOp::B8x16xor: + case MozOp::B16x8and: + case MozOp::B16x8or: + case MozOp::B16x8xor: + case MozOp::B32x4and: + case MozOp::B32x4or: + case MozOp::B32x4xor: + return OpKind::Binary; + case MozOp::F64Sin: + case MozOp::F64Cos: + case MozOp::F64Tan: + case MozOp::F64Asin: + case MozOp::F64Acos: + case MozOp::F64Atan: + case MozOp::F64Exp: + case MozOp::F64Log: + return OpKind::Unary; + case MozOp::I32TeeStore8: + case MozOp::I32TeeStore16: + case MozOp::I64TeeStore8: + case MozOp::I64TeeStore16: + case MozOp::I64TeeStore32: + case MozOp::I32TeeStore: + case MozOp::I64TeeStore: + case MozOp::F32TeeStore: + case MozOp::F64TeeStore: + case MozOp::F32TeeStoreF64: + case MozOp::F64TeeStoreF32: + return OpKind::TeeStore; + case MozOp::I32x4fromFloat32x4: + case MozOp::I32x4fromFloat32x4U: + case MozOp::F32x4fromInt32x4: + case MozOp::F32x4fromUint32x4: + case MozOp::I32x4fromFloat32x4Bits: + case MozOp::I32x4fromInt8x16Bits: + case MozOp::I32x4fromInt16x8Bits: + case MozOp::I16x8fromInt8x16Bits: + case MozOp::I16x8fromInt32x4Bits: + case MozOp::I16x8fromFloat32x4Bits: + case MozOp::I8x16fromInt16x8Bits: + case MozOp::I8x16fromInt32x4Bits: + case MozOp::I8x16fromFloat32x4Bits: + case MozOp::F32x4fromInt8x16Bits: + case MozOp::F32x4fromInt16x8Bits: + case MozOp::F32x4fromInt32x4Bits: + return OpKind::Conversion; + case MozOp::I8x16load: + case MozOp::I16x8load: + case MozOp::I32x4load: + case MozOp::I32x4load1: + case MozOp::I32x4load2: + case MozOp::I32x4load3: + case MozOp::F32x4load: + case MozOp::F32x4load1: + case MozOp::F32x4load2: + case MozOp::F32x4load3: + return OpKind::Load; + case MozOp::I8x16store: + case MozOp::I16x8store: + case MozOp::I32x4store: + case MozOp::I32x4store1: + case MozOp::I32x4store2: + case MozOp::I32x4store3: + case MozOp::F32x4store: + case MozOp::F32x4store1: + case MozOp::F32x4store2: + case MozOp::F32x4store3: + return OpKind::TeeStore; + case MozOp::OldCallIndirect: + return OpKind::OldCallIndirect; + case MozOp::I32AtomicsLoad: + return OpKind::AtomicLoad; + case MozOp::I32AtomicsStore: + return OpKind::AtomicStore; + case MozOp::I32AtomicsBinOp: + return OpKind::AtomicBinOp; + case MozOp::I32AtomicsCompareExchange: + return OpKind::AtomicCompareExchange; + case MozOp::I32AtomicsExchange: + return OpKind::AtomicExchange; + case MozOp::I8x16extractLane: + case MozOp::I8x16extractLaneU: + case MozOp::I16x8extractLane: + case MozOp::I16x8extractLaneU: + case MozOp::I32x4extractLane: + case MozOp::F32x4extractLane: + case MozOp::B8x16extractLane: + case MozOp::B16x8extractLane: + case MozOp::B32x4extractLane: + return OpKind::ExtractLane; + case MozOp::I8x16replaceLane: + case MozOp::I16x8replaceLane: + case MozOp::I32x4replaceLane: + case MozOp::F32x4replaceLane: + case MozOp::B8x16replaceLane: + case MozOp::B16x8replaceLane: + case MozOp::B32x4replaceLane: + return OpKind::ReplaceLane; + case MozOp::I8x16swizzle: + case MozOp::I16x8swizzle: + case MozOp::I32x4swizzle: + case MozOp::F32x4swizzle: + return OpKind::Swizzle; + case MozOp::I8x16shuffle: + case MozOp::I16x8shuffle: + case MozOp::I32x4shuffle: + case MozOp::F32x4shuffle: + return OpKind::Shuffle; + case MozOp::I16x8check: + case MozOp::I16x8splat: + case MozOp::I32x4check: + case MozOp::I32x4splat: + case MozOp::I8x16check: + case MozOp::I8x16splat: + case MozOp::F32x4check: + case MozOp::F32x4splat: + case MozOp::B16x8check: + case MozOp::B16x8splat: + case MozOp::B32x4check: + case MozOp::B32x4splat: + case MozOp::B8x16check: + case MozOp::B8x16splat: + return OpKind::Splat; + case MozOp::I8x16select: + case MozOp::I16x8select: + case MozOp::I32x4select: + case MozOp::F32x4select: + return OpKind::SimdSelect; + case MozOp::I8x16Constructor: + case MozOp::I16x8Constructor: + case MozOp::I32x4Constructor: + case MozOp::F32x4Constructor: + case MozOp::B8x16Constructor: + case MozOp::B16x8Constructor: + case MozOp::B32x4Constructor: + return OpKind::SimdCtor; + case MozOp::B8x16allTrue: + case MozOp::B8x16anyTrue: + case MozOp::B16x8allTrue: + case MozOp::B16x8anyTrue: + case MozOp::B32x4allTrue: + case MozOp::B32x4anyTrue: + return OpKind::SimdBooleanReduction; + case MozOp::I8x16shiftLeftByScalar: + case MozOp::I8x16shiftRightByScalar: + case MozOp::I8x16shiftRightByScalarU: + case MozOp::I16x8shiftLeftByScalar: + case MozOp::I16x8shiftRightByScalar: + case MozOp::I16x8shiftRightByScalarU: + case MozOp::I32x4shiftLeftByScalar: + case MozOp::I32x4shiftRightByScalar: + case MozOp::I32x4shiftRightByScalarU: + return OpKind::SimdShiftByScalar; + case MozOp::I8x16equal: + case MozOp::I8x16notEqual: + case MozOp::I8x16greaterThan: + case MozOp::I8x16greaterThanOrEqual: + case MozOp::I8x16lessThan: + case MozOp::I8x16lessThanOrEqual: + case MozOp::I8x16greaterThanU: + case MozOp::I8x16greaterThanOrEqualU: + case MozOp::I8x16lessThanU: + case MozOp::I8x16lessThanOrEqualU: + case MozOp::I16x8equal: + case MozOp::I16x8notEqual: + case MozOp::I16x8greaterThan: + case MozOp::I16x8greaterThanOrEqual: + case MozOp::I16x8lessThan: + case MozOp::I16x8lessThanOrEqual: + case MozOp::I16x8greaterThanU: + case MozOp::I16x8greaterThanOrEqualU: + case MozOp::I16x8lessThanU: + case MozOp::I16x8lessThanOrEqualU: + case MozOp::I32x4equal: + case MozOp::I32x4notEqual: + case MozOp::I32x4greaterThan: + case MozOp::I32x4greaterThanOrEqual: + case MozOp::I32x4lessThan: + case MozOp::I32x4lessThanOrEqual: + case MozOp::I32x4greaterThanU: + case MozOp::I32x4greaterThanOrEqualU: + case MozOp::I32x4lessThanU: + case MozOp::I32x4lessThanOrEqualU: + case MozOp::F32x4equal: + case MozOp::F32x4notEqual: + case MozOp::F32x4greaterThan: + case MozOp::F32x4greaterThanOrEqual: + case MozOp::F32x4lessThan: + case MozOp::F32x4lessThanOrEqual: + return OpKind::SimdComparison; + } + break; + } } MOZ_MAKE_COMPILER_ASSUME_IS_UNREACHABLE("unimplemented opcode"); } diff --git a/js/src/wasm/WasmBinaryIterator.h b/js/src/wasm/WasmBinaryIterator.h index d1666b7878cd..04f9d7e99cef 100644 --- a/js/src/wasm/WasmBinaryIterator.h +++ b/js/src/wasm/WasmBinaryIterator.h @@ -158,7 +158,7 @@ enum class OpKind { // Return the OpKind for a given Op. This is used for sanity-checking that // API users use the correct read function for a given Op. OpKind -Classify(Op op); +Classify(OpBytes op); #endif // Common fields for linear memory access. @@ -310,7 +310,9 @@ class MOZ_STACK_CLASS OpIter : private Policy Vector, 8, SystemAllocPolicy> valueStack_; Vector, 8, SystemAllocPolicy> controlStack_; - DebugOnly op_; +#ifdef DEBUG + OpBytes op_; +#endif size_t offsetOfLastReadOp_; MOZ_MUST_USE bool readFixedU8(uint8_t* out) { @@ -426,9 +428,15 @@ class MOZ_STACK_CLASS OpIter : private Policy public: typedef Vector ValueVector; +#ifdef DEBUG explicit OpIter(const ModuleEnvironment& env, Decoder& decoder) - : d_(decoder), env_(env), op_(Op::Limit), offsetOfLastReadOp_(0) + : d_(decoder), env_(env), op_(OpBytes(Op::Limit)), offsetOfLastReadOp_(0) {} +#else + explicit OpIter(const ModuleEnvironment& env, Decoder& decoder) + : d_(decoder), env_(env), offsetOfLastReadOp_(0) + {} +#endif // Return the decoding byte offset. uint32_t currentOffset() const { @@ -459,7 +467,7 @@ class MOZ_STACK_CLASS OpIter : private Policy MOZ_MUST_USE bool fail(const char* msg) MOZ_COLD; // Report an unrecognized opcode. - MOZ_MUST_USE bool unrecognizedOpcode(uint32_t expr) MOZ_COLD; + MOZ_MUST_USE bool unrecognizedOpcode(const OpBytes* expr) MOZ_COLD; // Return whether the innermost block has a polymorphic base of its stack. // Ideally this accessor would be removed; consider using something else. @@ -470,7 +478,7 @@ class MOZ_STACK_CLASS OpIter : private Policy // ------------------------------------------------------------------------ // Decoding and validation interface. - MOZ_MUST_USE bool readOp(uint16_t* op); + MOZ_MUST_USE bool readOp(OpBytes* op); MOZ_MUST_USE bool readFunctionStart(ExprType ret); MOZ_MUST_USE bool readFunctionEnd(const uint8_t* bodyEnd); MOZ_MUST_USE bool readReturn(Value* value); @@ -559,8 +567,8 @@ class MOZ_STACK_CLASS OpIter : private Policy // At a location where readOp is allowed, peek at the next opcode // without consuming it or updating any internal state. - // Never fails: returns uint16_t(Op::Limit) if it can't read. - uint16_t peekOp(); + // Never fails: returns uint16_t(Op::Limit) in op->b0 if it can't read. + void peekOp(OpBytes* op); // ------------------------------------------------------------------------ // Stack management. @@ -599,9 +607,10 @@ class MOZ_STACK_CLASS OpIter : private Policy template inline bool -OpIter::unrecognizedOpcode(uint32_t expr) +OpIter::unrecognizedOpcode(const OpBytes* expr) { - UniqueChars error(JS_smprintf("unrecognized opcode: %x", expr)); + UniqueChars error(JS_smprintf("unrecognized opcode: %x %x", expr->b0, + IsPrefixByte(expr->b0) ? expr->b1 : 0)); if (!error) return false; @@ -830,7 +839,7 @@ OpIter::readBlockType(ExprType* type) template inline bool -OpIter::readOp(uint16_t* op) +OpIter::readOp(OpBytes* op) { MOZ_ASSERT(!controlStack_.empty()); @@ -839,24 +848,23 @@ OpIter::readOp(uint16_t* op) if (MOZ_UNLIKELY(!d_.readOp(op))) return fail("unable to read opcode"); - op_ = Op(*op); // debug-only +#ifdef DEBUG + op_ = *op; +#endif return true; } template -inline uint16_t -OpIter::peekOp() +inline void +OpIter::peekOp(OpBytes* op) { const uint8_t* pos = d_.currentPosition(); - uint16_t op; - if (MOZ_UNLIKELY(!d_.readOp(&op))) - op = uint16_t(Op::Limit); + if (MOZ_UNLIKELY(!d_.readOp(op))) + op->b0 = uint16_t(Op::Limit); d_.rollbackPosition(pos); - - return op; } template @@ -865,7 +873,7 @@ OpIter::readFunctionStart(ExprType ret) { MOZ_ASSERT(valueStack_.empty()); MOZ_ASSERT(controlStack_.empty()); - MOZ_ASSERT(Op(op_) == Op::Limit); + MOZ_ASSERT(op_.b0 == uint16_t(Op::Limit)); return pushControl(LabelKind::Block, ret); } @@ -880,7 +888,9 @@ OpIter::readFunctionEnd(const uint8_t* bodyEnd) if (!controlStack_.empty()) return fail("unbalanced function body control flow"); - op_ = Op::Limit; +#ifdef DEBUG + op_ = OpBytes(Op::Limit); +#endif valueStack_.clear(); return true; } diff --git a/js/src/wasm/WasmBinaryToAST.cpp b/js/src/wasm/WasmBinaryToAST.cpp index 161ea039f8f1..f3ebbc42c67e 100644 --- a/js/src/wasm/WasmBinaryToAST.cpp +++ b/js/src/wasm/WasmBinaryToAST.cpp @@ -966,12 +966,12 @@ static bool AstDecodeExpr(AstDecodeContext& c) { uint32_t exprOffset = c.iter().currentOffset(); - uint16_t op; + OpBytes op; if (!c.iter().readOp(&op)) return false; AstExpr* tmp; - switch (op) { + switch (op.b0) { case uint16_t(Op::Nop): if (!AstDecodeNop(c)) return false; @@ -1040,7 +1040,7 @@ AstDecodeExpr(AstDecodeContext& c) break; case uint16_t(Op::Block): case uint16_t(Op::Loop): - if (!AstDecodeBlock(c, Op(op))) + if (!AstDecodeBlock(c, Op(op.b0))) return false; break; case uint16_t(Op::If): @@ -1058,13 +1058,13 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::I32Clz): case uint16_t(Op::I32Ctz): case uint16_t(Op::I32Popcnt): - if (!AstDecodeUnary(c, ValType::I32, Op(op))) + if (!AstDecodeUnary(c, ValType::I32, Op(op.b0))) return false; break; case uint16_t(Op::I64Clz): case uint16_t(Op::I64Ctz): case uint16_t(Op::I64Popcnt): - if (!AstDecodeUnary(c, ValType::I64, Op(op))) + if (!AstDecodeUnary(c, ValType::I64, Op(op.b0))) return false; break; case uint16_t(Op::F32Abs): @@ -1074,7 +1074,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::F32Sqrt): case uint16_t(Op::F32Trunc): case uint16_t(Op::F32Nearest): - if (!AstDecodeUnary(c, ValType::F32, Op(op))) + if (!AstDecodeUnary(c, ValType::F32, Op(op.b0))) return false; break; case uint16_t(Op::F64Abs): @@ -1084,7 +1084,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::F64Sqrt): case uint16_t(Op::F64Trunc): case uint16_t(Op::F64Nearest): - if (!AstDecodeUnary(c, ValType::F64, Op(op))) + if (!AstDecodeUnary(c, ValType::F64, Op(op.b0))) return false; break; case uint16_t(Op::I32Add): @@ -1102,7 +1102,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::I32ShrU): case uint16_t(Op::I32Rotl): case uint16_t(Op::I32Rotr): - if (!AstDecodeBinary(c, ValType::I32, Op(op))) + if (!AstDecodeBinary(c, ValType::I32, Op(op.b0))) return false; break; case uint16_t(Op::I64Add): @@ -1120,7 +1120,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::I64ShrU): case uint16_t(Op::I64Rotl): case uint16_t(Op::I64Rotr): - if (!AstDecodeBinary(c, ValType::I64, Op(op))) + if (!AstDecodeBinary(c, ValType::I64, Op(op.b0))) return false; break; case uint16_t(Op::F32Add): @@ -1130,7 +1130,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::F32Min): case uint16_t(Op::F32Max): case uint16_t(Op::F32CopySign): - if (!AstDecodeBinary(c, ValType::F32, Op(op))) + if (!AstDecodeBinary(c, ValType::F32, Op(op.b0))) return false; break; case uint16_t(Op::F64Add): @@ -1140,7 +1140,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::F64Min): case uint16_t(Op::F64Max): case uint16_t(Op::F64CopySign): - if (!AstDecodeBinary(c, ValType::F64, Op(op))) + if (!AstDecodeBinary(c, ValType::F64, Op(op.b0))) return false; break; case uint16_t(Op::I32Eq): @@ -1153,7 +1153,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::I32GtU): case uint16_t(Op::I32GeS): case uint16_t(Op::I32GeU): - if (!AstDecodeComparison(c, ValType::I32, Op(op))) + if (!AstDecodeComparison(c, ValType::I32, Op(op.b0))) return false; break; case uint16_t(Op::I64Eq): @@ -1166,7 +1166,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::I64GtU): case uint16_t(Op::I64GeS): case uint16_t(Op::I64GeU): - if (!AstDecodeComparison(c, ValType::I64, Op(op))) + if (!AstDecodeComparison(c, ValType::I64, Op(op.b0))) return false; break; case uint16_t(Op::F32Eq): @@ -1175,7 +1175,7 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::F32Le): case uint16_t(Op::F32Gt): case uint16_t(Op::F32Ge): - if (!AstDecodeComparison(c, ValType::F32, Op(op))) + if (!AstDecodeComparison(c, ValType::F32, Op(op.b0))) return false; break; case uint16_t(Op::F64Eq): @@ -1184,150 +1184,150 @@ AstDecodeExpr(AstDecodeContext& c) case uint16_t(Op::F64Le): case uint16_t(Op::F64Gt): case uint16_t(Op::F64Ge): - if (!AstDecodeComparison(c, ValType::F64, Op(op))) + if (!AstDecodeComparison(c, ValType::F64, Op(op.b0))) return false; break; case uint16_t(Op::I32Eqz): - if (!AstDecodeConversion(c, ValType::I32, ValType::I32, Op(op))) + if (!AstDecodeConversion(c, ValType::I32, ValType::I32, Op(op.b0))) return false; break; case uint16_t(Op::I64Eqz): case uint16_t(Op::I32WrapI64): - if (!AstDecodeConversion(c, ValType::I64, ValType::I32, Op(op))) + if (!AstDecodeConversion(c, ValType::I64, ValType::I32, Op(op.b0))) return false; break; case uint16_t(Op::I32TruncSF32): case uint16_t(Op::I32TruncUF32): case uint16_t(Op::I32ReinterpretF32): - if (!AstDecodeConversion(c, ValType::F32, ValType::I32, Op(op))) + if (!AstDecodeConversion(c, ValType::F32, ValType::I32, Op(op.b0))) return false; break; case uint16_t(Op::I32TruncSF64): case uint16_t(Op::I32TruncUF64): - if (!AstDecodeConversion(c, ValType::F64, ValType::I32, Op(op))) + if (!AstDecodeConversion(c, ValType::F64, ValType::I32, Op(op.b0))) return false; break; case uint16_t(Op::I64ExtendSI32): case uint16_t(Op::I64ExtendUI32): - if (!AstDecodeConversion(c, ValType::I32, ValType::I64, Op(op))) + if (!AstDecodeConversion(c, ValType::I32, ValType::I64, Op(op.b0))) return false; break; case uint16_t(Op::I64TruncSF32): case uint16_t(Op::I64TruncUF32): - if (!AstDecodeConversion(c, ValType::F32, ValType::I64, Op(op))) + if (!AstDecodeConversion(c, ValType::F32, ValType::I64, Op(op.b0))) return false; break; case uint16_t(Op::I64TruncSF64): case uint16_t(Op::I64TruncUF64): case uint16_t(Op::I64ReinterpretF64): - if (!AstDecodeConversion(c, ValType::F64, ValType::I64, Op(op))) + if (!AstDecodeConversion(c, ValType::F64, ValType::I64, Op(op.b0))) return false; break; case uint16_t(Op::F32ConvertSI32): case uint16_t(Op::F32ConvertUI32): case uint16_t(Op::F32ReinterpretI32): - if (!AstDecodeConversion(c, ValType::I32, ValType::F32, Op(op))) + if (!AstDecodeConversion(c, ValType::I32, ValType::F32, Op(op.b0))) return false; break; case uint16_t(Op::F32ConvertSI64): case uint16_t(Op::F32ConvertUI64): - if (!AstDecodeConversion(c, ValType::I64, ValType::F32, Op(op))) + if (!AstDecodeConversion(c, ValType::I64, ValType::F32, Op(op.b0))) return false; break; case uint16_t(Op::F32DemoteF64): - if (!AstDecodeConversion(c, ValType::F64, ValType::F32, Op(op))) + if (!AstDecodeConversion(c, ValType::F64, ValType::F32, Op(op.b0))) return false; break; case uint16_t(Op::F64ConvertSI32): case uint16_t(Op::F64ConvertUI32): - if (!AstDecodeConversion(c, ValType::I32, ValType::F64, Op(op))) + if (!AstDecodeConversion(c, ValType::I32, ValType::F64, Op(op.b0))) return false; break; case uint16_t(Op::F64ConvertSI64): case uint16_t(Op::F64ConvertUI64): case uint16_t(Op::F64ReinterpretI64): - if (!AstDecodeConversion(c, ValType::I64, ValType::F64, Op(op))) + if (!AstDecodeConversion(c, ValType::I64, ValType::F64, Op(op.b0))) return false; break; case uint16_t(Op::F64PromoteF32): - if (!AstDecodeConversion(c, ValType::F32, ValType::F64, Op(op))) + if (!AstDecodeConversion(c, ValType::F32, ValType::F64, Op(op.b0))) return false; break; case uint16_t(Op::I32Load8S): case uint16_t(Op::I32Load8U): - if (!AstDecodeLoad(c, ValType::I32, 1, Op(op))) + if (!AstDecodeLoad(c, ValType::I32, 1, Op(op.b0))) return false; break; case uint16_t(Op::I32Load16S): case uint16_t(Op::I32Load16U): - if (!AstDecodeLoad(c, ValType::I32, 2, Op(op))) + if (!AstDecodeLoad(c, ValType::I32, 2, Op(op.b0))) return false; break; case uint16_t(Op::I32Load): - if (!AstDecodeLoad(c, ValType::I32, 4, Op(op))) + if (!AstDecodeLoad(c, ValType::I32, 4, Op(op.b0))) return false; break; case uint16_t(Op::I64Load8S): case uint16_t(Op::I64Load8U): - if (!AstDecodeLoad(c, ValType::I64, 1, Op(op))) + if (!AstDecodeLoad(c, ValType::I64, 1, Op(op.b0))) return false; break; case uint16_t(Op::I64Load16S): case uint16_t(Op::I64Load16U): - if (!AstDecodeLoad(c, ValType::I64, 2, Op(op))) + if (!AstDecodeLoad(c, ValType::I64, 2, Op(op.b0))) return false; break; case uint16_t(Op::I64Load32S): case uint16_t(Op::I64Load32U): - if (!AstDecodeLoad(c, ValType::I64, 4, Op(op))) + if (!AstDecodeLoad(c, ValType::I64, 4, Op(op.b0))) return false; break; case uint16_t(Op::I64Load): - if (!AstDecodeLoad(c, ValType::I64, 8, Op(op))) + if (!AstDecodeLoad(c, ValType::I64, 8, Op(op.b0))) return false; break; case uint16_t(Op::F32Load): - if (!AstDecodeLoad(c, ValType::F32, 4, Op(op))) + if (!AstDecodeLoad(c, ValType::F32, 4, Op(op.b0))) return false; break; case uint16_t(Op::F64Load): - if (!AstDecodeLoad(c, ValType::F64, 8, Op(op))) + if (!AstDecodeLoad(c, ValType::F64, 8, Op(op.b0))) return false; break; case uint16_t(Op::I32Store8): - if (!AstDecodeStore(c, ValType::I32, 1, Op(op))) + if (!AstDecodeStore(c, ValType::I32, 1, Op(op.b0))) return false; break; case uint16_t(Op::I32Store16): - if (!AstDecodeStore(c, ValType::I32, 2, Op(op))) + if (!AstDecodeStore(c, ValType::I32, 2, Op(op.b0))) return false; break; case uint16_t(Op::I32Store): - if (!AstDecodeStore(c, ValType::I32, 4, Op(op))) + if (!AstDecodeStore(c, ValType::I32, 4, Op(op.b0))) return false; break; case uint16_t(Op::I64Store8): - if (!AstDecodeStore(c, ValType::I64, 1, Op(op))) + if (!AstDecodeStore(c, ValType::I64, 1, Op(op.b0))) return false; break; case uint16_t(Op::I64Store16): - if (!AstDecodeStore(c, ValType::I64, 2, Op(op))) + if (!AstDecodeStore(c, ValType::I64, 2, Op(op.b0))) return false; break; case uint16_t(Op::I64Store32): - if (!AstDecodeStore(c, ValType::I64, 4, Op(op))) + if (!AstDecodeStore(c, ValType::I64, 4, Op(op.b0))) return false; break; case uint16_t(Op::I64Store): - if (!AstDecodeStore(c, ValType::I64, 8, Op(op))) + if (!AstDecodeStore(c, ValType::I64, 8, Op(op.b0))) return false; break; case uint16_t(Op::F32Store): - if (!AstDecodeStore(c, ValType::F32, 4, Op(op))) + if (!AstDecodeStore(c, ValType::F32, 4, Op(op.b0))) return false; break; case uint16_t(Op::F64Store): - if (!AstDecodeStore(c, ValType::F64, 8, Op(op))) + if (!AstDecodeStore(c, ValType::F64, 8, Op(op.b0))) return false; break; case uint16_t(Op::CurrentMemory): @@ -1348,7 +1348,7 @@ AstDecodeExpr(AstDecodeContext& c) break; case uint16_t(Op::Br): case uint16_t(Op::BrIf): - if (!AstDecodeBranch(c, Op(op))) + if (!AstDecodeBranch(c, Op(op.b0))) return false; break; case uint16_t(Op::BrTable): @@ -1369,7 +1369,7 @@ AstDecodeExpr(AstDecodeContext& c) return false; break; default: - return c.iter().unrecognizedOpcode(op); + return c.iter().unrecognizedOpcode(&op); } AstExpr* lastExpr = c.top().expr; diff --git a/js/src/wasm/WasmIonCompile.cpp b/js/src/wasm/WasmIonCompile.cpp index 89c638662194..317c5f4e42ea 100644 --- a/js/src/wasm/WasmIonCompile.cpp +++ b/js/src/wasm/WasmIonCompile.cpp @@ -3227,7 +3227,7 @@ EmitBodyExprs(FunctionCompiler& f) #define CHECK_ASMJS(c) \ if (!f.env().isAsmJS()) \ - return f.iter().unrecognizedOpcode(op); \ + return f.iter().unrecognizedOpcode(&op); \ if (!(c)) \ return false; \ break @@ -3236,11 +3236,11 @@ EmitBodyExprs(FunctionCompiler& f) if (!f.mirGen().ensureBallast()) return false; - uint16_t op; + OpBytes op; if (!f.iter().readOp(&op)) return false; - switch (op) { + switch (op.b0) { case uint16_t(Op::End): if (!EmitEnd(f)) return false; @@ -3447,10 +3447,10 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitMul(f, ValType::I32, MIRType::Int32)); case uint16_t(Op::I32DivS): case uint16_t(Op::I32DivU): - CHECK(EmitDiv(f, ValType::I32, MIRType::Int32, Op(op) == Op::I32DivU)); + CHECK(EmitDiv(f, ValType::I32, MIRType::Int32, Op(op.b0) == Op::I32DivU)); case uint16_t(Op::I32RemS): case uint16_t(Op::I32RemU): - CHECK(EmitRem(f, ValType::I32, MIRType::Int32, Op(op) == Op::I32RemU)); + CHECK(EmitRem(f, ValType::I32, MIRType::Int32, Op(op.b0) == Op::I32RemU)); case uint16_t(Op::I32And): CHECK(EmitBitwise(f, ValType::I32, MIRType::Int32)); case uint16_t(Op::I32Or): @@ -3465,7 +3465,7 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitBitwise(f, ValType::I32, MIRType::Int32)); case uint16_t(Op::I32Rotl): case uint16_t(Op::I32Rotr): - CHECK(EmitRotate(f, ValType::I32, Op(op) == Op::I32Rotl)); + CHECK(EmitRotate(f, ValType::I32, Op(op.b0) == Op::I32Rotl)); case uint16_t(Op::I64Clz): CHECK(EmitUnaryWithType(f, ValType::I64, MIRType::Int64)); case uint16_t(Op::I64Ctz): @@ -3480,10 +3480,10 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitMul(f, ValType::I64, MIRType::Int64)); case uint16_t(Op::I64DivS): case uint16_t(Op::I64DivU): - CHECK(EmitDiv(f, ValType::I64, MIRType::Int64, Op(op) == Op::I64DivU)); + CHECK(EmitDiv(f, ValType::I64, MIRType::Int64, Op(op.b0) == Op::I64DivU)); case uint16_t(Op::I64RemS): case uint16_t(Op::I64RemU): - CHECK(EmitRem(f, ValType::I64, MIRType::Int64, Op(op) == Op::I64RemU)); + CHECK(EmitRem(f, ValType::I64, MIRType::Int64, Op(op.b0) == Op::I64RemU)); case uint16_t(Op::I64And): CHECK(EmitBitwise(f, ValType::I64, MIRType::Int64)); case uint16_t(Op::I64Or): @@ -3498,7 +3498,7 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitBitwise(f, ValType::I64, MIRType::Int64)); case uint16_t(Op::I64Rotl): case uint16_t(Op::I64Rotr): - CHECK(EmitRotate(f, ValType::I64, Op(op) == Op::I64Rotl)); + CHECK(EmitRotate(f, ValType::I64, Op(op.b0) == Op::I64Rotl)); case uint16_t(Op::F32Abs): CHECK(EmitUnaryWithType(f, ValType::F32, MIRType::Float32)); case uint16_t(Op::F32Neg): @@ -3523,7 +3523,7 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitDiv(f, ValType::F32, MIRType::Float32, /* isUnsigned = */ false)); case uint16_t(Op::F32Min): case uint16_t(Op::F32Max): - CHECK(EmitMinMax(f, ValType::F32, MIRType::Float32, Op(op) == Op::F32Max)); + CHECK(EmitMinMax(f, ValType::F32, MIRType::Float32, Op(op.b0) == Op::F32Max)); case uint16_t(Op::F32CopySign): CHECK(EmitCopySign(f, ValType::F32)); case uint16_t(Op::F64Abs): @@ -3550,7 +3550,7 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitDiv(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false)); case uint16_t(Op::F64Min): case uint16_t(Op::F64Max): - CHECK(EmitMinMax(f, ValType::F64, MIRType::Double, Op(op) == Op::F64Max)); + CHECK(EmitMinMax(f, ValType::F64, MIRType::Double, Op(op.b0) == Op::F64Max)); case uint16_t(Op::F64CopySign): CHECK(EmitCopySign(f, ValType::F64)); @@ -3559,26 +3559,26 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitConversion(f, ValType::I64, ValType::I32)); case uint16_t(Op::I32TruncSF32): case uint16_t(Op::I32TruncUF32): - CHECK(EmitTruncate(f, ValType::F32, ValType::I32, Op(op) == Op::I32TruncUF32)); + CHECK(EmitTruncate(f, ValType::F32, ValType::I32, Op(op.b0) == Op::I32TruncUF32)); case uint16_t(Op::I32TruncSF64): case uint16_t(Op::I32TruncUF64): - CHECK(EmitTruncate(f, ValType::F64, ValType::I32, Op(op) == Op::I32TruncUF64)); + CHECK(EmitTruncate(f, ValType::F64, ValType::I32, Op(op.b0) == Op::I32TruncUF64)); case uint16_t(Op::I64ExtendSI32): case uint16_t(Op::I64ExtendUI32): - CHECK(EmitExtendI32(f, Op(op) == Op::I64ExtendUI32)); + CHECK(EmitExtendI32(f, Op(op.b0) == Op::I64ExtendUI32)); case uint16_t(Op::I64TruncSF32): case uint16_t(Op::I64TruncUF32): - CHECK(EmitTruncate(f, ValType::F32, ValType::I64, Op(op) == Op::I64TruncUF32)); + CHECK(EmitTruncate(f, ValType::F32, ValType::I64, Op(op.b0) == Op::I64TruncUF32)); case uint16_t(Op::I64TruncSF64): case uint16_t(Op::I64TruncUF64): - CHECK(EmitTruncate(f, ValType::F64, ValType::I64, Op(op) == Op::I64TruncUF64)); + CHECK(EmitTruncate(f, ValType::F64, ValType::I64, Op(op.b0) == Op::I64TruncUF64)); case uint16_t(Op::F32ConvertSI32): CHECK(EmitConversion(f, ValType::I32, ValType::F32)); case uint16_t(Op::F32ConvertUI32): CHECK(EmitConversion(f, ValType::I32, ValType::F32)); case uint16_t(Op::F32ConvertSI64): case uint16_t(Op::F32ConvertUI64): - CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F32, MIRType::Float32, Op(op) == Op::F32ConvertUI64)); + CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F32, MIRType::Float32, Op(op.b0) == Op::F32ConvertUI64)); case uint16_t(Op::F32DemoteF64): CHECK(EmitConversion(f, ValType::F64, ValType::F32)); case uint16_t(Op::F64ConvertSI32): @@ -3587,7 +3587,7 @@ EmitBodyExprs(FunctionCompiler& f) CHECK(EmitConversion(f, ValType::I32, ValType::F64)); case uint16_t(Op::F64ConvertSI64): case uint16_t(Op::F64ConvertUI64): - CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F64, MIRType::Double, Op(op) == Op::F64ConvertUI64)); + CHECK(EmitConvertI64ToFloatingPoint(f, ValType::F64, MIRType::Double, Op(op.b0) == Op::F64ConvertUI64)); case uint16_t(Op::F64PromoteF32): CHECK(EmitConversion(f, ValType::F32, ValType::F64)); @@ -3603,80 +3603,82 @@ EmitBodyExprs(FunctionCompiler& f) // asm.js-specific operators - case uint16_t(Op::TeeGlobal): - CHECK_ASMJS(EmitTeeGlobal(f)); - case uint16_t(Op::I32Min): - case uint16_t(Op::I32Max): - CHECK_ASMJS(EmitMinMax(f, ValType::I32, MIRType::Int32, Op(op) == Op::I32Max)); - case uint16_t(Op::I32Neg): - CHECK_ASMJS(EmitUnaryWithType(f, ValType::I32, MIRType::Int32)); - case uint16_t(Op::I32BitNot): - CHECK_ASMJS(EmitBitNot(f, ValType::I32)); - case uint16_t(Op::I32Abs): - CHECK_ASMJS(EmitUnaryWithType(f, ValType::I32, MIRType::Int32)); - case uint16_t(Op::F32TeeStoreF64): - CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F32, Scalar::Float64)); - case uint16_t(Op::F64TeeStoreF32): - CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F64, Scalar::Float32)); - case uint16_t(Op::I32TeeStore8): - CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int8)); - case uint16_t(Op::I32TeeStore16): - CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int16)); - case uint16_t(Op::I64TeeStore8): - CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int8)); - case uint16_t(Op::I64TeeStore16): - CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int16)); - case uint16_t(Op::I64TeeStore32): - CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int32)); - case uint16_t(Op::I32TeeStore): - CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int32)); - case uint16_t(Op::I64TeeStore): - CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int64)); - case uint16_t(Op::F32TeeStore): - CHECK_ASMJS(EmitTeeStore(f, ValType::F32, Scalar::Float32)); - case uint16_t(Op::F64TeeStore): - CHECK_ASMJS(EmitTeeStore(f, ValType::F64, Scalar::Float64)); - case uint16_t(Op::F64Mod): - CHECK_ASMJS(EmitRem(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false)); - case uint16_t(Op::F64Sin): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::SinD, ValType::F64)); - case uint16_t(Op::F64Cos): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CosD, ValType::F64)); - case uint16_t(Op::F64Tan): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TanD, ValType::F64)); - case uint16_t(Op::F64Asin): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ASinD, ValType::F64)); - case uint16_t(Op::F64Acos): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ACosD, ValType::F64)); - case uint16_t(Op::F64Atan): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ATanD, ValType::F64)); - case uint16_t(Op::F64Exp): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ExpD, ValType::F64)); - case uint16_t(Op::F64Log): - CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::LogD, ValType::F64)); - case uint16_t(Op::F64Pow): - CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::PowD, ValType::F64)); - case uint16_t(Op::F64Atan2): - CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::ATan2D, ValType::F64)); - case uint16_t(Op::OldCallIndirect): - CHECK_ASMJS(EmitCallIndirect(f, /* oldStyle = */ true)); + case uint16_t(Op::MozPrefix): { + switch (op.b1) { + case uint16_t(MozOp::TeeGlobal): + CHECK_ASMJS(EmitTeeGlobal(f)); + case uint16_t(MozOp::I32Min): + case uint16_t(MozOp::I32Max): + CHECK_ASMJS(EmitMinMax(f, ValType::I32, MIRType::Int32, MozOp(op.b1) == MozOp::I32Max)); + case uint16_t(MozOp::I32Neg): + CHECK_ASMJS(EmitUnaryWithType(f, ValType::I32, MIRType::Int32)); + case uint16_t(MozOp::I32BitNot): + CHECK_ASMJS(EmitBitNot(f, ValType::I32)); + case uint16_t(MozOp::I32Abs): + CHECK_ASMJS(EmitUnaryWithType(f, ValType::I32, MIRType::Int32)); + case uint16_t(MozOp::F32TeeStoreF64): + CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F32, Scalar::Float64)); + case uint16_t(MozOp::F64TeeStoreF32): + CHECK_ASMJS(EmitTeeStoreWithCoercion(f, ValType::F64, Scalar::Float32)); + case uint16_t(MozOp::I32TeeStore8): + CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int8)); + case uint16_t(MozOp::I32TeeStore16): + CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int16)); + case uint16_t(MozOp::I64TeeStore8): + CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int8)); + case uint16_t(MozOp::I64TeeStore16): + CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int16)); + case uint16_t(MozOp::I64TeeStore32): + CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int32)); + case uint16_t(MozOp::I32TeeStore): + CHECK_ASMJS(EmitTeeStore(f, ValType::I32, Scalar::Int32)); + case uint16_t(MozOp::I64TeeStore): + CHECK_ASMJS(EmitTeeStore(f, ValType::I64, Scalar::Int64)); + case uint16_t(MozOp::F32TeeStore): + CHECK_ASMJS(EmitTeeStore(f, ValType::F32, Scalar::Float32)); + case uint16_t(MozOp::F64TeeStore): + CHECK_ASMJS(EmitTeeStore(f, ValType::F64, Scalar::Float64)); + case uint16_t(MozOp::F64Mod): + CHECK_ASMJS(EmitRem(f, ValType::F64, MIRType::Double, /* isUnsigned = */ false)); + case uint16_t(MozOp::F64Sin): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::SinD, ValType::F64)); + case uint16_t(MozOp::F64Cos): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::CosD, ValType::F64)); + case uint16_t(MozOp::F64Tan): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::TanD, ValType::F64)); + case uint16_t(MozOp::F64Asin): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ASinD, ValType::F64)); + case uint16_t(MozOp::F64Acos): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ACosD, ValType::F64)); + case uint16_t(MozOp::F64Atan): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ATanD, ValType::F64)); + case uint16_t(MozOp::F64Exp): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::ExpD, ValType::F64)); + case uint16_t(MozOp::F64Log): + CHECK_ASMJS(EmitUnaryMathBuiltinCall(f, SymbolicAddress::LogD, ValType::F64)); + case uint16_t(MozOp::F64Pow): + CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::PowD, ValType::F64)); + case uint16_t(MozOp::F64Atan2): + CHECK_ASMJS(EmitBinaryMathBuiltinCall(f, SymbolicAddress::ATan2D, ValType::F64)); + case uint16_t(MozOp::OldCallIndirect): + CHECK_ASMJS(EmitCallIndirect(f, /* oldStyle = */ true)); - // Atomics - case uint16_t(Op::I32AtomicsLoad): - CHECK_ASMJS(EmitAtomicsLoad(f)); - case uint16_t(Op::I32AtomicsStore): - CHECK_ASMJS(EmitAtomicsStore(f)); - case uint16_t(Op::I32AtomicsBinOp): - CHECK_ASMJS(EmitAtomicsBinOp(f)); - case uint16_t(Op::I32AtomicsCompareExchange): - CHECK_ASMJS(EmitAtomicsCompareExchange(f)); - case uint16_t(Op::I32AtomicsExchange): - CHECK_ASMJS(EmitAtomicsExchange(f)); + // Atomics + case uint16_t(MozOp::I32AtomicsLoad): + CHECK_ASMJS(EmitAtomicsLoad(f)); + case uint16_t(MozOp::I32AtomicsStore): + CHECK_ASMJS(EmitAtomicsStore(f)); + case uint16_t(MozOp::I32AtomicsBinOp): + CHECK_ASMJS(EmitAtomicsBinOp(f)); + case uint16_t(MozOp::I32AtomicsCompareExchange): + CHECK_ASMJS(EmitAtomicsCompareExchange(f)); + case uint16_t(MozOp::I32AtomicsExchange): + CHECK_ASMJS(EmitAtomicsExchange(f)); - // SIMD -#define CASE(TYPE, OP, SIGN) \ - case uint16_t(Op::TYPE##OP): \ - CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Fn_##OP, SIGN)); + // SIMD +#define CASE(TYPE, OP, SIGN) \ + case uint16_t(MozOp::TYPE##OP): \ + CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Fn_##OP, SIGN)); #define I8x16CASE(OP) CASE(I8x16, OP, SimdSign::Signed) #define I16x8CASE(OP) CASE(I16x8, OP, SimdSign::Signed) #define I32x4CASE(OP) CASE(I32x4, OP, SimdSign::Signed) @@ -3684,18 +3686,18 @@ EmitBodyExprs(FunctionCompiler& f) #define B8x16CASE(OP) CASE(B8x16, OP, SimdSign::NotApplicable) #define B16x8CASE(OP) CASE(B16x8, OP, SimdSign::NotApplicable) #define B32x4CASE(OP) CASE(B32x4, OP, SimdSign::NotApplicable) -#define ENUMERATE(TYPE, FORALL, DO) \ - case uint16_t(Op::TYPE##Constructor): \ - CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Constructor, SimdSign::NotApplicable)); \ - FORALL(DO) +#define ENUMERATE(TYPE, FORALL, DO) \ + case uint16_t(MozOp::TYPE##Constructor): \ + CHECK_ASMJS(EmitSimdOp(f, ValType::TYPE, SimdOperation::Constructor, SimdSign::NotApplicable)); \ + FORALL(DO) - ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) - ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) - ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) - ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) - ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE) - ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE) - ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE) + ENUMERATE(I8x16, FORALL_INT8X16_ASMJS_OP, I8x16CASE) + ENUMERATE(I16x8, FORALL_INT16X8_ASMJS_OP, I16x8CASE) + ENUMERATE(I32x4, FORALL_INT32X4_ASMJS_OP, I32x4CASE) + ENUMERATE(F32x4, FORALL_FLOAT32X4_ASMJS_OP, F32x4CASE) + ENUMERATE(B8x16, FORALL_BOOL_SIMD_OP, B8x16CASE) + ENUMERATE(B16x8, FORALL_BOOL_SIMD_OP, B16x8CASE) + ENUMERATE(B32x4, FORALL_BOOL_SIMD_OP, B32x4CASE) #undef CASE #undef I8x16CASE @@ -3707,70 +3709,76 @@ EmitBodyExprs(FunctionCompiler& f) #undef B32x4CASE #undef ENUMERATE - case uint16_t(Op::I8x16Const): - CHECK_ASMJS(EmitI8x16Const(f)); - case uint16_t(Op::I16x8Const): - CHECK_ASMJS(EmitI16x8Const(f)); - case uint16_t(Op::I32x4Const): - CHECK_ASMJS(EmitI32x4Const(f)); - case uint16_t(Op::F32x4Const): - CHECK_ASMJS(EmitF32x4Const(f)); - case uint16_t(Op::B8x16Const): - CHECK_ASMJS(EmitB8x16Const(f)); - case uint16_t(Op::B16x8Const): - CHECK_ASMJS(EmitB16x8Const(f)); - case uint16_t(Op::B32x4Const): - CHECK_ASMJS(EmitB32x4Const(f)); + case uint16_t(MozOp::I8x16Const): + CHECK_ASMJS(EmitI8x16Const(f)); + case uint16_t(MozOp::I16x8Const): + CHECK_ASMJS(EmitI16x8Const(f)); + case uint16_t(MozOp::I32x4Const): + CHECK_ASMJS(EmitI32x4Const(f)); + case uint16_t(MozOp::F32x4Const): + CHECK_ASMJS(EmitF32x4Const(f)); + case uint16_t(MozOp::B8x16Const): + CHECK_ASMJS(EmitB8x16Const(f)); + case uint16_t(MozOp::B16x8Const): + CHECK_ASMJS(EmitB16x8Const(f)); + case uint16_t(MozOp::B32x4Const): + CHECK_ASMJS(EmitB32x4Const(f)); - case uint16_t(Op::I8x16addSaturateU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_addSaturate, SimdSign::Unsigned)); - case uint16_t(Op::I8x16subSaturateU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_subSaturate, SimdSign::Unsigned)); - case uint16_t(Op::I8x16shiftRightByScalarU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned)); - case uint16_t(Op::I8x16lessThanU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThan, SimdSign::Unsigned)); - case uint16_t(Op::I8x16lessThanOrEqualU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned)); - case uint16_t(Op::I8x16greaterThanU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThan, SimdSign::Unsigned)); - case uint16_t(Op::I8x16greaterThanOrEqualU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned)); - case uint16_t(Op::I8x16extractLaneU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_extractLane, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16addSaturateU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_addSaturate, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16subSaturateU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_subSaturate, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16shiftRightByScalarU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16lessThanU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThan, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16lessThanOrEqualU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16greaterThanU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThan, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16greaterThanOrEqualU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned)); + case uint16_t(MozOp::I8x16extractLaneU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I8x16, SimdOperation::Fn_extractLane, SimdSign::Unsigned)); - case uint16_t(Op::I16x8addSaturateU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_addSaturate, SimdSign::Unsigned)); - case uint16_t(Op::I16x8subSaturateU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_subSaturate, SimdSign::Unsigned)); - case uint16_t(Op::I16x8shiftRightByScalarU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned)); - case uint16_t(Op::I16x8lessThanU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThan, SimdSign::Unsigned)); - case uint16_t(Op::I16x8lessThanOrEqualU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned)); - case uint16_t(Op::I16x8greaterThanU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThan, SimdSign::Unsigned)); - case uint16_t(Op::I16x8greaterThanOrEqualU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned)); - case uint16_t(Op::I16x8extractLaneU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_extractLane, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8addSaturateU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_addSaturate, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8subSaturateU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_subSaturate, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8shiftRightByScalarU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8lessThanU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThan, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8lessThanOrEqualU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8greaterThanU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThan, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8greaterThanOrEqualU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned)); + case uint16_t(MozOp::I16x8extractLaneU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I16x8, SimdOperation::Fn_extractLane, SimdSign::Unsigned)); - case uint16_t(Op::I32x4shiftRightByScalarU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned)); - case uint16_t(Op::I32x4lessThanU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned)); - case uint16_t(Op::I32x4lessThanOrEqualU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned)); - case uint16_t(Op::I32x4greaterThanU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned)); - case uint16_t(Op::I32x4greaterThanOrEqualU): - CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned)); - case uint16_t(Op::I32x4fromFloat32x4U): - CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4, SimdSign::Unsigned)); + case uint16_t(MozOp::I32x4shiftRightByScalarU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_shiftRightByScalar, SimdSign::Unsigned)); + case uint16_t(MozOp::I32x4lessThanU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThan, SimdSign::Unsigned)); + case uint16_t(MozOp::I32x4lessThanOrEqualU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_lessThanOrEqual, SimdSign::Unsigned)); + case uint16_t(MozOp::I32x4greaterThanU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThan, SimdSign::Unsigned)); + case uint16_t(MozOp::I32x4greaterThanOrEqualU): + CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_greaterThanOrEqual, SimdSign::Unsigned)); + case uint16_t(MozOp::I32x4fromFloat32x4U): + CHECK_ASMJS(EmitSimdOp(f, ValType::I32x4, SimdOperation::Fn_fromFloat32x4, SimdSign::Unsigned)); + + default: + return f.iter().unrecognizedOpcode(&op); + } + break; + } default: - return f.iter().unrecognizedOpcode(op); + return f.iter().unrecognizedOpcode(&op); } } diff --git a/js/src/wasm/WasmValidate.cpp b/js/src/wasm/WasmValidate.cpp index 06d7d7952f24..5c1577da2dc3 100644 --- a/js/src/wasm/WasmValidate.cpp +++ b/js/src/wasm/WasmValidate.cpp @@ -350,13 +350,13 @@ DecodeFunctionBodyExprs(const ModuleEnvironment& env, const Sig& sig, const ValT #define CHECK(c) if (!(c)) return false; break while (true) { - uint16_t op; + OpBytes op; if (!iter.readOp(&op)) return false; Nothing nothing; - switch (op) { + switch (op.b0) { case uint16_t(Op::End): { LabelKind unusedKind; ExprType unusedType; @@ -681,7 +681,7 @@ DecodeFunctionBodyExprs(const ModuleEnvironment& env, const Sig& sig, const ValT case uint16_t(Op::Unreachable): CHECK(iter.readUnreachable()); default: - return iter.unrecognizedOpcode(op); + return iter.unrecognizedOpcode(&op); } } @@ -1143,11 +1143,11 @@ static bool DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType expected, InitExpr* init) { - uint16_t op; + OpBytes op; if (!d.readOp(&op)) return d.fail("failed to read initializer type"); - switch (op) { + switch (op.b0) { case uint16_t(Op::I32Const): { int32_t i32; if (!d.readVarS32(&i32)) @@ -1195,8 +1195,8 @@ DecodeInitializerExpression(Decoder& d, const GlobalDescVector& globals, ValType if (expected != init->type()) return d.fail("type mismatch: initializer type and expected type don't match"); - uint16_t end; - if (!d.readOp(&end) || end != uint16_t(Op::End)) + OpBytes end; + if (!d.readOp(&end) || end.b0 != uint16_t(Op::End)) return d.fail("failed to read end of initializer expression"); return true; diff --git a/js/src/wasm/WasmValidate.h b/js/src/wasm/WasmValidate.h index b16c25f81cbd..a13e2568a935 100644 --- a/js/src/wasm/WasmValidate.h +++ b/js/src/wasm/WasmValidate.h @@ -242,12 +242,15 @@ class Encoder return writeFixedU8(uint8_t(type)); } MOZ_MUST_USE bool writeOp(Op op) { - static_assert(size_t(Op::Limit) <= 2 * UINT8_MAX, "fits"); + static_assert(size_t(Op::Limit) == 256, "fits"); MOZ_ASSERT(size_t(op) < size_t(Op::Limit)); - if (size_t(op) < UINT8_MAX) - return writeFixedU8(uint8_t(op)); - return writeFixedU8(UINT8_MAX) && - writeFixedU8(size_t(op) - UINT8_MAX); + return writeFixedU8(uint8_t(op)); + } + MOZ_MUST_USE bool writeOp(MozOp op) { + static_assert(size_t(MozOp::Limit) <= 256, "fits"); + MOZ_ASSERT(size_t(op) < size_t(MozOp::Limit)); + return writeFixedU8(uint8_t(Op::MozPrefix)) && + writeFixedU8(uint8_t(op)); } // Fixed-length encodings that allow back-patching. @@ -496,18 +499,19 @@ class Decoder static_assert(size_t(TypeCode::Limit) <= UINT8_MAX, "fits"); return readFixedU8(type); } - MOZ_MUST_USE bool readOp(uint16_t* op) { - static_assert(size_t(Op::Limit) <= 2 * UINT8_MAX, "fits"); + MOZ_MUST_USE bool readOp(OpBytes* op) { + static_assert(size_t(Op::Limit) == 256, "fits"); uint8_t u8; if (!readFixedU8(&u8)) return false; - if (MOZ_LIKELY(u8 != UINT8_MAX)) { - *op = u8; + op->b0 = u8; + if (MOZ_LIKELY(!IsPrefixByte(u8))) return true; - } - if (!readFixedU8(&u8)) + if (!readFixedU8(&u8)) { + op->b1 = 0; // Make it sane return false; - *op = uint16_t(u8) + UINT8_MAX; + } + op->b1 = u8; return true; } @@ -615,7 +619,7 @@ class Decoder return (ValType)uncheckedReadFixedU8(); } Op uncheckedReadOp() { - static_assert(size_t(Op::Limit) <= 2 * UINT8_MAX, "fits"); + static_assert(size_t(Op::Limit) == 256, "fits"); uint8_t u8 = uncheckedReadFixedU8(); return u8 != UINT8_MAX ? Op(u8)