[wasm] Optimize decode fastpath
This CL further optimizes the decoding fastpath by moving feature checks off the critical path. For prototype opcodes that are enabled by feature flags, they are handled in a switch case off the main path. R=mstarzinger@chromium.org Change-Id: If40fedbaadb9c611c78bc2b7df035ced056cb39a Reviewed-on: https://chromium-review.googlesource.com/1076187 Reviewed-by: Michael Starzinger <mstarzinger@chromium.org> Commit-Queue: Ben Titzer <titzer@chromium.org> Cr-Commit-Position: refs/heads/master@{#53406}
This commit is contained in:
parent
b2abe2cf97
commit
42f179ad02
@ -1908,6 +1908,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
len += DecodeAtomicOpcode(opcode);
|
||||
break;
|
||||
}
|
||||
// Note that prototype opcodes are not handled in the fastpath
|
||||
// above this switch, to avoid checking a feature flag.
|
||||
#define SIMPLE_PROTOTYPE_CASE(name, opc, sig) \
|
||||
case kExpr##name: /* fallthrough */
|
||||
FOREACH_SIMPLE_PROTOTYPE_OPCODE(SIMPLE_PROTOTYPE_CASE)
|
||||
#undef SIMPLE_PROTOTYPE_CASE
|
||||
BuildSimplePrototypeOperator(opcode);
|
||||
break;
|
||||
default: {
|
||||
// Deal with special asmjs opcodes.
|
||||
if (this->module_ != nullptr &&
|
||||
@ -2423,14 +2431,18 @@ class WasmFullDecoder : public WasmDecoder<validate> {
|
||||
CALL_INTERFACE(OnFirstError);
|
||||
}
|
||||
|
||||
inline void BuildSimpleOperator(WasmOpcode opcode, FunctionSig* sig) {
|
||||
void BuildSimplePrototypeOperator(WasmOpcode opcode) {
|
||||
if (WasmOpcodes::IsSignExtensionOpcode(opcode)) {
|
||||
RET_ON_PROTOTYPE_OPCODE(se);
|
||||
}
|
||||
if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
|
||||
RET_ON_PROTOTYPE_OPCODE(anyref);
|
||||
}
|
||||
FunctionSig* sig = WasmOpcodes::Signature(opcode);
|
||||
BuildSimpleOperator(opcode, sig);
|
||||
}
|
||||
|
||||
inline void BuildSimpleOperator(WasmOpcode opcode, FunctionSig* sig) {
|
||||
switch (sig->parameter_count()) {
|
||||
case 1: {
|
||||
auto val = Pop(0, sig->GetParam(0));
|
||||
|
@ -360,6 +360,7 @@ bool WasmOpcodes::IsAnyRefOpcode(WasmOpcode opcode) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
|
||||
if (sig.return_count() == 0) os << "v";
|
||||
for (auto ret : sig.returns()) {
|
||||
@ -398,7 +399,7 @@ FOREACH_SIGNATURE(DECLARE_SIG)
|
||||
#undef DECLARE_SIG
|
||||
|
||||
#define DECLARE_SIG_ENTRY(name, ...) &kSig_##name,
|
||||
constexpr const FunctionSig* kSimpleExprSigs[] = {
|
||||
constexpr const FunctionSig* kCachedSigs[] = {
|
||||
nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)};
|
||||
#undef DECLARE_SIG_ENTRY
|
||||
|
||||
@ -407,18 +408,11 @@ constexpr const FunctionSig* kSimpleExprSigs[] = {
|
||||
// encapsulate these constexpr functions in functors.
|
||||
// TODO(clemensh): Remove this once we require gcc >= 5.0.
|
||||
|
||||
struct GetOpcodeSigIndex {
|
||||
struct GetShortOpcodeSigIndex {
|
||||
constexpr WasmOpcodeSig operator()(byte opcode) const {
|
||||
#define CASE(name, opc, sig) opcode == opc ? kSigEnum_##sig:
|
||||
return FOREACH_SIMPLE_OPCODE(CASE) kSigEnum_None;
|
||||
#undef CASE
|
||||
}
|
||||
};
|
||||
|
||||
struct GetSimpleOpcodeSig {
|
||||
constexpr const FunctionSig* operator()(byte opcode) const {
|
||||
#define CASE(name, opc, sig) opcode == opc ? &kSig_##sig:
|
||||
return FOREACH_SIMPLE_OPCODE(CASE) nullptr;
|
||||
return FOREACH_SIMPLE_OPCODE(CASE) FOREACH_SIMPLE_PROTOTYPE_OPCODE(CASE)
|
||||
kSigEnum_None;
|
||||
#undef CASE
|
||||
}
|
||||
};
|
||||
@ -455,8 +449,8 @@ struct GetNumericOpcodeSigIndex {
|
||||
}
|
||||
};
|
||||
|
||||
constexpr std::array<WasmOpcodeSig, 256> kSimpleExprSigTable =
|
||||
base::make_array<256>(GetOpcodeSigIndex{});
|
||||
constexpr std::array<WasmOpcodeSig, 256> kShortSigTable =
|
||||
base::make_array<256>(GetShortOpcodeSigIndex{});
|
||||
constexpr std::array<WasmOpcodeSig, 256> kSimpleAsmjsExprSigTable =
|
||||
base::make_array<256>(GetAsmJsOpcodeSigIndex{});
|
||||
constexpr std::array<WasmOpcodeSig, 256> kSimdExprSigTable =
|
||||
@ -466,6 +460,15 @@ constexpr std::array<WasmOpcodeSig, 256> kAtomicExprSigTable =
|
||||
constexpr std::array<WasmOpcodeSig, 256> kNumericExprSigTable =
|
||||
base::make_array<256>(GetNumericOpcodeSigIndex{});
|
||||
|
||||
// Computes a direct pointer to a cached signature for a simple opcode.
|
||||
struct GetSimpleOpcodeSig {
|
||||
constexpr const FunctionSig* operator()(byte opcode) const {
|
||||
#define CASE(name, opc, sig) opcode == opc ? &kSig_##sig:
|
||||
return FOREACH_SIMPLE_OPCODE(CASE) nullptr;
|
||||
#undef CASE
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
const std::array<const FunctionSig*, 256> kSimpleOpcodeSigs =
|
||||
@ -473,26 +476,27 @@ const std::array<const FunctionSig*, 256> kSimpleOpcodeSigs =
|
||||
|
||||
FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) {
|
||||
switch (opcode >> 8) {
|
||||
case 0:
|
||||
return const_cast<FunctionSig*>(kCachedSigs[kShortSigTable[opcode]]);
|
||||
case kSimdPrefix:
|
||||
return const_cast<FunctionSig*>(
|
||||
kSimpleExprSigs[kSimdExprSigTable[opcode & 0xFF]]);
|
||||
kCachedSigs[kSimdExprSigTable[opcode & 0xFF]]);
|
||||
case kAtomicPrefix:
|
||||
return const_cast<FunctionSig*>(
|
||||
kSimpleExprSigs[kAtomicExprSigTable[opcode & 0xFF]]);
|
||||
kCachedSigs[kAtomicExprSigTable[opcode & 0xFF]]);
|
||||
case kNumericPrefix:
|
||||
return const_cast<FunctionSig*>(
|
||||
kSimpleExprSigs[kNumericExprSigTable[opcode & 0xFF]]);
|
||||
kCachedSigs[kNumericExprSigTable[opcode & 0xFF]]);
|
||||
default:
|
||||
DCHECK_GT(kSimpleExprSigTable.size(), opcode);
|
||||
return const_cast<FunctionSig*>(
|
||||
kSimpleExprSigs[kSimpleExprSigTable[opcode]]);
|
||||
UNREACHABLE(); // invalid prefix.
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
FunctionSig* WasmOpcodes::AsmjsSignature(WasmOpcode opcode) {
|
||||
DCHECK_GT(kSimpleAsmjsExprSigTable.size(), opcode);
|
||||
return const_cast<FunctionSig*>(
|
||||
kSimpleExprSigs[kSimpleAsmjsExprSigTable[opcode]]);
|
||||
kCachedSigs[kSimpleAsmjsExprSigTable[opcode]]);
|
||||
}
|
||||
|
||||
// Define constexpr arrays.
|
||||
|
@ -218,13 +218,15 @@ using WasmName = Vector<const char>;
|
||||
V(I32ReinterpretF32, 0xbc, i_f) \
|
||||
V(I64ReinterpretF64, 0xbd, l_d) \
|
||||
V(F32ReinterpretI32, 0xbe, f_i) \
|
||||
V(F64ReinterpretI64, 0xbf, d_l) \
|
||||
V(I32SExtendI8, 0xc0, i_i) \
|
||||
V(I32SExtendI16, 0xc1, i_i) \
|
||||
V(I64SExtendI8, 0xc2, l_l) \
|
||||
V(I64SExtendI16, 0xc3, l_l) \
|
||||
V(I64SExtendI32, 0xc4, l_l) \
|
||||
V(RefIsNull, 0xd1, i_r) \
|
||||
V(F64ReinterpretI64, 0xbf, d_l)
|
||||
|
||||
#define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \
|
||||
V(I32SExtendI8, 0xc0, i_i) \
|
||||
V(I32SExtendI16, 0xc1, i_i) \
|
||||
V(I64SExtendI8, 0xc2, l_l) \
|
||||
V(I64SExtendI16, 0xc3, l_l) \
|
||||
V(I64SExtendI32, 0xc4, l_l) \
|
||||
V(RefIsNull, 0xd1, i_r) \
|
||||
V(RefEq, 0xd2, i_rr)
|
||||
|
||||
// For compatibility with Asm.js.
|
||||
@ -479,6 +481,7 @@ using WasmName = Vector<const char>;
|
||||
FOREACH_CONTROL_OPCODE(V) \
|
||||
FOREACH_MISC_OPCODE(V) \
|
||||
FOREACH_SIMPLE_OPCODE(V) \
|
||||
FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \
|
||||
FOREACH_STORE_MEM_OPCODE(V) \
|
||||
FOREACH_LOAD_MEM_OPCODE(V) \
|
||||
FOREACH_MISC_MEM_OPCODE(V) \
|
||||
|
Loading…
Reference in New Issue
Block a user