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