Home | History | Annotate | Download | only in ic
      1 // Copyright 2014 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/ic/ic-state.h"
      6 
      7 #include "src/ast/ast-types.h"
      8 #include "src/feedback-vector.h"
      9 #include "src/ic/ic.h"
     10 #include "src/objects-inl.h"
     11 
     12 namespace v8 {
     13 namespace internal {
     14 
     15 // static
     16 void ICUtility::Clear(Isolate* isolate, Address address,
     17                       Address constant_pool) {
     18   IC::Clear(isolate, address, constant_pool);
     19 }
     20 
     21 
     22 // static
     23 STATIC_CONST_MEMBER_DEFINITION const int BinaryOpICState::FIRST_TOKEN;
     24 
     25 
     26 // static
     27 STATIC_CONST_MEMBER_DEFINITION const int BinaryOpICState::LAST_TOKEN;
     28 
     29 
     30 BinaryOpICState::BinaryOpICState(Isolate* isolate, ExtraICState extra_ic_state)
     31     : fixed_right_arg_(
     32           HasFixedRightArgField::decode(extra_ic_state)
     33               ? Just(1 << FixedRightArgValueField::decode(extra_ic_state))
     34               : Nothing<int>()),
     35       isolate_(isolate) {
     36   op_ =
     37       static_cast<Token::Value>(FIRST_TOKEN + OpField::decode(extra_ic_state));
     38   left_kind_ = LeftKindField::decode(extra_ic_state);
     39   right_kind_ = fixed_right_arg_.IsJust()
     40                     ? (Smi::IsValid(fixed_right_arg_.FromJust()) ? SMI : INT32)
     41                     : RightKindField::decode(extra_ic_state);
     42   result_kind_ = ResultKindField::decode(extra_ic_state);
     43   DCHECK_LE(FIRST_TOKEN, op_);
     44   DCHECK_LE(op_, LAST_TOKEN);
     45 }
     46 
     47 
     48 ExtraICState BinaryOpICState::GetExtraICState() const {
     49   ExtraICState extra_ic_state =
     50       OpField::encode(op_ - FIRST_TOKEN) | LeftKindField::encode(left_kind_) |
     51       ResultKindField::encode(result_kind_) |
     52       HasFixedRightArgField::encode(fixed_right_arg_.IsJust());
     53   if (fixed_right_arg_.IsJust()) {
     54     extra_ic_state = FixedRightArgValueField::update(
     55         extra_ic_state, WhichPowerOf2(fixed_right_arg_.FromJust()));
     56   } else {
     57     extra_ic_state = RightKindField::update(extra_ic_state, right_kind_);
     58   }
     59   return extra_ic_state;
     60 }
     61 
     62 std::string BinaryOpICState::ToString() const {
     63   std::string ret = "(";
     64   ret += Token::Name(op_);
     65   if (CouldCreateAllocationMementos()) ret += "_CreateAllocationMementos";
     66   ret += ":";
     67   ret += BinaryOpICState::KindToString(left_kind_);
     68   ret += "*";
     69   if (fixed_right_arg_.IsJust()) {
     70     ret += fixed_right_arg_.FromJust();
     71   } else {
     72     ret += BinaryOpICState::KindToString(right_kind_);
     73   }
     74   ret += "->";
     75   ret += BinaryOpICState::KindToString(result_kind_);
     76   ret += ")";
     77   return ret;
     78 }
     79 
     80 // static
     81 void BinaryOpICState::GenerateAheadOfTime(
     82     Isolate* isolate, void (*Generate)(Isolate*, const BinaryOpICState&)) {
     83 // TODO(olivf) We should investigate why adding stubs to the snapshot is so
     84 // expensive at runtime. When solved we should be able to add most binops to
     85 // the snapshot instead of hand-picking them.
     86 // Generated list of commonly used stubs
     87 #define GENERATE(op, left_kind, right_kind, result_kind) \
     88   do {                                                   \
     89     BinaryOpICState state(isolate, op);                  \
     90     state.left_kind_ = left_kind;                        \
     91     state.fixed_right_arg_ = Nothing<int>();             \
     92     state.right_kind_ = right_kind;                      \
     93     state.result_kind_ = result_kind;                    \
     94     Generate(isolate, state);                            \
     95   } while (false)
     96   GENERATE(Token::ADD, INT32, INT32, INT32);
     97   GENERATE(Token::ADD, INT32, INT32, NUMBER);
     98   GENERATE(Token::ADD, INT32, NUMBER, NUMBER);
     99   GENERATE(Token::ADD, INT32, SMI, INT32);
    100   GENERATE(Token::ADD, NUMBER, INT32, NUMBER);
    101   GENERATE(Token::ADD, NUMBER, NUMBER, NUMBER);
    102   GENERATE(Token::ADD, NUMBER, SMI, NUMBER);
    103   GENERATE(Token::ADD, SMI, INT32, INT32);
    104   GENERATE(Token::ADD, SMI, INT32, NUMBER);
    105   GENERATE(Token::ADD, SMI, NUMBER, NUMBER);
    106   GENERATE(Token::ADD, SMI, SMI, INT32);
    107   GENERATE(Token::ADD, SMI, SMI, SMI);
    108   GENERATE(Token::BIT_AND, INT32, INT32, INT32);
    109   GENERATE(Token::BIT_AND, INT32, INT32, SMI);
    110   GENERATE(Token::BIT_AND, INT32, SMI, INT32);
    111   GENERATE(Token::BIT_AND, INT32, SMI, SMI);
    112   GENERATE(Token::BIT_AND, NUMBER, INT32, INT32);
    113   GENERATE(Token::BIT_AND, NUMBER, SMI, SMI);
    114   GENERATE(Token::BIT_AND, SMI, INT32, INT32);
    115   GENERATE(Token::BIT_AND, SMI, INT32, SMI);
    116   GENERATE(Token::BIT_AND, SMI, NUMBER, SMI);
    117   GENERATE(Token::BIT_AND, SMI, SMI, SMI);
    118   GENERATE(Token::BIT_OR, INT32, INT32, INT32);
    119   GENERATE(Token::BIT_OR, INT32, INT32, SMI);
    120   GENERATE(Token::BIT_OR, INT32, SMI, INT32);
    121   GENERATE(Token::BIT_OR, INT32, SMI, SMI);
    122   GENERATE(Token::BIT_OR, NUMBER, SMI, INT32);
    123   GENERATE(Token::BIT_OR, NUMBER, SMI, SMI);
    124   GENERATE(Token::BIT_OR, SMI, INT32, INT32);
    125   GENERATE(Token::BIT_OR, SMI, INT32, SMI);
    126   GENERATE(Token::BIT_OR, SMI, SMI, SMI);
    127   GENERATE(Token::BIT_XOR, INT32, INT32, INT32);
    128   GENERATE(Token::BIT_XOR, INT32, INT32, SMI);
    129   GENERATE(Token::BIT_XOR, INT32, NUMBER, SMI);
    130   GENERATE(Token::BIT_XOR, INT32, SMI, INT32);
    131   GENERATE(Token::BIT_XOR, NUMBER, INT32, INT32);
    132   GENERATE(Token::BIT_XOR, NUMBER, SMI, INT32);
    133   GENERATE(Token::BIT_XOR, NUMBER, SMI, SMI);
    134   GENERATE(Token::BIT_XOR, SMI, INT32, INT32);
    135   GENERATE(Token::BIT_XOR, SMI, INT32, SMI);
    136   GENERATE(Token::BIT_XOR, SMI, SMI, SMI);
    137   GENERATE(Token::DIV, INT32, INT32, INT32);
    138   GENERATE(Token::DIV, INT32, INT32, NUMBER);
    139   GENERATE(Token::DIV, INT32, NUMBER, NUMBER);
    140   GENERATE(Token::DIV, INT32, SMI, INT32);
    141   GENERATE(Token::DIV, INT32, SMI, NUMBER);
    142   GENERATE(Token::DIV, NUMBER, INT32, NUMBER);
    143   GENERATE(Token::DIV, NUMBER, NUMBER, NUMBER);
    144   GENERATE(Token::DIV, NUMBER, SMI, NUMBER);
    145   GENERATE(Token::DIV, SMI, INT32, INT32);
    146   GENERATE(Token::DIV, SMI, INT32, NUMBER);
    147   GENERATE(Token::DIV, SMI, NUMBER, NUMBER);
    148   GENERATE(Token::DIV, SMI, SMI, NUMBER);
    149   GENERATE(Token::DIV, SMI, SMI, SMI);
    150   GENERATE(Token::MOD, NUMBER, SMI, NUMBER);
    151   GENERATE(Token::MOD, SMI, SMI, SMI);
    152   GENERATE(Token::MUL, INT32, INT32, INT32);
    153   GENERATE(Token::MUL, INT32, INT32, NUMBER);
    154   GENERATE(Token::MUL, INT32, NUMBER, NUMBER);
    155   GENERATE(Token::MUL, INT32, SMI, INT32);
    156   GENERATE(Token::MUL, INT32, SMI, NUMBER);
    157   GENERATE(Token::MUL, NUMBER, INT32, NUMBER);
    158   GENERATE(Token::MUL, NUMBER, NUMBER, NUMBER);
    159   GENERATE(Token::MUL, NUMBER, SMI, NUMBER);
    160   GENERATE(Token::MUL, SMI, INT32, INT32);
    161   GENERATE(Token::MUL, SMI, INT32, NUMBER);
    162   GENERATE(Token::MUL, SMI, NUMBER, NUMBER);
    163   GENERATE(Token::MUL, SMI, SMI, INT32);
    164   GENERATE(Token::MUL, SMI, SMI, NUMBER);
    165   GENERATE(Token::MUL, SMI, SMI, SMI);
    166   GENERATE(Token::SAR, INT32, SMI, INT32);
    167   GENERATE(Token::SAR, INT32, SMI, SMI);
    168   GENERATE(Token::SAR, NUMBER, SMI, SMI);
    169   GENERATE(Token::SAR, SMI, SMI, SMI);
    170   GENERATE(Token::SHL, INT32, SMI, INT32);
    171   GENERATE(Token::SHL, INT32, SMI, SMI);
    172   GENERATE(Token::SHL, NUMBER, SMI, SMI);
    173   GENERATE(Token::SHL, SMI, SMI, INT32);
    174   GENERATE(Token::SHL, SMI, SMI, SMI);
    175   GENERATE(Token::SHR, INT32, SMI, SMI);
    176   GENERATE(Token::SHR, NUMBER, SMI, INT32);
    177   GENERATE(Token::SHR, NUMBER, SMI, SMI);
    178   GENERATE(Token::SHR, SMI, SMI, SMI);
    179   GENERATE(Token::SUB, INT32, INT32, INT32);
    180   GENERATE(Token::SUB, INT32, NUMBER, NUMBER);
    181   GENERATE(Token::SUB, INT32, SMI, INT32);
    182   GENERATE(Token::SUB, NUMBER, INT32, NUMBER);
    183   GENERATE(Token::SUB, NUMBER, NUMBER, NUMBER);
    184   GENERATE(Token::SUB, NUMBER, SMI, NUMBER);
    185   GENERATE(Token::SUB, SMI, INT32, INT32);
    186   GENERATE(Token::SUB, SMI, NUMBER, NUMBER);
    187   GENERATE(Token::SUB, SMI, SMI, SMI);
    188 #undef GENERATE
    189 #define GENERATE(op, left_kind, fixed_right_arg_value, result_kind) \
    190   do {                                                              \
    191     BinaryOpICState state(isolate, op);                             \
    192     state.left_kind_ = left_kind;                                   \
    193     state.fixed_right_arg_ = Just(fixed_right_arg_value);           \
    194     state.right_kind_ = SMI;                                        \
    195     state.result_kind_ = result_kind;                               \
    196     Generate(isolate, state);                                       \
    197   } while (false)
    198   GENERATE(Token::MOD, SMI, 2, SMI);
    199   GENERATE(Token::MOD, SMI, 4, SMI);
    200   GENERATE(Token::MOD, SMI, 8, SMI);
    201   GENERATE(Token::MOD, SMI, 16, SMI);
    202   GENERATE(Token::MOD, SMI, 32, SMI);
    203   GENERATE(Token::MOD, SMI, 2048, SMI);
    204 #undef GENERATE
    205 }
    206 
    207 AstType* BinaryOpICState::GetResultType() const {
    208   Kind result_kind = result_kind_;
    209   if (HasSideEffects()) {
    210     result_kind = NONE;
    211   } else if (result_kind == GENERIC && op_ == Token::ADD) {
    212     return AstType::NumberOrString();
    213   } else if (result_kind == NUMBER && op_ == Token::SHR) {
    214     return AstType::Unsigned32();
    215   }
    216   DCHECK_NE(GENERIC, result_kind);
    217   return KindToType(result_kind);
    218 }
    219 
    220 
    221 std::ostream& operator<<(std::ostream& os, const BinaryOpICState& s) {
    222   os << "(" << Token::Name(s.op_);
    223   if (s.CouldCreateAllocationMementos()) os << "_CreateAllocationMementos";
    224   os << ":" << BinaryOpICState::KindToString(s.left_kind_) << "*";
    225   if (s.fixed_right_arg_.IsJust()) {
    226     os << s.fixed_right_arg_.FromJust();
    227   } else {
    228     os << BinaryOpICState::KindToString(s.right_kind_);
    229   }
    230   return os << "->" << BinaryOpICState::KindToString(s.result_kind_) << ")";
    231 }
    232 
    233 
    234 void BinaryOpICState::Update(Handle<Object> left, Handle<Object> right,
    235                              Handle<Object> result) {
    236   ExtraICState old_extra_ic_state = GetExtraICState();
    237 
    238   left_kind_ = UpdateKind(left, left_kind_);
    239   right_kind_ = UpdateKind(right, right_kind_);
    240 
    241   int32_t fixed_right_arg_value = 0;
    242   bool has_fixed_right_arg =
    243       op_ == Token::MOD && right->ToInt32(&fixed_right_arg_value) &&
    244       fixed_right_arg_value > 0 &&
    245       base::bits::IsPowerOfTwo32(fixed_right_arg_value) &&
    246       FixedRightArgValueField::is_valid(WhichPowerOf2(fixed_right_arg_value)) &&
    247       (left_kind_ == SMI || left_kind_ == INT32) &&
    248       (result_kind_ == NONE || !fixed_right_arg_.IsJust());
    249   fixed_right_arg_ =
    250       has_fixed_right_arg ? Just(fixed_right_arg_value) : Nothing<int32_t>();
    251   result_kind_ = UpdateKind(result, result_kind_);
    252 
    253   if (!Token::IsTruncatingBinaryOp(op_)) {
    254     Kind input_kind = Max(left_kind_, right_kind_);
    255     if (result_kind_ < input_kind && input_kind <= NUMBER) {
    256       result_kind_ = input_kind;
    257     }
    258   }
    259 
    260   // We don't want to distinguish INT32 and NUMBER for string add (because
    261   // NumberToString can't make use of this anyway).
    262   if (left_kind_ == STRING && right_kind_ == INT32) {
    263     DCHECK_EQ(STRING, result_kind_);
    264     DCHECK_EQ(Token::ADD, op_);
    265     right_kind_ = NUMBER;
    266   } else if (right_kind_ == STRING && left_kind_ == INT32) {
    267     DCHECK_EQ(STRING, result_kind_);
    268     DCHECK_EQ(Token::ADD, op_);
    269     left_kind_ = NUMBER;
    270   }
    271 
    272   if (old_extra_ic_state == GetExtraICState()) {
    273     // Tagged operations can lead to non-truncating HChanges
    274     if (left->IsOddball()) {
    275       left_kind_ = GENERIC;
    276     } else {
    277       DCHECK(right->IsOddball());
    278       right_kind_ = GENERIC;
    279     }
    280   }
    281 }
    282 
    283 
    284 BinaryOpICState::Kind BinaryOpICState::UpdateKind(Handle<Object> object,
    285                                                   Kind kind) const {
    286   Kind new_kind = GENERIC;
    287   bool is_truncating = Token::IsTruncatingBinaryOp(op());
    288   if (object->IsOddball() && is_truncating) {
    289     // Oddballs will be automatically truncated by HChange.
    290     new_kind = INT32;
    291   } else if (object->IsUndefined(isolate_)) {
    292     // Undefined will be automatically truncated by HChange.
    293     new_kind = is_truncating ? INT32 : NUMBER;
    294   } else if (object->IsSmi()) {
    295     new_kind = SMI;
    296   } else if (object->IsHeapNumber()) {
    297     double value = Handle<HeapNumber>::cast(object)->value();
    298     new_kind = IsInt32Double(value) ? INT32 : NUMBER;
    299   } else if (object->IsString() && op() == Token::ADD) {
    300     new_kind = STRING;
    301   }
    302   if (new_kind == INT32 && SmiValuesAre32Bits()) {
    303     new_kind = NUMBER;
    304   }
    305   if (kind != NONE && ((new_kind <= NUMBER && kind > NUMBER) ||
    306                        (new_kind > NUMBER && kind <= NUMBER))) {
    307     new_kind = GENERIC;
    308   }
    309   return Max(kind, new_kind);
    310 }
    311 
    312 
    313 // static
    314 const char* BinaryOpICState::KindToString(Kind kind) {
    315   switch (kind) {
    316     case NONE:
    317       return "None";
    318     case SMI:
    319       return "Smi";
    320     case INT32:
    321       return "Int32";
    322     case NUMBER:
    323       return "Number";
    324     case STRING:
    325       return "String";
    326     case GENERIC:
    327       return "Generic";
    328   }
    329   UNREACHABLE();
    330   return NULL;
    331 }
    332 
    333 
    334 // static
    335 AstType* BinaryOpICState::KindToType(Kind kind) {
    336   switch (kind) {
    337     case NONE:
    338       return AstType::None();
    339     case SMI:
    340       return AstType::SignedSmall();
    341     case INT32:
    342       return AstType::Signed32();
    343     case NUMBER:
    344       return AstType::Number();
    345     case STRING:
    346       return AstType::String();
    347     case GENERIC:
    348       return AstType::Any();
    349   }
    350   UNREACHABLE();
    351   return NULL;
    352 }
    353 
    354 
    355 const char* CompareICState::GetStateName(State state) {
    356   switch (state) {
    357     case UNINITIALIZED:
    358       return "UNINITIALIZED";
    359     case BOOLEAN:
    360       return "BOOLEAN";
    361     case SMI:
    362       return "SMI";
    363     case NUMBER:
    364       return "NUMBER";
    365     case INTERNALIZED_STRING:
    366       return "INTERNALIZED_STRING";
    367     case STRING:
    368       return "STRING";
    369     case UNIQUE_NAME:
    370       return "UNIQUE_NAME";
    371     case RECEIVER:
    372       return "RECEIVER";
    373     case KNOWN_RECEIVER:
    374       return "KNOWN_RECEIVER";
    375     case GENERIC:
    376       return "GENERIC";
    377   }
    378   UNREACHABLE();
    379   return NULL;
    380 }
    381 
    382 AstType* CompareICState::StateToType(Zone* zone, State state, Handle<Map> map) {
    383   switch (state) {
    384     case UNINITIALIZED:
    385       return AstType::None();
    386     case BOOLEAN:
    387       return AstType::Boolean();
    388     case SMI:
    389       return AstType::SignedSmall();
    390     case NUMBER:
    391       return AstType::Number();
    392     case STRING:
    393       return AstType::String();
    394     case INTERNALIZED_STRING:
    395       return AstType::InternalizedString();
    396     case UNIQUE_NAME:
    397       return AstType::UniqueName();
    398     case RECEIVER:
    399       return AstType::Receiver();
    400     case KNOWN_RECEIVER:
    401       return map.is_null() ? AstType::Receiver() : AstType::Class(map, zone);
    402     case GENERIC:
    403       return AstType::Any();
    404   }
    405   UNREACHABLE();
    406   return NULL;
    407 }
    408 
    409 
    410 CompareICState::State CompareICState::NewInputState(State old_state,
    411                                                     Handle<Object> value) {
    412   switch (old_state) {
    413     case UNINITIALIZED:
    414       if (value->IsBoolean()) return BOOLEAN;
    415       if (value->IsSmi()) return SMI;
    416       if (value->IsHeapNumber()) return NUMBER;
    417       if (value->IsInternalizedString()) return INTERNALIZED_STRING;
    418       if (value->IsString()) return STRING;
    419       if (value->IsSymbol()) return UNIQUE_NAME;
    420       if (value->IsJSReceiver() && !value->IsUndetectable()) {
    421         return RECEIVER;
    422       }
    423       break;
    424     case BOOLEAN:
    425       if (value->IsBoolean()) return BOOLEAN;
    426       break;
    427     case SMI:
    428       if (value->IsSmi()) return SMI;
    429       if (value->IsHeapNumber()) return NUMBER;
    430       break;
    431     case NUMBER:
    432       if (value->IsNumber()) return NUMBER;
    433       break;
    434     case INTERNALIZED_STRING:
    435       if (value->IsInternalizedString()) return INTERNALIZED_STRING;
    436       if (value->IsString()) return STRING;
    437       if (value->IsSymbol()) return UNIQUE_NAME;
    438       break;
    439     case STRING:
    440       if (value->IsString()) return STRING;
    441       break;
    442     case UNIQUE_NAME:
    443       if (value->IsUniqueName()) return UNIQUE_NAME;
    444       break;
    445     case RECEIVER:
    446       if (value->IsJSReceiver() && !value->IsUndetectable()) {
    447         return RECEIVER;
    448       }
    449       break;
    450     case GENERIC:
    451       break;
    452     case KNOWN_RECEIVER:
    453       UNREACHABLE();
    454       break;
    455   }
    456   return GENERIC;
    457 }
    458 
    459 
    460 // static
    461 CompareICState::State CompareICState::TargetState(
    462     Isolate* isolate, State old_state, State old_left, State old_right,
    463     Token::Value op, bool has_inlined_smi_code, Handle<Object> x,
    464     Handle<Object> y) {
    465   switch (old_state) {
    466     case UNINITIALIZED:
    467       if (x->IsBoolean() && y->IsBoolean()) return BOOLEAN;
    468       if (x->IsSmi() && y->IsSmi()) return SMI;
    469       if (x->IsNumber() && y->IsNumber()) return NUMBER;
    470       if (Token::IsOrderedRelationalCompareOp(op)) {
    471         // Ordered comparisons treat undefined as NaN, so the
    472         // NUMBER stub will do the right thing.
    473         if ((x->IsNumber() && y->IsUndefined(isolate)) ||
    474             (y->IsNumber() && x->IsUndefined(isolate))) {
    475           return NUMBER;
    476         }
    477       }
    478       if (x->IsInternalizedString() && y->IsInternalizedString()) {
    479         // We compare internalized strings as plain ones if we need to determine
    480         // the order in a non-equality compare.
    481         return Token::IsEqualityOp(op) ? INTERNALIZED_STRING : STRING;
    482       }
    483       if (x->IsString() && y->IsString()) return STRING;
    484       if (x->IsJSReceiver() && y->IsJSReceiver()) {
    485         if (x->IsUndetectable() || y->IsUndetectable()) {
    486           return GENERIC;
    487         }
    488         if (Handle<JSReceiver>::cast(x)->map() ==
    489             Handle<JSReceiver>::cast(y)->map()) {
    490           return KNOWN_RECEIVER;
    491         } else {
    492           return Token::IsEqualityOp(op) ? RECEIVER : GENERIC;
    493         }
    494       }
    495       if (!Token::IsEqualityOp(op)) return GENERIC;
    496       if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
    497       return GENERIC;
    498     case SMI:
    499       return x->IsNumber() && y->IsNumber() ? NUMBER : GENERIC;
    500     case INTERNALIZED_STRING:
    501       DCHECK(Token::IsEqualityOp(op));
    502       if (x->IsString() && y->IsString()) return STRING;
    503       if (x->IsUniqueName() && y->IsUniqueName()) return UNIQUE_NAME;
    504       return GENERIC;
    505     case NUMBER:
    506       // If the failure was due to one side changing from smi to heap number,
    507       // then keep the state (if other changed at the same time, we will get
    508       // a second miss and then go to generic).
    509       if (old_left == SMI && x->IsHeapNumber()) return NUMBER;
    510       if (old_right == SMI && y->IsHeapNumber()) return NUMBER;
    511       return GENERIC;
    512     case KNOWN_RECEIVER:
    513       if (x->IsJSReceiver() && y->IsJSReceiver()) {
    514         return Token::IsEqualityOp(op) ? RECEIVER : GENERIC;
    515       }
    516       return GENERIC;
    517     case BOOLEAN:
    518     case STRING:
    519     case UNIQUE_NAME:
    520     case RECEIVER:
    521     case GENERIC:
    522       return GENERIC;
    523   }
    524   UNREACHABLE();
    525   return GENERIC;  // Make the compiler happy.
    526 }
    527 
    528 }  // namespace internal
    529 }  // namespace v8
    530