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> {
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) \
......
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