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::TypeFromValue(Handle<Object> value) { 46 TypeInfo info; 47 if (value->IsSmi()) { 48 info = TypeInfo::Smi(); 49 } else if (value->IsHeapNumber()) { 50 info = TypeInfo::IsInt32Double(HeapNumber::cast(*value)->value()) 51 ? TypeInfo::Integer32() 52 : TypeInfo::Double(); 53 } else if (value->IsString()) { 54 info = TypeInfo::String(); 55 } else { 56 info = TypeInfo::Unknown(); 57 } 58 return info; 59 } 60 61 62 TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code, 63 Handle<Context> global_context, 64 Isolate* isolate) { 65 global_context_ = global_context; 66 isolate_ = isolate; 67 BuildDictionary(code); 68 ASSERT(reinterpret_cast<Address>(*dictionary_.location()) != kHandleZapValue); 69 } 70 71 72 Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) { 73 int entry = dictionary_->FindEntry(ast_id); 74 return entry != UnseededNumberDictionary::kNotFound 75 ? Handle<Object>(dictionary_->ValueAt(entry)) 76 : Handle<Object>::cast(isolate_->factory()->undefined_value()); 77 } 78 79 80 bool TypeFeedbackOracle::LoadIsUninitialized(Property* expr) { 81 Handle<Object> map_or_code = GetInfo(expr->id()); 82 if (map_or_code->IsMap()) return false; 83 if (map_or_code->IsCode()) { 84 Handle<Code> code = Handle<Code>::cast(map_or_code); 85 return code->is_inline_cache_stub() && code->ic_state() == UNINITIALIZED; 86 } 87 return false; 88 } 89 90 91 bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) { 92 Handle<Object> map_or_code = GetInfo(expr->id()); 93 if (map_or_code->IsMap()) return true; 94 if (map_or_code->IsCode()) { 95 Handle<Code> code = Handle<Code>::cast(map_or_code); 96 return code->is_keyed_load_stub() && 97 code->ic_state() == MONOMORPHIC && 98 Code::ExtractTypeFromFlags(code->flags()) == NORMAL && 99 code->FindFirstMap() != NULL && 100 !CanRetainOtherContext(code->FindFirstMap(), *global_context_); 101 } 102 return false; 103 } 104 105 106 bool TypeFeedbackOracle::LoadIsMegamorphicWithTypeInfo(Property* expr) { 107 Handle<Object> map_or_code = GetInfo(expr->id()); 108 if (map_or_code->IsCode()) { 109 Handle<Code> code = Handle<Code>::cast(map_or_code); 110 Builtins* builtins = isolate_->builtins(); 111 return code->is_keyed_load_stub() && 112 *code != builtins->builtin(Builtins::kKeyedLoadIC_Generic) && 113 code->ic_state() == MEGAMORPHIC; 114 } 115 return false; 116 } 117 118 119 bool TypeFeedbackOracle::StoreIsMonomorphicNormal(Expression* expr) { 120 Handle<Object> map_or_code = GetInfo(expr->id()); 121 if (map_or_code->IsMap()) return true; 122 if (map_or_code->IsCode()) { 123 Handle<Code> code = Handle<Code>::cast(map_or_code); 124 bool allow_growth = 125 Code::GetKeyedAccessGrowMode(code->extra_ic_state()) == 126 ALLOW_JSARRAY_GROWTH; 127 return code->is_keyed_store_stub() && 128 !allow_growth && 129 code->ic_state() == MONOMORPHIC && 130 Code::ExtractTypeFromFlags(code->flags()) == NORMAL && 131 code->FindFirstMap() != NULL && 132 !CanRetainOtherContext(code->FindFirstMap(), *global_context_); 133 } 134 return false; 135 } 136 137 138 bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(Expression* expr) { 139 Handle<Object> map_or_code = GetInfo(expr->id()); 140 if (map_or_code->IsCode()) { 141 Handle<Code> code = Handle<Code>::cast(map_or_code); 142 Builtins* builtins = isolate_->builtins(); 143 bool allow_growth = 144 Code::GetKeyedAccessGrowMode(code->extra_ic_state()) == 145 ALLOW_JSARRAY_GROWTH; 146 return code->is_keyed_store_stub() && 147 !allow_growth && 148 *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) && 149 *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic_Strict) && 150 code->ic_state() == MEGAMORPHIC; 151 } 152 return false; 153 } 154 155 156 bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { 157 Handle<Object> value = GetInfo(expr->id()); 158 return value->IsMap() || value->IsSmi() || value->IsJSFunction(); 159 } 160 161 162 bool TypeFeedbackOracle::CallNewIsMonomorphic(CallNew* expr) { 163 Handle<Object> value = GetInfo(expr->id()); 164 return value->IsJSFunction(); 165 } 166 167 168 bool TypeFeedbackOracle::ObjectLiteralStoreIsMonomorphic( 169 ObjectLiteral::Property* prop) { 170 Handle<Object> map_or_code = GetInfo(prop->key()->id()); 171 return map_or_code->IsMap(); 172 } 173 174 175 bool TypeFeedbackOracle::IsForInFastCase(ForInStatement* stmt) { 176 Handle<Object> value = GetInfo(stmt->PrepareId()); 177 return value->IsSmi() && 178 Smi::cast(*value)->value() == TypeFeedbackCells::kForInFastCaseMarker; 179 } 180 181 182 Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { 183 ASSERT(LoadIsMonomorphicNormal(expr)); 184 Handle<Object> map_or_code = GetInfo(expr->id()); 185 if (map_or_code->IsCode()) { 186 Handle<Code> code = Handle<Code>::cast(map_or_code); 187 Map* first_map = code->FindFirstMap(); 188 ASSERT(first_map != NULL); 189 return CanRetainOtherContext(first_map, *global_context_) 190 ? Handle<Map>::null() 191 : Handle<Map>(first_map); 192 } 193 return Handle<Map>::cast(map_or_code); 194 } 195 196 197 Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) { 198 ASSERT(StoreIsMonomorphicNormal(expr)); 199 Handle<Object> map_or_code = GetInfo(expr->id()); 200 if (map_or_code->IsCode()) { 201 Handle<Code> code = Handle<Code>::cast(map_or_code); 202 Map* first_map = code->FindFirstMap(); 203 ASSERT(first_map != NULL); 204 return CanRetainOtherContext(first_map, *global_context_) 205 ? Handle<Map>::null() 206 : Handle<Map>(first_map); 207 } 208 return Handle<Map>::cast(map_or_code); 209 } 210 211 212 void TypeFeedbackOracle::LoadReceiverTypes(Property* expr, 213 Handle<String> name, 214 SmallMapList* types) { 215 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::LOAD_IC, NORMAL); 216 CollectReceiverTypes(expr->id(), name, flags, types); 217 } 218 219 220 void TypeFeedbackOracle::StoreReceiverTypes(Assignment* expr, 221 Handle<String> name, 222 SmallMapList* types) { 223 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::STORE_IC, NORMAL); 224 CollectReceiverTypes(expr->id(), name, flags, types); 225 } 226 227 228 void TypeFeedbackOracle::CallReceiverTypes(Call* expr, 229 Handle<String> name, 230 CallKind call_kind, 231 SmallMapList* types) { 232 int arity = expr->arguments()->length(); 233 234 // Note: Currently we do not take string extra ic data into account 235 // here. 236 Code::ExtraICState extra_ic_state = 237 CallIC::Contextual::encode(call_kind == CALL_AS_FUNCTION); 238 239 Code::Flags flags = Code::ComputeMonomorphicFlags(Code::CALL_IC, 240 NORMAL, 241 extra_ic_state, 242 OWN_MAP, 243 arity); 244 CollectReceiverTypes(expr->id(), name, flags, types); 245 } 246 247 248 CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) { 249 Handle<Object> value = GetInfo(expr->id()); 250 if (!value->IsSmi()) return RECEIVER_MAP_CHECK; 251 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value()); 252 ASSERT(check != RECEIVER_MAP_CHECK); 253 return check; 254 } 255 256 257 Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck( 258 CheckType check) { 259 JSFunction* function = NULL; 260 switch (check) { 261 case RECEIVER_MAP_CHECK: 262 UNREACHABLE(); 263 break; 264 case STRING_CHECK: 265 function = global_context_->string_function(); 266 break; 267 case NUMBER_CHECK: 268 function = global_context_->number_function(); 269 break; 270 case BOOLEAN_CHECK: 271 function = global_context_->boolean_function(); 272 break; 273 } 274 ASSERT(function != NULL); 275 return Handle<JSObject>(JSObject::cast(function->instance_prototype())); 276 } 277 278 279 Handle<JSFunction> TypeFeedbackOracle::GetCallTarget(Call* expr) { 280 return Handle<JSFunction>::cast(GetInfo(expr->id())); 281 } 282 283 284 Handle<JSFunction> TypeFeedbackOracle::GetCallNewTarget(CallNew* expr) { 285 return Handle<JSFunction>::cast(GetInfo(expr->id())); 286 } 287 288 289 Handle<Map> TypeFeedbackOracle::GetObjectLiteralStoreMap( 290 ObjectLiteral::Property* prop) { 291 ASSERT(ObjectLiteralStoreIsMonomorphic(prop)); 292 return Handle<Map>::cast(GetInfo(prop->key()->id())); 293 } 294 295 296 bool TypeFeedbackOracle::LoadIsBuiltin(Property* expr, Builtins::Name id) { 297 return *GetInfo(expr->id()) == 298 isolate_->builtins()->builtin(id); 299 } 300 301 302 TypeInfo TypeFeedbackOracle::CompareType(CompareOperation* expr) { 303 Handle<Object> object = GetInfo(expr->id()); 304 TypeInfo unknown = TypeInfo::Unknown(); 305 if (!object->IsCode()) return unknown; 306 Handle<Code> code = Handle<Code>::cast(object); 307 if (!code->is_compare_ic_stub()) return unknown; 308 309 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); 310 switch (state) { 311 case CompareIC::UNINITIALIZED: 312 // Uninitialized means never executed. 313 return TypeInfo::Uninitialized(); 314 case CompareIC::SMIS: 315 return TypeInfo::Smi(); 316 case CompareIC::HEAP_NUMBERS: 317 return TypeInfo::Number(); 318 case CompareIC::SYMBOLS: 319 case CompareIC::STRINGS: 320 return TypeInfo::String(); 321 case CompareIC::OBJECTS: 322 case CompareIC::KNOWN_OBJECTS: 323 // TODO(kasperl): We really need a type for JS objects here. 324 return TypeInfo::NonPrimitive(); 325 case CompareIC::GENERIC: 326 default: 327 return unknown; 328 } 329 } 330 331 332 bool TypeFeedbackOracle::IsSymbolCompare(CompareOperation* expr) { 333 Handle<Object> object = GetInfo(expr->id()); 334 if (!object->IsCode()) return false; 335 Handle<Code> code = Handle<Code>::cast(object); 336 if (!code->is_compare_ic_stub()) return false; 337 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); 338 return state == CompareIC::SYMBOLS; 339 } 340 341 342 Handle<Map> TypeFeedbackOracle::GetCompareMap(CompareOperation* expr) { 343 Handle<Object> object = GetInfo(expr->id()); 344 if (!object->IsCode()) return Handle<Map>::null(); 345 Handle<Code> code = Handle<Code>::cast(object); 346 if (!code->is_compare_ic_stub()) return Handle<Map>::null(); 347 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); 348 if (state != CompareIC::KNOWN_OBJECTS) { 349 return Handle<Map>::null(); 350 } 351 Map* first_map = code->FindFirstMap(); 352 ASSERT(first_map != NULL); 353 return CanRetainOtherContext(first_map, *global_context_) 354 ? Handle<Map>::null() 355 : Handle<Map>(first_map); 356 } 357 358 359 TypeInfo TypeFeedbackOracle::UnaryType(UnaryOperation* expr) { 360 Handle<Object> object = GetInfo(expr->id()); 361 TypeInfo unknown = TypeInfo::Unknown(); 362 if (!object->IsCode()) return unknown; 363 Handle<Code> code = Handle<Code>::cast(object); 364 ASSERT(code->is_unary_op_stub()); 365 UnaryOpIC::TypeInfo type = static_cast<UnaryOpIC::TypeInfo>( 366 code->unary_op_type()); 367 switch (type) { 368 case UnaryOpIC::SMI: 369 return TypeInfo::Smi(); 370 case UnaryOpIC::HEAP_NUMBER: 371 return TypeInfo::Double(); 372 default: 373 return unknown; 374 } 375 } 376 377 378 TypeInfo TypeFeedbackOracle::BinaryType(BinaryOperation* expr) { 379 Handle<Object> object = GetInfo(expr->id()); 380 TypeInfo unknown = TypeInfo::Unknown(); 381 if (!object->IsCode()) return unknown; 382 Handle<Code> code = Handle<Code>::cast(object); 383 if (code->is_binary_op_stub()) { 384 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( 385 code->binary_op_type()); 386 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>( 387 code->binary_op_result_type()); 388 389 switch (type) { 390 case BinaryOpIC::UNINITIALIZED: 391 // Uninitialized means never executed. 392 return TypeInfo::Uninitialized(); 393 case BinaryOpIC::SMI: 394 switch (result_type) { 395 case BinaryOpIC::UNINITIALIZED: 396 if (expr->op() == Token::DIV) { 397 return TypeInfo::Double(); 398 } 399 return TypeInfo::Smi(); 400 case BinaryOpIC::SMI: 401 return TypeInfo::Smi(); 402 case BinaryOpIC::INT32: 403 return TypeInfo::Integer32(); 404 case BinaryOpIC::HEAP_NUMBER: 405 return TypeInfo::Double(); 406 default: 407 return unknown; 408 } 409 case BinaryOpIC::INT32: 410 if (expr->op() == Token::DIV || 411 result_type == BinaryOpIC::HEAP_NUMBER) { 412 return TypeInfo::Double(); 413 } 414 return TypeInfo::Integer32(); 415 case BinaryOpIC::HEAP_NUMBER: 416 return TypeInfo::Double(); 417 case BinaryOpIC::BOTH_STRING: 418 return TypeInfo::String(); 419 case BinaryOpIC::STRING: 420 case BinaryOpIC::GENERIC: 421 return unknown; 422 default: 423 return unknown; 424 } 425 } 426 return unknown; 427 } 428 429 430 TypeInfo TypeFeedbackOracle::SwitchType(CaseClause* clause) { 431 Handle<Object> object = GetInfo(clause->CompareId()); 432 TypeInfo unknown = TypeInfo::Unknown(); 433 if (!object->IsCode()) return unknown; 434 Handle<Code> code = Handle<Code>::cast(object); 435 if (!code->is_compare_ic_stub()) return unknown; 436 437 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); 438 switch (state) { 439 case CompareIC::UNINITIALIZED: 440 // Uninitialized means never executed. 441 // TODO(fschneider): Introduce a separate value for never-executed ICs. 442 return unknown; 443 case CompareIC::SMIS: 444 return TypeInfo::Smi(); 445 case CompareIC::STRINGS: 446 return TypeInfo::String(); 447 case CompareIC::SYMBOLS: 448 return TypeInfo::Symbol(); 449 case CompareIC::HEAP_NUMBERS: 450 return TypeInfo::Number(); 451 case CompareIC::OBJECTS: 452 case CompareIC::KNOWN_OBJECTS: 453 // TODO(kasperl): We really need a type for JS objects here. 454 return TypeInfo::NonPrimitive(); 455 case CompareIC::GENERIC: 456 default: 457 return unknown; 458 } 459 } 460 461 462 TypeInfo TypeFeedbackOracle::IncrementType(CountOperation* expr) { 463 Handle<Object> object = GetInfo(expr->CountId()); 464 TypeInfo unknown = TypeInfo::Unknown(); 465 if (!object->IsCode()) return unknown; 466 Handle<Code> code = Handle<Code>::cast(object); 467 if (!code->is_binary_op_stub()) return unknown; 468 469 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( 470 code->binary_op_type()); 471 switch (type) { 472 case BinaryOpIC::UNINITIALIZED: 473 case BinaryOpIC::SMI: 474 return TypeInfo::Smi(); 475 case BinaryOpIC::INT32: 476 return TypeInfo::Integer32(); 477 case BinaryOpIC::HEAP_NUMBER: 478 return TypeInfo::Double(); 479 case BinaryOpIC::BOTH_STRING: 480 case BinaryOpIC::STRING: 481 case BinaryOpIC::GENERIC: 482 return unknown; 483 default: 484 return unknown; 485 } 486 UNREACHABLE(); 487 return unknown; 488 } 489 490 491 void TypeFeedbackOracle::CollectReceiverTypes(unsigned ast_id, 492 Handle<String> name, 493 Code::Flags flags, 494 SmallMapList* types) { 495 Handle<Object> object = GetInfo(ast_id); 496 if (object->IsUndefined() || object->IsSmi()) return; 497 498 if (*object == 499 isolate_->builtins()->builtin(Builtins::kStoreIC_GlobalProxy)) { 500 // TODO(fschneider): We could collect the maps and signal that 501 // we need a generic store (or load) here. 502 ASSERT(Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC); 503 } else if (object->IsMap()) { 504 types->Add(Handle<Map>::cast(object)); 505 } else if (FLAG_collect_megamorphic_maps_from_stub_cache && 506 Handle<Code>::cast(object)->ic_state() == MEGAMORPHIC) { 507 types->Reserve(4); 508 ASSERT(object->IsCode()); 509 isolate_->stub_cache()->CollectMatchingMaps(types, 510 *name, 511 flags, 512 global_context_); 513 } 514 } 515 516 517 // Check if a map originates from a given global context. We use this 518 // information to filter out maps from different context to avoid 519 // retaining objects from different tabs in Chrome via optimized code. 520 bool TypeFeedbackOracle::CanRetainOtherContext(Map* map, 521 Context* global_context) { 522 Object* constructor = NULL; 523 while (!map->prototype()->IsNull()) { 524 constructor = map->constructor(); 525 if (!constructor->IsNull()) { 526 // If the constructor is not null or a JSFunction, we have to 527 // conservatively assume that it may retain a global context. 528 if (!constructor->IsJSFunction()) return true; 529 // Check if the constructor directly references a foreign context. 530 if (CanRetainOtherContext(JSFunction::cast(constructor), 531 global_context)) { 532 return true; 533 } 534 } 535 map = HeapObject::cast(map->prototype())->map(); 536 } 537 constructor = map->constructor(); 538 if (constructor->IsNull()) return false; 539 JSFunction* function = JSFunction::cast(constructor); 540 return CanRetainOtherContext(function, global_context); 541 } 542 543 544 bool TypeFeedbackOracle::CanRetainOtherContext(JSFunction* function, 545 Context* global_context) { 546 return function->context()->global() != global_context->global() 547 && function->context()->global() != global_context->builtins(); 548 } 549 550 551 static void AddMapIfMissing(Handle<Map> map, SmallMapList* list) { 552 for (int i = 0; i < list->length(); ++i) { 553 if (list->at(i).is_identical_to(map)) return; 554 } 555 list->Add(map); 556 } 557 558 559 void TypeFeedbackOracle::CollectKeyedReceiverTypes(unsigned ast_id, 560 SmallMapList* types) { 561 Handle<Object> object = GetInfo(ast_id); 562 if (!object->IsCode()) return; 563 Handle<Code> code = Handle<Code>::cast(object); 564 if (code->kind() == Code::KEYED_LOAD_IC || 565 code->kind() == Code::KEYED_STORE_IC) { 566 AssertNoAllocation no_allocation; 567 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); 568 for (RelocIterator it(*code, mask); !it.done(); it.next()) { 569 RelocInfo* info = it.rinfo(); 570 Object* object = info->target_object(); 571 if (object->IsMap()) { 572 Map* map = Map::cast(object); 573 if (!CanRetainOtherContext(map, *global_context_)) { 574 AddMapIfMissing(Handle<Map>(map), types); 575 } 576 } 577 } 578 } 579 } 580 581 582 byte TypeFeedbackOracle::ToBooleanTypes(unsigned ast_id) { 583 Handle<Object> object = GetInfo(ast_id); 584 return object->IsCode() ? Handle<Code>::cast(object)->to_boolean_state() : 0; 585 } 586 587 588 // Things are a bit tricky here: The iterator for the RelocInfos and the infos 589 // themselves are not GC-safe, so we first get all infos, then we create the 590 // dictionary (possibly triggering GC), and finally we relocate the collected 591 // infos before we process them. 592 void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) { 593 AssertNoAllocation no_allocation; 594 ZoneList<RelocInfo> infos(16); 595 HandleScope scope; 596 GetRelocInfos(code, &infos); 597 CreateDictionary(code, &infos); 598 ProcessRelocInfos(&infos); 599 ProcessTypeFeedbackCells(code); 600 // Allocate handle in the parent scope. 601 dictionary_ = scope.CloseAndEscape(dictionary_); 602 } 603 604 605 void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code, 606 ZoneList<RelocInfo>* infos) { 607 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); 608 for (RelocIterator it(*code, mask); !it.done(); it.next()) { 609 infos->Add(*it.rinfo()); 610 } 611 } 612 613 614 void TypeFeedbackOracle::CreateDictionary(Handle<Code> code, 615 ZoneList<RelocInfo>* infos) { 616 DisableAssertNoAllocation allocation_allowed; 617 int cell_count = code->type_feedback_info()->IsTypeFeedbackInfo() 618 ? TypeFeedbackInfo::cast(code->type_feedback_info())-> 619 type_feedback_cells()->CellCount() 620 : 0; 621 int length = infos->length() + cell_count; 622 byte* old_start = code->instruction_start(); 623 dictionary_ = FACTORY->NewUnseededNumberDictionary(length); 624 byte* new_start = code->instruction_start(); 625 RelocateRelocInfos(infos, old_start, new_start); 626 } 627 628 629 void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos, 630 byte* old_start, 631 byte* new_start) { 632 for (int i = 0; i < infos->length(); i++) { 633 RelocInfo* info = &(*infos)[i]; 634 info->set_pc(new_start + (info->pc() - old_start)); 635 } 636 } 637 638 639 void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) { 640 for (int i = 0; i < infos->length(); i++) { 641 RelocInfo reloc_entry = (*infos)[i]; 642 Address target_address = reloc_entry.target_address(); 643 unsigned ast_id = static_cast<unsigned>((*infos)[i].data()); 644 Code* target = Code::GetCodeFromTargetAddress(target_address); 645 switch (target->kind()) { 646 case Code::LOAD_IC: 647 case Code::STORE_IC: 648 case Code::CALL_IC: 649 case Code::KEYED_CALL_IC: 650 if (target->ic_state() == MONOMORPHIC) { 651 if (target->kind() == Code::CALL_IC && 652 target->check_type() != RECEIVER_MAP_CHECK) { 653 SetInfo(ast_id, Smi::FromInt(target->check_type())); 654 } else { 655 Object* map = target->FindFirstMap(); 656 if (map == NULL) { 657 SetInfo(ast_id, static_cast<Object*>(target)); 658 } else if (!CanRetainOtherContext(Map::cast(map), 659 *global_context_)) { 660 SetInfo(ast_id, map); 661 } 662 } 663 } else { 664 SetInfo(ast_id, target); 665 } 666 break; 667 668 case Code::KEYED_LOAD_IC: 669 case Code::KEYED_STORE_IC: 670 if (target->ic_state() == MONOMORPHIC || 671 target->ic_state() == MEGAMORPHIC) { 672 SetInfo(ast_id, target); 673 } 674 break; 675 676 case Code::UNARY_OP_IC: 677 case Code::BINARY_OP_IC: 678 case Code::COMPARE_IC: 679 case Code::TO_BOOLEAN_IC: 680 SetInfo(ast_id, target); 681 break; 682 683 default: 684 break; 685 } 686 } 687 } 688 689 690 void TypeFeedbackOracle::ProcessTypeFeedbackCells(Handle<Code> code) { 691 Object* raw_info = code->type_feedback_info(); 692 if (!raw_info->IsTypeFeedbackInfo()) return; 693 Handle<TypeFeedbackCells> cache( 694 TypeFeedbackInfo::cast(raw_info)->type_feedback_cells()); 695 for (int i = 0; i < cache->CellCount(); i++) { 696 unsigned ast_id = cache->AstId(i)->value(); 697 Object* value = cache->Cell(i)->value(); 698 if (value->IsSmi() || 699 (value->IsJSFunction() && 700 !CanRetainOtherContext(JSFunction::cast(value), 701 *global_context_))) { 702 SetInfo(ast_id, value); 703 } 704 } 705 } 706 707 708 void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) { 709 ASSERT(dictionary_->FindEntry(ast_id) == UnseededNumberDictionary::kNotFound); 710 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target); 711 USE(maybe_result); 712 #ifdef DEBUG 713 Object* result = NULL; 714 // Dictionary has been allocated with sufficient size for all elements. 715 ASSERT(maybe_result->ToObject(&result)); 716 ASSERT(*dictionary_ == result); 717 #endif 718 } 719 720 } } // namespace v8::internal 721