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