1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Redistribution and use in source and binary forms, with or without 3 // modification, are permitted provided that the following conditions are 4 // met: 5 // 6 // * Redistributions of source code must retain the above copyright 7 // notice, this list of conditions and the following disclaimer. 8 // * Redistributions in binary form must reproduce the above 9 // copyright notice, this list of conditions and the following 10 // disclaimer in the documentation and/or other materials provided 11 // with the distribution. 12 // * Neither the name of Google Inc. nor the names of its 13 // contributors may be used to endorse or promote products derived 14 // from this software without specific prior written permission. 15 // 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 28 #include "v8.h" 29 30 #include "ast.h" 31 #include "code-stubs.h" 32 #include "compiler.h" 33 #include "ic.h" 34 #include "macro-assembler.h" 35 #include "stub-cache.h" 36 #include "type-info.h" 37 38 #include "ic-inl.h" 39 #include "objects-inl.h" 40 41 namespace v8 { 42 namespace internal { 43 44 45 TypeInfo TypeInfo::FromValue(Handle<Object> value) { 46 if (value->IsSmi()) { 47 return TypeInfo::Smi(); 48 } else if (value->IsHeapNumber()) { 49 return TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value()) 50 ? TypeInfo::Integer32() 51 : TypeInfo::Double(); 52 } else if (value->IsString()) { 53 return TypeInfo::String(); 54 } 55 return TypeInfo::Unknown(); 56 } 57 58 59 TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code, 60 Handle<Context> native_context, 61 Isolate* isolate, 62 Zone* zone) 63 : native_context_(native_context), 64 isolate_(isolate), 65 zone_(zone) { 66 BuildDictionary(code); 67 ASSERT(dictionary_->IsDictionary()); 68 } 69 70 71 static uint32_t IdToKey(TypeFeedbackId ast_id) { 72 return static_cast<uint32_t>(ast_id.ToInt()); 73 } 74 75 76 Handle<Object> TypeFeedbackOracle::GetInfo(TypeFeedbackId ast_id) { 77 int entry = dictionary_->FindEntry(IdToKey(ast_id)); 78 if (entry != UnseededNumberDictionary::kNotFound) { 79 Object* value = dictionary_->ValueAt(entry); 80 if (value->IsCell()) { 81 Cell* cell = Cell::cast(value); 82 return Handle<Object>(cell->value(), isolate_); 83 } else { 84 return Handle<Object>(value, isolate_); 85 } 86 } 87 return Handle<Object>::cast(isolate_->factory()->undefined_value()); 88 } 89 90 91 Handle<Cell> TypeFeedbackOracle::GetInfoCell( 92 TypeFeedbackId ast_id) { 93 int entry = dictionary_->FindEntry(IdToKey(ast_id)); 94 if (entry != UnseededNumberDictionary::kNotFound) { 95 Cell* cell = Cell::cast(dictionary_->ValueAt(entry)); 96 return Handle<Cell>(cell, isolate_); 97 } 98 return Handle<Cell>::null(); 99 } 100 101 102 bool TypeFeedbackOracle::LoadIsUninitialized(Property* expr) { 103 Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId()); 104 if (map_or_code->IsMap()) return false; 105 if (map_or_code->IsCode()) { 106 Handle<Code> code = Handle<Code>::cast(map_or_code); 107 return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; 108 } 109 return false; 110 } 111 112 113 bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) { 114 Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId()); 115 if (map_or_code->IsMap()) return true; 116 if (map_or_code->IsCode()) { 117 Handle<Code> code = Handle<Code>::cast(map_or_code); 118 bool preliminary_checks = code->is_keyed_load_stub() && 119 code->ic_state() == MONOMORPHIC && 120 Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL; 121 if (!preliminary_checks) return false; 122 Map* map = code->FindFirstMap(); 123 if (map == NULL) return false; 124 map = map->CurrentMapForDeprecated(); 125 return map != NULL && !CanRetainOtherContext(map, *native_context_); 126 } 127 return false; 128 } 129 130 131 bool TypeFeedbackOracle::LoadIsPolymorphic(Property* expr) { 132 Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId()); 133 if (map_or_code->IsCode()) { 134 Handle<Code> code = Handle<Code>::cast(map_or_code); 135 return code->is_keyed_load_stub() && code->ic_state() == POLYMORPHIC; 136 } 137 return false; 138 } 139 140 141 bool TypeFeedbackOracle::StoreIsUninitialized(TypeFeedbackId ast_id) { 142 Handle<Object> map_or_code = GetInfo(ast_id); 143 if (map_or_code->IsMap()) return false; 144 if (!map_or_code->IsCode()) return false; 145 Handle<Code> code = Handle<Code>::cast(map_or_code); 146 return code->ic_state() == UNINITIALIZED; 147 } 148 149 150 bool TypeFeedbackOracle::StoreIsMonomorphicNormal(TypeFeedbackId ast_id) { 151 Handle<Object> map_or_code = GetInfo(ast_id); 152 if (map_or_code->IsMap()) return true; 153 if (map_or_code->IsCode()) { 154 Handle<Code> code = Handle<Code>::cast(map_or_code); 155 bool standard_store = FLAG_compiled_keyed_stores || 156 (Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == 157 STANDARD_STORE); 158 bool preliminary_checks = 159 code->is_keyed_store_stub() && 160 standard_store && 161 code->ic_state() == MONOMORPHIC && 162 Code::ExtractTypeFromFlags(code->flags()) == Code::NORMAL; 163 if (!preliminary_checks) return false; 164 Map* map = code->FindFirstMap(); 165 if (map == NULL) return false; 166 map = map->CurrentMapForDeprecated(); 167 return map != NULL && !CanRetainOtherContext(map, *native_context_); 168 } 169 return false; 170 } 171 172 173 bool TypeFeedbackOracle::StoreIsKeyedPolymorphic(TypeFeedbackId ast_id) { 174 Handle<Object> map_or_code = GetInfo(ast_id); 175 if (map_or_code->IsCode()) { 176 Handle<Code> code = Handle<Code>::cast(map_or_code); 177 bool standard_store = FLAG_compiled_keyed_stores || 178 (Code::GetKeyedAccessStoreMode(code->extra_ic_state()) == 179 STANDARD_STORE); 180 return code->is_keyed_store_stub() && standard_store && 181 code->ic_state() == POLYMORPHIC; 182 } 183 return false; 184 } 185 186 187 bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { 188 Handle<Object> value = GetInfo(expr->CallFeedbackId()); 189 return value->IsMap() || value->IsAllocationSite() || value->IsJSFunction() || 190 value->IsSmi(); 191 } 192 193 194 bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) { 195 Handle<Object> info = GetInfo(expr->CallNewFeedbackId()); 196 return info->IsAllocationSite() || info->IsJSFunction(); 197 } 198 199 200 bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic( 201 ObjectLiteral::Property* prop) { 202 Handle<Object> map_or_code = GetInfo(prop->key()->LiteralFeedbackId()); 203 return map_or_code->IsMap(); 204 } 205 206 207 byte TypeFeedbackOracle::ForInType(ForInStatement* stmt) { 208 Handle<Object> value = GetInfo(stmt->ForInFeedbackId()); 209 return value->IsSmi() && 210 Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker 211 ? ForInStatement::FAST_FOR_IN : ForInStatement::SLOW_FOR_IN; 212 } 213 214 215 Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { 216 ASSERT(LoadIsMonomorphicNormal(expr)); 217 Handle<Object> map_or_code = GetInfo(expr->PropertyFeedbackId()); 218 if (map_or_code->IsCode()) { 219 Handle<Code> code = Handle<Code>::cast(map_or_code); 220 Map* map = code->FindFirstMap()->CurrentMapForDeprecated(); 221 return map == NULL || CanRetainOtherContext(map, *native_context_) 222 ? Handle<Map>::null() 223 : Handle<Map>(map); 224 } 225 return Handle<Map>::cast(map_or_code); 226 } 227 228 229 Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType( 230 TypeFeedbackId ast_id) { 231 ASSERT(StoreIsMonomorphicNormal(ast_id)); 232 Handle<Object> map_or_code = GetInfo(ast_id); 233 if (map_or_code->IsCode()) { 234 Handle<Code> code = Handle<Code>::cast(map_or_code); 235 Map* map = code->FindFirstMap()->CurrentMapForDeprecated(); 236 return map == NULL || CanRetainOtherContext(map, *native_context_) 237 ? Handle<Map>::null() 238 : Handle<Map>(map); 239 } 240 return Handle<Map>::cast(map_or_code); 241 } 242 243 244 KeyedAccessStoreMode TypeFeedbackOracle::GetStoreMode( 245 TypeFeedbackId ast_id) { 246 Handle<Object> map_or_code = GetInfo(ast_id); 247 if (map_or_code->IsCode()) { 248 Handle<Code> code = Handle<Code>::cast(map_or_code); 249 if (code->kind() == Code::KEYED_STORE_IC) { 250 return Code::GetKeyedAccessStoreMode(code->extra_ic_state()); 251 } 252 } 253 return STANDARD_STORE; 254 } 255 256 257 void TypeFeedbackOracle::LoadReceiverTypes(Property* expr, 258 Handle<String> name, 259 SmallMapList* types) { 260 Code::Flags flags = Code::ComputeFlags( 261 Code::STUB, MONOMORPHIC, Code::kNoExtraICState, 262 Code::NORMAL, Code::LOAD_IC); 263 CollectReceiverTypes(expr->PropertyFeedbackId(), name, flags, types); 264 } 265 266 267 void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, 268 Handle<String> name, 269 SmallMapList* types) { 270 Code::Flags flags = Code::ComputeFlags( 271 Code::STUB, MONOMORPHIC, Code::kNoExtraICState, 272 Code::NORMAL, Code::STORE_IC); 273 CollectReceiverTypes(expr->AssignmentFeedbackId(), name, flags, types); 274 } 275 276 277 void TypeFeedbackOracle::CallReceiverTypes(Call* expr, 278 Handle<String> name, 279 CallKind call_kind, 280 SmallMapList* types) { 281 int arity = expr->arguments()->length(); 282 283 // Note: Currently we do not take string extra ic data into account 284 // here. 285 Code::ExtraICState extra_ic_state = 286 CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION); 287 288 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, 289 extra_ic_state, 290 Code::NORMAL, 291 arity, 292 OWN_MAP); 293 CollectReceiverTypes(expr->CallFeedbackId(), name, flags, types); 294 } 295 296 297 CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) { 298 Handle<Object> value = GetInfo(expr->CallFeedbackId()); 299 if (!value->IsSmi()) return RECEIVER_MAP_CHECK; 300 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value()); 301 ASSERT(check != RECEIVER_MAP_CHECK); 302 return check; 303 } 304 305 306 Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) { 307 Handle<Object> info = GetInfo(expr->CallFeedbackId()); 308 if (info->IsAllocationSite()) { 309 return Handle<JSFunction>(isolate_->global_context()->array_function()); 310 } else { 311 return Handle<JSFunction>::cast(info); 312 } 313 } 314 315 316 Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(CallNew* expr) { 317 Handle<Object> info = GetInfo(expr->CallNewFeedbackId()); 318 if (info->IsAllocationSite()) { 319 return Handle<JSFunction>(isolate_->global_context()->array_function()); 320 } else { 321 return Handle<JSFunction>::cast(info); 322 } 323 } 324 325 326 Handle<Cell> TypeFeedbackOracle::GetCallNewAllocationInfoCell(CallNew* expr) { 327 return GetInfoCell(expr->CallNewFeedbackId()); 328 } 329 330 331 Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap( 332 ObjectLiteral::Property* prop) { 333 ASSERT(ObjectLiteralStoreIsMonomorphic(prop)); 334 return Handle<Map>::cast(GetInfo(prop->key()->LiteralFeedbackId())); 335 } 336 337 338 bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { 339 return *GetInfo(expr->PropertyFeedbackId()) == 340 isolate_->builtins()->builtin(id); 341 } 342 343 344 bool TypeFeedbackOracle::LoadIsStub(Property* expr, ICStub* stub) { 345 Handle<Object> object = GetInfo(expr->PropertyFeedbackId()); 346 if (!object->IsCode()) return false; 347 Handle<Code> code = Handle<Code>::cast(object); 348 if (!code->is_load_stub()) return false; 349 if (code->ic_state() != MONOMORPHIC) return false; 350 return stub->Describes(*code); 351 } 352 353 354 void TypeFeedbackOracle::CompareType(TypeFeedbackId id, 355 Handle<Type>* left_type, 356 Handle<Type>* right_type, 357 Handle<Type>* combined_type) { 358 Handle<Object> info = GetInfo(id); 359 if (!info->IsCode()) { 360 // For some comparisons we don't have ICs, e.g. LiteralCompareTypeof. 361 *left_type = *right_type = *combined_type = handle(Type::None(), isolate_); 362 return; 363 } 364 Handle<Code> code = Handle<Code>::cast(info); 365 366 Handle<Map> map; 367 Map* raw_map = code->FindFirstMap(); 368 if (raw_map != NULL) { 369 raw_map = raw_map->CurrentMapForDeprecated(); 370 if (raw_map != NULL && !CanRetainOtherContext(raw_map, *native_context_)) { 371 map = handle(raw_map, isolate_); 372 } 373 } 374 375 if (code->is_compare_ic_stub()) { 376 int stub_minor_key = code->stub_info(); 377 CompareIC::StubInfoToType( 378 stub_minor_key, left_type, right_type, combined_type, map, isolate()); 379 } else if (code->is_compare_nil_ic_stub()) { 380 CompareNilICStub stub(code->extended_extra_ic_state()); 381 *combined_type = stub.GetType(isolate_, map); 382 *left_type = *right_type = stub.GetInputType(isolate_, map); 383 } 384 } 385 386 387 void TypeFeedbackOracle::BinaryType(TypeFeedbackId id, 388 Handle<Type>* left, 389 Handle<Type>* right, 390 Handle<Type>* result, 391 Maybe<int>* fixed_right_arg) { 392 Handle<Object> object = GetInfo(id); 393 if (!object->IsCode()) { 394 // For some binary ops we don't have ICs, e.g. Token::COMMA. 395 *left = *right = *result = handle(Type::None(), isolate_); 396 return; 397 } 398 Handle<Code> code = Handle<Code>::cast(object); 399 ASSERT(code->is_binary_op_stub()); 400 401 int minor_key = code->stub_info(); 402 BinaryOpIC::StubInfoToType(minor_key, left, right, result, isolate()); 403 *fixed_right_arg = 404 BinaryOpStub::decode_fixed_right_arg_from_minor_key(minor_key); 405 } 406 407 408 Handle<Type> TypeFeedbackOracle::ClauseType(TypeFeedbackId id) { 409 Handle<Object> info = GetInfo(id); 410 Handle<Type> result(Type::None(), isolate_); 411 if (info->IsCode() && Handle<Code>::cast(info)->is_compare_ic_stub()) { 412 Handle<Code> code = Handle<Code>::cast(info); 413 CompareIC::State state = ICCompareStub::CompareState(code->stub_info()); 414 result = CompareIC::StateToType(isolate_, state); 415 } 416 return result; 417 } 418 419 420 TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) { 421 Handle<Object> object = GetInfo(expr->CountBinOpFeedbackId()); 422 TypeInfo unknown = TypeInfo::Unknown(); 423 if (!object->IsCode()) return unknown; 424 Handle<Code> code = Handle<Code>::cast(object); 425 if (!code->is_binary_op_stub()) return unknown; 426 427 BinaryOpIC::TypeInfo left_type, right_type, unused_result_type; 428 BinaryOpStub::decode_types_from_minor_key(code->stub_info(), &left_type, 429 &right_type, &unused_result_type); 430 // CountOperations should always have +1 or -1 as their right input. 431 ASSERT(right_type == BinaryOpIC::SMI || 432 right_type == BinaryOpIC::UNINITIALIZED); 433 434 switch (left_type) { 435 case BinaryOpIC::UNINITIALIZED: 436 case BinaryOpIC::SMI: 437 return TypeInfo::Smi(); 438 case BinaryOpIC::INT32: 439 return TypeInfo::Integer32(); 440 case BinaryOpIC::NUMBER: 441 return TypeInfo::Double(); 442 case BinaryOpIC::STRING: 443 case BinaryOpIC::GENERIC: 444 return unknown; 445 default: 446 return unknown; 447 } 448 UNREACHABLE(); 449 return unknown; 450 } 451 452 453 void TypeFeedbackOracle::CollectPolymorphicMaps(Handle<Code> code, 454 SmallMapList* types) { 455 MapHandleList maps; 456 code->FindAllMaps(&maps); 457 types->Reserve(maps.length(), zone()); 458 for (int i = 0; i < maps.length(); i++) { 459 Handle<Map> map(maps.at(i)); 460 if (!CanRetainOtherContext(*map, *native_context_)) { 461 types->AddMapIfMissing(map, zone()); 462 } 463 } 464 } 465 466 467 void TypeFeedbackOracle::CollectReceiverTypes(TypeFeedbackId ast_id, 468 Handle<String> name, 469 Code::Flags flags, 470 SmallMapList* types) { 471 Handle<Object> object = GetInfo(ast_id); 472 if (object->IsUndefined() || object->IsSmi()) return; 473 474 if (object.is_identical_to(isolate_->builtins()->StoreIC_GlobalProxy())) { 475 // TODO(fschneider): We could collect the maps and signal that 476 // we need a generic store (or load) here. 477 ASSERT(Handle<Code>::cast(object)->ic_state() == GENERIC); 478 } else if (object->IsMap()) { 479 types->AddMapIfMissing(Handle<Map>::cast(object), zone()); 480 } else if (Handle<Code>::cast(object)->ic_state() == POLYMORPHIC || 481 Handle<Code>::cast(object)->ic_state() == MONOMORPHIC) { 482 CollectPolymorphicMaps(Handle<Code>::cast(object), types); 483 } else if (FLAG_collect_megamorphic_maps_from_stub_cache && 484 Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) { 485 types->Reserve(4, zone()); 486 ASSERT(object->IsCode()); 487 isolate_->stub_cache()->CollectMatchingMaps(types, 488 name, 489 flags, 490 native_context_, 491 zone()); 492 } 493 } 494 495 496 // Check if a map originates from a given native context. We use this 497 // information to filter out maps from different context to avoid 498 // retaining objects from different tabs in Chrome via optimized code. 499 bool TypeFeedbackOracle::CanRetainOtherContext(Map* map, 500 Context* native_context) { 501 Object* constructor = NULL; 502 while (!map->prototype()->IsNull()) { 503 constructor = map->constructor(); 504 if (!constructor->IsNull()) { 505 // If the constructor is not null or a JSFunction, we have to 506 // conservatively assume that it may retain a native context. 507 if (!constructor->IsJSFunction()) return true; 508 // Check if the constructor directly references a foreign context. 509 if (CanRetainOtherContext(JSFunction::cast(constructor), 510 native_context)) { 511 return true; 512 } 513 } 514 map = HeapObject::cast(map->prototype())->map(); 515 } 516 constructor = map->constructor(); 517 if (constructor->IsNull()) return false; 518 JSFunction* function = JSFunction::cast(constructor); 519 return CanRetainOtherContext(function, native_context); 520 } 521 522 523 bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function, 524 Context* native_context) { 525 return function->context()->global_object() != native_context->global_object() 526 && function->context()->global_object() != native_context->builtins(); 527 } 528 529 530 void TypeFeedbackOracle::CollectKeyedReceiverTypes(TypeFeedbackId ast_id, 531 SmallMapList* types) { 532 Handle<Object> object = GetInfo(ast_id); 533 if (!object->IsCode()) return; 534 Handle<Code> code = Handle<Code>::cast(object); 535 if (code->kind() == Code::KEYED_LOAD_IC || 536 code->kind() == Code::KEYED_STORE_IC) { 537 CollectPolymorphicMaps(code, types); 538 } 539 } 540 541 542 void TypeFeedbackOracle::CollectPolymorphicStoreReceiverTypes( 543 TypeFeedbackId ast_id, 544 SmallMapList* types) { 545 Handle<Object> object = GetInfo(ast_id); 546 if (!object->IsCode()) return; 547 Handle<Code> code = Handle<Code>::cast(object); 548 if (code->kind() == Code::STORE_IC && code->ic_state() == POLYMORPHIC) { 549 CollectPolymorphicMaps(code, types); 550 } 551 } 552 553 554 byte TypeFeedbackOracle::ToBooleanTypes(TypeFeedbackId id) { 555 Handle<Object> object = GetInfo(id); 556 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0; 557 } 558 559 560 // Things are a bit tricky here: The iterator for the RelocInfos and the infos 561 // themselves are not GC-safe, so we first get all infos, then we create the 562 // dictionary (possibly triggering GC), and finally we relocate the collected 563 // infos before we process them. 564 void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) { 565 DisallowHeapAllocation no_allocation; 566 ZoneList<RelocInfo> infos(16, zone()); 567 HandleScope scope(isolate_); 568 GetRelocInfos(code, &infos); 569 CreateDictionary(code, &infos); 570 ProcessRelocInfos(&infos); 571 ProcessTypeFeedbackCells(code); 572 // Allocate handle in the parent scope. 573 dictionary_ = scope.CloseAndEscape(dictionary_); 574 } 575 576 577 void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code, 578 ZoneList<RelocInfo>* infos) { 579 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); 580 for (RelocIterator it(*code, mask); !it.done(); it.next()) { 581 infos->Add(*it.rinfo(), zone()); 582 } 583 } 584 585 586 void TypeFeedbackOracle::CreateDictionary(Handle<Code> code, 587 ZoneList<RelocInfo>* infos) { 588 AllowHeapAllocation allocation_allowed; 589 int cell_count = code->type_feedback_info()->IsTypeFeedbackInfo() 590 ? TypeFeedbackInfo::cast(code->type_feedback_info())-> 591 type_feedback_cells()->CellCount() 592 : 0; 593 int length = infos->length() + cell_count; 594 byte* old_start = code->instruction_start(); 595 dictionary_ = isolate()->factory()->NewUnseededNumberDictionary(length); 596 byte* new_start = code->instruction_start(); 597 RelocateRelocInfos(infos, old_start, new_start); 598 } 599 600 601 void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos, 602 byte* old_start, 603 byte* new_start) { 604 for (int i = 0; i < infos->length(); i++) { 605 RelocInfo* info = &(*infos)[i]; 606 info->set_pc(new_start + (info->pc() - old_start)); 607 } 608 } 609 610 611 void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) { 612 for (int i = 0; i < infos->length(); i++) { 613 RelocInfo reloc_entry = (*infos)[i]; 614 Address target_address = reloc_entry.target_address(); 615 TypeFeedbackId ast_id = 616 TypeFeedbackId(static_cast<unsigned>((*infos)[i].data())); 617 Code* target = Code::GetCodeFromTargetAddress(target_address); 618 switch (target->kind()) { 619 case Code::LOAD_IC: 620 case Code::STORE_IC: 621 case Code::CALL_IC: 622 case Code::KEYED_CALL_IC: 623 if (target->ic_state() == MONOMORPHIC) { 624 if (target->kind() == Code::CALL_IC && 625 target->check_type() != RECEIVER_MAP_CHECK) { 626 SetInfo(ast_id, Smi::FromInt(target->check_type())); 627 } else { 628 Object* map = target->FindFirstMap(); 629 if (map == NULL) { 630 SetInfo(ast_id, static_cast<Object*>(target)); 631 } else if (!CanRetainOtherContext(Map::cast(map), 632 *native_context_)) { 633 Map* feedback = Map::cast(map)->CurrentMapForDeprecated(); 634 if (feedback != NULL) SetInfo(ast_id, feedback); 635 } 636 } 637 } else { 638 SetInfo(ast_id, target); 639 } 640 break; 641 642 case Code::KEYED_LOAD_IC: 643 case Code::KEYED_STORE_IC: 644 if (target->ic_state() == MONOMORPHIC || 645 target->ic_state() == POLYMORPHIC) { 646 SetInfo(ast_id, target); 647 } 648 break; 649 650 case Code::BINARY_OP_IC: 651 case Code::COMPARE_IC: 652 case Code::TO_BOOLEAN_IC: 653 case Code::COMPARE_NIL_IC: 654 SetInfo(ast_id, target); 655 break; 656 657 default: 658 break; 659 } 660 } 661 } 662 663 664 void TypeFeedbackOracle::ProcessTypeFeedbackCells(Handle<Code> code) { 665 Object* raw_info = code->type_feedback_info(); 666 if (!raw_info->IsTypeFeedbackInfo()) return; 667 Handle<TypeFeedbackCells> cache( 668 TypeFeedbackInfo::cast(raw_info)->type_feedback_cells()); 669 for (int i = 0; i < cache->CellCount(); i++) { 670 TypeFeedbackId ast_id = cache->AstId(i); 671 Cell* cell = cache->GetCell(i); 672 Object* value = cell->value(); 673 if (value->IsSmi() || 674 value->IsAllocationSite() || 675 (value->IsJSFunction() && 676 !CanRetainOtherContext(JSFunction::cast(value), 677 *native_context_))) { 678 SetInfo(ast_id, cell); 679 } 680 } 681 } 682 683 684 void TypeFeedbackOracle::SetInfo(TypeFeedbackId ast_id, Object* target) { 685 ASSERT(dictionary_->FindEntry(IdToKey(ast_id)) == 686 UnseededNumberDictionary::kNotFound); 687 MaybeObject* maybe_result = dictionary_->AtNumberPut(IdToKey(ast_id), target); 688 USE(maybe_result); 689 #ifdef DEBUG 690 Object* result = NULL; 691 // Dictionary has been allocated with sufficient size for all elements. 692 ASSERT(maybe_result->ToObject(&result)); 693 ASSERT(*dictionary_ == result); 694 #endif 695 } 696 697 698 Representation Representation::FromType(TypeInfo info) { 699 if (info.IsUninitialized()) return Representation::None(); 700 if (info.IsSmi()) return Representation::Smi(); 701 if (info.IsInteger32()) return Representation::Integer32(); 702 if (info.IsDouble()) return Representation::Double(); 703 if (info.IsNumber()) return Representation::Double(); 704 return Representation::Tagged(); 705 } 706 707 708 } } // namespace v8::internal 709