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