| Index: src/interpreter/bytecode-traits.h
 | 
| diff --git a/src/interpreter/bytecode-traits.h b/src/interpreter/bytecode-traits.h
 | 
| index c724827356a3d020384386e7b875545c29f9b569..e7d14325037a44ce8757fc9ed07be47d85a8f00f 100644
 | 
| --- a/src/interpreter/bytecode-traits.h
 | 
| +++ b/src/interpreter/bytecode-traits.h
 | 
| @@ -41,6 +41,28 @@ struct OperandTraits {
 | 
|  OPERAND_TYPE_LIST(DECLARE_OPERAND_TYPE_TRAITS)
 | 
|  #undef DECLARE_OPERAND_TYPE_TRAITS
 | 
|  
 | 
| +template <OperandType operand_type, OperandScale operand_scale>
 | 
| +struct OperandScaler {
 | 
| +  template <bool, OperandSize, OperandScale>
 | 
| +  struct Helper {
 | 
| +    static const int kSize = 0;
 | 
| +  };
 | 
| +  template <OperandSize size, OperandScale scale>
 | 
| +  struct Helper<false, size, scale> {
 | 
| +    static const int kSize = static_cast<int>(size);
 | 
| +  };
 | 
| +  template <OperandSize size, OperandScale scale>
 | 
| +  struct Helper<true, size, scale> {
 | 
| +    static const int kSize = static_cast<int>(size) * static_cast<int>(scale);
 | 
| +  };
 | 
| +
 | 
| +  static const int kSize =
 | 
| +      Helper<OperandTraits<operand_type>::TypeInfo::kIsScalable,
 | 
| +             OperandTraits<operand_type>::TypeInfo::kUnscaledSize,
 | 
| +             operand_scale>::kSize;
 | 
| +  static const OperandSize kOperandSize = static_cast<OperandSize>(kSize);
 | 
| +};
 | 
| +
 | 
|  template <OperandType>
 | 
|  struct RegisterOperandTraits {
 | 
|    static const int kIsRegisterOperand = 0;
 | 
| @@ -61,11 +83,30 @@ template <AccumulatorUse accumulator_use, OperandType operand_0,
 | 
|            OperandType operand_1, OperandType operand_2, OperandType operand_3>
 | 
|  struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2,
 | 
|                        operand_3> {
 | 
| -  static OperandType GetOperandType(int i) {
 | 
| -    DCHECK(0 <= i && i < kOperandCount);
 | 
| -    const OperandType kOperands[] = {operand_0, operand_1, operand_2,
 | 
| -                                     operand_3};
 | 
| -    return kOperands[i];
 | 
| +  static const OperandType* GetOperandTypes() {
 | 
| +    static const OperandType operand_types[] = {operand_0, operand_1, operand_2,
 | 
| +                                                operand_3, OperandType::kNone};
 | 
| +    return operand_types;
 | 
| +  }
 | 
| +
 | 
| +  static OperandSize GetOperandSize(int i, OperandScale operand_scale) {
 | 
| +    switch (operand_scale) {
 | 
| +#define CASE(Name, _)                                                  \
 | 
| +  case OperandScale::k##Name: {                                        \
 | 
| +    static const OperandSize kOperandSizes[] = {                       \
 | 
| +        OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \
 | 
| +        OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \
 | 
| +        OperandScaler<operand_2, OperandScale::k##Name>::kOperandSize, \
 | 
| +        OperandScaler<operand_3, OperandScale::k##Name>::kOperandSize, \
 | 
| +    };                                                                 \
 | 
| +    DCHECK_LT(static_cast<size_t>(i), arraysize(kOperandSizes));       \
 | 
| +    return kOperandSizes[i];                                           \
 | 
| +  }
 | 
| +      OPERAND_SCALE_LIST(CASE)
 | 
| +#undef CASE
 | 
| +    }
 | 
| +    UNREACHABLE();
 | 
| +    return OperandSize::kNone;
 | 
|    }
 | 
|  
 | 
|    template <OperandType ot>
 | 
| @@ -98,10 +139,29 @@ struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2,
 | 
|  template <AccumulatorUse accumulator_use, OperandType operand_0,
 | 
|            OperandType operand_1, OperandType operand_2>
 | 
|  struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2> {
 | 
| -  static inline OperandType GetOperandType(int i) {
 | 
| -    DCHECK(0 <= i && i <= 2);
 | 
| -    const OperandType kOperands[] = {operand_0, operand_1, operand_2};
 | 
| -    return kOperands[i];
 | 
| +  static const OperandType* GetOperandTypes() {
 | 
| +    static const OperandType operand_types[] = {operand_0, operand_1, operand_2,
 | 
| +                                                OperandType::kNone};
 | 
| +    return operand_types;
 | 
| +  }
 | 
| +
 | 
| +  static OperandSize GetOperandSize(int i, OperandScale operand_scale) {
 | 
| +    switch (operand_scale) {
 | 
| +#define CASE(Name, _)                                                  \
 | 
| +  case OperandScale::k##Name: {                                        \
 | 
| +    static const OperandSize kOperandSizes[] = {                       \
 | 
| +        OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \
 | 
| +        OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \
 | 
| +        OperandScaler<operand_2, OperandScale::k##Name>::kOperandSize, \
 | 
| +    };                                                                 \
 | 
| +    DCHECK_LT(static_cast<size_t>(i), arraysize(kOperandSizes));       \
 | 
| +    return kOperandSizes[i];                                           \
 | 
| +  }
 | 
| +      OPERAND_SCALE_LIST(CASE)
 | 
| +#undef CASE
 | 
| +    }
 | 
| +    UNREACHABLE();
 | 
| +    return OperandSize::kNone;
 | 
|    }
 | 
|  
 | 
|    template <OperandType ot>
 | 
| @@ -130,10 +190,28 @@ struct BytecodeTraits<accumulator_use, operand_0, operand_1, operand_2> {
 | 
|  template <AccumulatorUse accumulator_use, OperandType operand_0,
 | 
|            OperandType operand_1>
 | 
|  struct BytecodeTraits<accumulator_use, operand_0, operand_1> {
 | 
| -  static inline OperandType GetOperandType(int i) {
 | 
| -    DCHECK(0 <= i && i < kOperandCount);
 | 
| -    const OperandType kOperands[] = {operand_0, operand_1};
 | 
| -    return kOperands[i];
 | 
| +  static const OperandType* GetOperandTypes() {
 | 
| +    static const OperandType operand_types[] = {operand_0, operand_1,
 | 
| +                                                OperandType::kNone};
 | 
| +    return operand_types;
 | 
| +  }
 | 
| +
 | 
| +  static OperandSize GetOperandSize(int i, OperandScale operand_scale) {
 | 
| +    switch (operand_scale) {
 | 
| +#define CASE(Name, _)                                                  \
 | 
| +  case OperandScale::k##Name: {                                        \
 | 
| +    static const OperandSize kOperandSizes[] = {                       \
 | 
| +        OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \
 | 
| +        OperandScaler<operand_1, OperandScale::k##Name>::kOperandSize, \
 | 
| +    };                                                                 \
 | 
| +    DCHECK_LT(static_cast<size_t>(i), arraysize(kOperandSizes));       \
 | 
| +    return kOperandSizes[i];                                           \
 | 
| +  }
 | 
| +      OPERAND_SCALE_LIST(CASE)
 | 
| +#undef CASE
 | 
| +    }
 | 
| +    UNREACHABLE();
 | 
| +    return OperandSize::kNone;
 | 
|    }
 | 
|  
 | 
|    template <OperandType ot>
 | 
| @@ -158,9 +236,26 @@ struct BytecodeTraits<accumulator_use, operand_0, operand_1> {
 | 
|  
 | 
|  template <AccumulatorUse accumulator_use, OperandType operand_0>
 | 
|  struct BytecodeTraits<accumulator_use, operand_0> {
 | 
| -  static inline OperandType GetOperandType(int i) {
 | 
| -    DCHECK(i == 0);
 | 
| -    return operand_0;
 | 
| +  static const OperandType* GetOperandTypes() {
 | 
| +    static const OperandType operand_types[] = {operand_0, OperandType::kNone};
 | 
| +    return operand_types;
 | 
| +  }
 | 
| +
 | 
| +  static OperandSize GetOperandSize(int i, OperandScale operand_scale) {
 | 
| +    switch (operand_scale) {
 | 
| +#define CASE(Name, _)                                                  \
 | 
| +  case OperandScale::k##Name: {                                        \
 | 
| +    static const OperandSize kOperandSizes[] = {                       \
 | 
| +        OperandScaler<operand_0, OperandScale::k##Name>::kOperandSize, \
 | 
| +    };                                                                 \
 | 
| +    DCHECK_LT(static_cast<size_t>(i), arraysize(kOperandSizes));       \
 | 
| +    return kOperandSizes[i];                                           \
 | 
| +  }
 | 
| +      OPERAND_SCALE_LIST(CASE)
 | 
| +#undef CASE
 | 
| +    }
 | 
| +    UNREACHABLE();
 | 
| +    return OperandSize::kNone;
 | 
|    }
 | 
|  
 | 
|    template <OperandType ot>
 | 
| @@ -182,9 +277,14 @@ struct BytecodeTraits<accumulator_use, operand_0> {
 | 
|  
 | 
|  template <AccumulatorUse accumulator_use>
 | 
|  struct BytecodeTraits<accumulator_use> {
 | 
| -  static inline OperandType GetOperandType(int i) {
 | 
| +  static const OperandType* GetOperandTypes() {
 | 
| +    static const OperandType operand_types[] = {OperandType::kNone};
 | 
| +    return operand_types;
 | 
| +  }
 | 
| +
 | 
| +  static OperandSize GetOperandSize(int i, OperandScale operand_scale) {
 | 
|      UNREACHABLE();
 | 
| -    return OperandType::kNone;
 | 
| +    return OperandSize::kNone;
 | 
|    }
 | 
|  
 | 
|    template <OperandType ot>
 | 
| @@ -200,37 +300,22 @@ struct BytecodeTraits<accumulator_use> {
 | 
|    static const int kRegisterOperandBitmap = 0;
 | 
|  };
 | 
|  
 | 
| -template <bool>
 | 
| -struct OperandScaler {
 | 
| -  static int Multiply(int size, int operand_scale) { return 0; }
 | 
| -};
 | 
| -
 | 
| -template <>
 | 
| -struct OperandScaler<false> {
 | 
| -  static int Multiply(int size, int operand_scale) { return size; }
 | 
| -};
 | 
| -
 | 
| -template <>
 | 
| -struct OperandScaler<true> {
 | 
| -  static int Multiply(int size, int operand_scale) {
 | 
| -    return size * operand_scale;
 | 
| -  }
 | 
| -};
 | 
| -
 | 
|  static OperandSize ScaledOperandSize(OperandType operand_type,
 | 
|                                       OperandScale operand_scale) {
 | 
| +  STATIC_ASSERT(static_cast<int>(OperandScale::kQuadruple) == 4 &&
 | 
| +                OperandScale::kLast == OperandScale::kQuadruple);
 | 
| +  int index = static_cast<int>(operand_scale) >> 1;
 | 
|    switch (operand_type) {
 | 
| -#define CASE(Name, TypeInfo)                                                   \
 | 
| -  case OperandType::k##Name: {                                                 \
 | 
| -    OperandSize base_size = OperandTypeInfoTraits<TypeInfo>::kUnscaledSize;    \
 | 
| -    int size =                                                                 \
 | 
| -        OperandScaler<OperandTypeInfoTraits<TypeInfo>::kIsScalable>::Multiply( \
 | 
| -            static_cast<int>(base_size), static_cast<int>(operand_scale));     \
 | 
| -    OperandSize operand_size = static_cast<OperandSize>(size);                 \
 | 
| -    DCHECK(operand_size == OperandSize::kByte ||                               \
 | 
| -           operand_size == OperandSize::kShort ||                              \
 | 
| -           operand_size == OperandSize::kQuad);                                \
 | 
| -    return operand_size;                                                       \
 | 
| +#define CASE(Name, TypeInfo)                                    \
 | 
| +  case OperandType::k##Name: {                                  \
 | 
| +    static const OperandSize kOperandSizes[] = {                \
 | 
| +        OperandScaler<OperandType::k##Name,                     \
 | 
| +                      OperandScale::kSingle>::kOperandSize,     \
 | 
| +        OperandScaler<OperandType::k##Name,                     \
 | 
| +                      OperandScale::kDouble>::kOperandSize,     \
 | 
| +        OperandScaler<OperandType::k##Name,                     \
 | 
| +                      OperandScale::kQuadruple>::kOperandSize}; \
 | 
| +    return kOperandSizes[index];                                \
 | 
|    }
 | 
|      OPERAND_TYPE_LIST(CASE)
 | 
|  #undef CASE
 | 
| 
 |