Commit 42f179ad authored by Ben L. Titzer's avatar Ben L. Titzer Committed by Commit Bot

[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/1076187Reviewed-by: 's avatarMichael Starzinger <mstarzinger@chromium.org>
Commit-Queue: Ben Titzer <titzer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#53406}
parent b2abe2cf
...@@ -1908,6 +1908,14 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -1908,6 +1908,14 @@ class WasmFullDecoder : public WasmDecoder<validate> {
len += DecodeAtomicOpcode(opcode); len += DecodeAtomicOpcode(opcode);
break; 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: { default: {
// Deal with special asmjs opcodes. // Deal with special asmjs opcodes.
if (this->module_ != nullptr && if (this->module_ != nullptr &&
...@@ -2423,14 +2431,18 @@ class WasmFullDecoder : public WasmDecoder<validate> { ...@@ -2423,14 +2431,18 @@ class WasmFullDecoder : public WasmDecoder<validate> {
CALL_INTERFACE(OnFirstError); CALL_INTERFACE(OnFirstError);
} }
inline void BuildSimpleOperator(WasmOpcode opcode, FunctionSig* sig) { void BuildSimplePrototypeOperator(WasmOpcode opcode) {
if (WasmOpcodes::IsSignExtensionOpcode(opcode)) { if (WasmOpcodes::IsSignExtensionOpcode(opcode)) {
RET_ON_PROTOTYPE_OPCODE(se); RET_ON_PROTOTYPE_OPCODE(se);
} }
if (WasmOpcodes::IsAnyRefOpcode(opcode)) { if (WasmOpcodes::IsAnyRefOpcode(opcode)) {
RET_ON_PROTOTYPE_OPCODE(anyref); RET_ON_PROTOTYPE_OPCODE(anyref);
} }
FunctionSig* sig = WasmOpcodes::Signature(opcode);
BuildSimpleOperator(opcode, sig);
}
inline void BuildSimpleOperator(WasmOpcode opcode, FunctionSig* sig) {
switch (sig->parameter_count()) { switch (sig->parameter_count()) {
case 1: { case 1: {
auto val = Pop(0, sig->GetParam(0)); auto val = Pop(0, sig->GetParam(0));
......
...@@ -360,6 +360,7 @@ bool WasmOpcodes::IsAnyRefOpcode(WasmOpcode opcode) { ...@@ -360,6 +360,7 @@ bool WasmOpcodes::IsAnyRefOpcode(WasmOpcode opcode) {
return false; return false;
} }
} }
std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) { std::ostream& operator<<(std::ostream& os, const FunctionSig& sig) {
if (sig.return_count() == 0) os << "v"; if (sig.return_count() == 0) os << "v";
for (auto ret : sig.returns()) { for (auto ret : sig.returns()) {
...@@ -398,7 +399,7 @@ FOREACH_SIGNATURE(DECLARE_SIG) ...@@ -398,7 +399,7 @@ FOREACH_SIGNATURE(DECLARE_SIG)
#undef DECLARE_SIG #undef DECLARE_SIG
#define DECLARE_SIG_ENTRY(name, ...) &kSig_##name, #define DECLARE_SIG_ENTRY(name, ...) &kSig_##name,
constexpr const FunctionSig* kSimpleExprSigs[] = { constexpr const FunctionSig* kCachedSigs[] = {
nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)}; nullptr, FOREACH_SIGNATURE(DECLARE_SIG_ENTRY)};
#undef DECLARE_SIG_ENTRY #undef DECLARE_SIG_ENTRY
...@@ -407,18 +408,11 @@ constexpr const FunctionSig* kSimpleExprSigs[] = { ...@@ -407,18 +408,11 @@ constexpr const FunctionSig* kSimpleExprSigs[] = {
// encapsulate these constexpr functions in functors. // encapsulate these constexpr functions in functors.
// TODO(clemensh): Remove this once we require gcc >= 5.0. // TODO(clemensh): Remove this once we require gcc >= 5.0.
struct GetOpcodeSigIndex { struct GetShortOpcodeSigIndex {
constexpr WasmOpcodeSig operator()(byte opcode) const { constexpr WasmOpcodeSig operator()(byte opcode) const {
#define CASE(name, opc, sig) opcode == opc ? kSigEnum_##sig: #define CASE(name, opc, sig) opcode == opc ? kSigEnum_##sig:
return FOREACH_SIMPLE_OPCODE(CASE) kSigEnum_None; return FOREACH_SIMPLE_OPCODE(CASE) FOREACH_SIMPLE_PROTOTYPE_OPCODE(CASE)
#undef CASE kSigEnum_None;
}
};
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 #undef CASE
} }
}; };
...@@ -455,8 +449,8 @@ struct GetNumericOpcodeSigIndex { ...@@ -455,8 +449,8 @@ struct GetNumericOpcodeSigIndex {
} }
}; };
constexpr std::array<WasmOpcodeSig, 256> kSimpleExprSigTable = constexpr std::array<WasmOpcodeSig, 256> kShortSigTable =
base::make_array<256>(GetOpcodeSigIndex{}); base::make_array<256>(GetShortOpcodeSigIndex{});
constexpr std::array<WasmOpcodeSig, 256> kSimpleAsmjsExprSigTable = constexpr std::array<WasmOpcodeSig, 256> kSimpleAsmjsExprSigTable =
base::make_array<256>(GetAsmJsOpcodeSigIndex{}); base::make_array<256>(GetAsmJsOpcodeSigIndex{});
constexpr std::array<WasmOpcodeSig, 256> kSimdExprSigTable = constexpr std::array<WasmOpcodeSig, 256> kSimdExprSigTable =
...@@ -466,6 +460,15 @@ constexpr std::array<WasmOpcodeSig, 256> kAtomicExprSigTable = ...@@ -466,6 +460,15 @@ constexpr std::array<WasmOpcodeSig, 256> kAtomicExprSigTable =
constexpr std::array<WasmOpcodeSig, 256> kNumericExprSigTable = constexpr std::array<WasmOpcodeSig, 256> kNumericExprSigTable =
base::make_array<256>(GetNumericOpcodeSigIndex{}); 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 } // namespace
const std::array<const FunctionSig*, 256> kSimpleOpcodeSigs = const std::array<const FunctionSig*, 256> kSimpleOpcodeSigs =
...@@ -473,26 +476,27 @@ const std::array<const FunctionSig*, 256> kSimpleOpcodeSigs = ...@@ -473,26 +476,27 @@ const std::array<const FunctionSig*, 256> kSimpleOpcodeSigs =
FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) { FunctionSig* WasmOpcodes::Signature(WasmOpcode opcode) {
switch (opcode >> 8) { switch (opcode >> 8) {
case 0:
return const_cast<FunctionSig*>(kCachedSigs[kShortSigTable[opcode]]);
case kSimdPrefix: case kSimdPrefix:
return const_cast<FunctionSig*>( return const_cast<FunctionSig*>(
kSimpleExprSigs[kSimdExprSigTable[opcode & 0xFF]]); kCachedSigs[kSimdExprSigTable[opcode & 0xFF]]);
case kAtomicPrefix: case kAtomicPrefix:
return const_cast<FunctionSig*>( return const_cast<FunctionSig*>(
kSimpleExprSigs[kAtomicExprSigTable[opcode & 0xFF]]); kCachedSigs[kAtomicExprSigTable[opcode & 0xFF]]);
case kNumericPrefix: case kNumericPrefix:
return const_cast<FunctionSig*>( return const_cast<FunctionSig*>(
kSimpleExprSigs[kNumericExprSigTable[opcode & 0xFF]]); kCachedSigs[kNumericExprSigTable[opcode & 0xFF]]);
default: default:
DCHECK_GT(kSimpleExprSigTable.size(), opcode); UNREACHABLE(); // invalid prefix.
return const_cast<FunctionSig*>( return nullptr;
kSimpleExprSigs[kSimpleExprSigTable[opcode]]);
} }
} }
FunctionSig* WasmOpcodes::AsmjsSignature(WasmOpcode opcode) { FunctionSig* WasmOpcodes::AsmjsSignature(WasmOpcode opcode) {
DCHECK_GT(kSimpleAsmjsExprSigTable.size(), opcode); DCHECK_GT(kSimpleAsmjsExprSigTable.size(), opcode);
return const_cast<FunctionSig*>( return const_cast<FunctionSig*>(
kSimpleExprSigs[kSimpleAsmjsExprSigTable[opcode]]); kCachedSigs[kSimpleAsmjsExprSigTable[opcode]]);
} }
// Define constexpr arrays. // Define constexpr arrays.
......
...@@ -218,7 +218,9 @@ using WasmName = Vector<const char>; ...@@ -218,7 +218,9 @@ using WasmName = Vector<const char>;
V(I32ReinterpretF32, 0xbc, i_f) \ V(I32ReinterpretF32, 0xbc, i_f) \
V(I64ReinterpretF64, 0xbd, l_d) \ V(I64ReinterpretF64, 0xbd, l_d) \
V(F32ReinterpretI32, 0xbe, f_i) \ V(F32ReinterpretI32, 0xbe, f_i) \
V(F64ReinterpretI64, 0xbf, d_l) \ V(F64ReinterpretI64, 0xbf, d_l)
#define FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \
V(I32SExtendI8, 0xc0, i_i) \ V(I32SExtendI8, 0xc0, i_i) \
V(I32SExtendI16, 0xc1, i_i) \ V(I32SExtendI16, 0xc1, i_i) \
V(I64SExtendI8, 0xc2, l_l) \ V(I64SExtendI8, 0xc2, l_l) \
...@@ -479,6 +481,7 @@ using WasmName = Vector<const char>; ...@@ -479,6 +481,7 @@ using WasmName = Vector<const char>;
FOREACH_CONTROL_OPCODE(V) \ FOREACH_CONTROL_OPCODE(V) \
FOREACH_MISC_OPCODE(V) \ FOREACH_MISC_OPCODE(V) \
FOREACH_SIMPLE_OPCODE(V) \ FOREACH_SIMPLE_OPCODE(V) \
FOREACH_SIMPLE_PROTOTYPE_OPCODE(V) \
FOREACH_STORE_MEM_OPCODE(V) \ FOREACH_STORE_MEM_OPCODE(V) \
FOREACH_LOAD_MEM_OPCODE(V) \ FOREACH_LOAD_MEM_OPCODE(V) \
FOREACH_MISC_MEM_OPCODE(V) \ FOREACH_MISC_MEM_OPCODE(V) \
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment