| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| (...skipping 10 matching lines...) Expand all Loading... |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT | 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | 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. | 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 | 27 |
| 28 #include "v8.h" | 28 #include "v8.h" |
| 29 | 29 |
| 30 #include "ast.h" | 30 #include "ast.h" |
| 31 #include "code-stubs.h" |
| 31 #include "compiler.h" | 32 #include "compiler.h" |
| 32 #include "ic.h" | 33 #include "ic.h" |
| 33 #include "macro-assembler.h" | 34 #include "macro-assembler.h" |
| 34 #include "stub-cache.h" | 35 #include "stub-cache.h" |
| 35 #include "type-info.h" | 36 #include "type-info.h" |
| 36 | 37 |
| 37 #include "ic-inl.h" | 38 #include "ic-inl.h" |
| 38 #include "objects-inl.h" | 39 #include "objects-inl.h" |
| 39 | 40 |
| 40 namespace v8 { | 41 namespace v8 { |
| (...skipping 13 matching lines...) Expand all Loading... |
| 54 } else { | 55 } else { |
| 55 info = TypeInfo::Unknown(); | 56 info = TypeInfo::Unknown(); |
| 56 } | 57 } |
| 57 return info; | 58 return info; |
| 58 } | 59 } |
| 59 | 60 |
| 60 | 61 |
| 61 TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code, | 62 TypeFeedbackOracle::TypeFeedbackOracle(Handle<Code> code, |
| 62 Handle<Context> global_context) { | 63 Handle<Context> global_context) { |
| 63 global_context_ = global_context; | 64 global_context_ = global_context; |
| 64 PopulateMap(code); | 65 BuildDictionary(code); |
| 65 ASSERT(reinterpret_cast<Address>(*dictionary_.location()) != kHandleZapValue); | 66 ASSERT(reinterpret_cast<Address>(*dictionary_.location()) != kHandleZapValue); |
| 66 } | 67 } |
| 67 | 68 |
| 68 | 69 |
| 69 Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) { | 70 Handle<Object> TypeFeedbackOracle::GetInfo(unsigned ast_id) { |
| 70 int entry = dictionary_->FindEntry(ast_id); | 71 int entry = dictionary_->FindEntry(ast_id); |
| 71 return entry != NumberDictionary::kNotFound | 72 return entry != NumberDictionary::kNotFound |
| 72 ? Handle<Object>(dictionary_->ValueAt(entry)) | 73 ? Handle<Object>(dictionary_->ValueAt(entry)) |
| 73 : Isolate::Current()->factory()->undefined_value(); | 74 : Isolate::Current()->factory()->undefined_value(); |
| 74 } | 75 } |
| 75 | 76 |
| 76 | 77 |
| 77 bool TypeFeedbackOracle::LoadIsMonomorphic(Property* expr) { | 78 bool TypeFeedbackOracle::LoadIsMonomorphicNormal(Property* expr) { |
| 78 Handle<Object> map_or_code(GetInfo(expr->id())); | 79 Handle<Object> map_or_code(GetInfo(expr->id())); |
| 79 if (map_or_code->IsMap()) return true; | 80 if (map_or_code->IsMap()) return true; |
| 80 if (map_or_code->IsCode()) { | 81 if (map_or_code->IsCode()) { |
| 81 Handle<Code> code = Handle<Code>::cast(map_or_code); | 82 Handle<Code> code = Handle<Code>::cast(map_or_code); |
| 82 return code->is_keyed_load_stub() && | 83 return code->is_keyed_load_stub() && |
| 83 code->ic_state() == MONOMORPHIC && | 84 code->ic_state() == MONOMORPHIC && |
| 85 Code::ExtractTypeFromFlags(code->flags()) == NORMAL && |
| 84 code->FindFirstMap() != NULL; | 86 code->FindFirstMap() != NULL; |
| 85 } | 87 } |
| 86 return false; | 88 return false; |
| 87 } | 89 } |
| 88 | 90 |
| 89 | 91 |
| 90 bool TypeFeedbackOracle::StoreIsMonomorphic(Expression* expr) { | 92 bool TypeFeedbackOracle::LoadIsMegamorphicWithTypeInfo(Property* expr) { |
| 93 Handle<Object> map_or_code(GetInfo(expr->id())); |
| 94 if (map_or_code->IsCode()) { |
| 95 Handle<Code> code = Handle<Code>::cast(map_or_code); |
| 96 Builtins* builtins = Isolate::Current()->builtins(); |
| 97 return code->is_keyed_load_stub() && |
| 98 *code != builtins->builtin(Builtins::kKeyedLoadIC_Generic) && |
| 99 code->ic_state() == MEGAMORPHIC; |
| 100 } |
| 101 return false; |
| 102 } |
| 103 |
| 104 |
| 105 bool TypeFeedbackOracle::StoreIsMonomorphicNormal(Expression* expr) { |
| 91 Handle<Object> map_or_code(GetInfo(expr->id())); | 106 Handle<Object> map_or_code(GetInfo(expr->id())); |
| 92 if (map_or_code->IsMap()) return true; | 107 if (map_or_code->IsMap()) return true; |
| 93 if (map_or_code->IsCode()) { | 108 if (map_or_code->IsCode()) { |
| 94 Handle<Code> code = Handle<Code>::cast(map_or_code); | 109 Handle<Code> code = Handle<Code>::cast(map_or_code); |
| 95 return code->is_keyed_store_stub() && | 110 return code->is_keyed_store_stub() && |
| 96 code->ic_state() == MONOMORPHIC; | 111 code->ic_state() == MONOMORPHIC && |
| 112 Code::ExtractTypeFromFlags(code->flags()) == NORMAL; |
| 113 } |
| 114 return false; |
| 115 } |
| 116 |
| 117 |
| 118 bool TypeFeedbackOracle::StoreIsMegamorphicWithTypeInfo(Expression* expr) { |
| 119 Handle<Object> map_or_code(GetInfo(expr->id())); |
| 120 if (map_or_code->IsCode()) { |
| 121 Handle<Code> code = Handle<Code>::cast(map_or_code); |
| 122 Builtins* builtins = Isolate::Current()->builtins(); |
| 123 return code->is_keyed_store_stub() && |
| 124 *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic) && |
| 125 *code != builtins->builtin(Builtins::kKeyedStoreIC_Generic_Strict) && |
| 126 code->ic_state() == MEGAMORPHIC; |
| 97 } | 127 } |
| 98 return false; | 128 return false; |
| 99 } | 129 } |
| 100 | 130 |
| 101 | 131 |
| 102 bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { | 132 bool TypeFeedbackOracle::CallIsMonomorphic(Call* expr) { |
| 103 Handle<Object> value = GetInfo(expr->id()); | 133 Handle<Object> value = GetInfo(expr->id()); |
| 104 return value->IsMap() || value->IsSmi(); | 134 return value->IsMap() || value->IsSmi(); |
| 105 } | 135 } |
| 106 | 136 |
| 107 | 137 |
| 108 Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { | 138 Handle<Map> TypeFeedbackOracle::LoadMonomorphicReceiverType(Property* expr) { |
| 109 ASSERT(LoadIsMonomorphic(expr)); | 139 ASSERT(LoadIsMonomorphicNormal(expr)); |
| 110 Handle<Object> map_or_code(GetInfo(expr->id())); | 140 Handle<Object> map_or_code(GetInfo(expr->id())); |
| 111 if (map_or_code->IsCode()) { | 141 if (map_or_code->IsCode()) { |
| 112 Handle<Code> code = Handle<Code>::cast(map_or_code); | 142 Handle<Code> code = Handle<Code>::cast(map_or_code); |
| 113 Map* first_map = code->FindFirstMap(); | 143 Map* first_map = code->FindFirstMap(); |
| 114 ASSERT(first_map != NULL); | 144 ASSERT(first_map != NULL); |
| 115 return Handle<Map>(first_map); | 145 return Handle<Map>(first_map); |
| 116 } | 146 } |
| 117 return Handle<Map>::cast(map_or_code); | 147 return Handle<Map>::cast(map_or_code); |
| 118 } | 148 } |
| 119 | 149 |
| 120 | 150 |
| 121 Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) { | 151 Handle<Map> TypeFeedbackOracle::StoreMonomorphicReceiverType(Expression* expr) { |
| 122 ASSERT(StoreIsMonomorphic(expr)); | 152 ASSERT(StoreIsMonomorphicNormal(expr)); |
| 123 Handle<Object> map_or_code(GetInfo(expr->id())); | 153 Handle<Object> map_or_code(GetInfo(expr->id())); |
| 124 if (map_or_code->IsCode()) { | 154 if (map_or_code->IsCode()) { |
| 125 Handle<Code> code = Handle<Code>::cast(map_or_code); | 155 Handle<Code> code = Handle<Code>::cast(map_or_code); |
| 126 return Handle<Map>(code->FindFirstMap()); | 156 return Handle<Map>(code->FindFirstMap()); |
| 127 } | 157 } |
| 128 return Handle<Map>::cast(map_or_code); | 158 return Handle<Map>::cast(map_or_code); |
| 129 } | 159 } |
| 130 | 160 |
| 131 | 161 |
| 132 ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr, | 162 ZoneMapList* TypeFeedbackOracle::LoadReceiverTypes(Property* expr, |
| (...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 164 | 194 |
| 165 | 195 |
| 166 CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) { | 196 CheckType TypeFeedbackOracle::GetCallCheckType(Call* expr) { |
| 167 Handle<Object> value = GetInfo(expr->id()); | 197 Handle<Object> value = GetInfo(expr->id()); |
| 168 if (!value->IsSmi()) return RECEIVER_MAP_CHECK; | 198 if (!value->IsSmi()) return RECEIVER_MAP_CHECK; |
| 169 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value()); | 199 CheckType check = static_cast<CheckType>(Smi::cast(*value)->value()); |
| 170 ASSERT(check != RECEIVER_MAP_CHECK); | 200 ASSERT(check != RECEIVER_MAP_CHECK); |
| 171 return check; | 201 return check; |
| 172 } | 202 } |
| 173 | 203 |
| 174 ExternalArrayType TypeFeedbackOracle::GetKeyedLoadExternalArrayType( | |
| 175 Property* expr) { | |
| 176 Handle<Object> stub = GetInfo(expr->id()); | |
| 177 ASSERT(stub->IsCode()); | |
| 178 return Code::cast(*stub)->external_array_type(); | |
| 179 } | |
| 180 | |
| 181 ExternalArrayType TypeFeedbackOracle::GetKeyedStoreExternalArrayType( | |
| 182 Expression* expr) { | |
| 183 Handle<Object> stub = GetInfo(expr->id()); | |
| 184 ASSERT(stub->IsCode()); | |
| 185 return Code::cast(*stub)->external_array_type(); | |
| 186 } | |
| 187 | |
| 188 Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck( | 204 Handle<JSObject> TypeFeedbackOracle::GetPrototypeForPrimitiveCheck( |
| 189 CheckType check) { | 205 CheckType check) { |
| 190 JSFunction* function = NULL; | 206 JSFunction* function = NULL; |
| 191 switch (check) { | 207 switch (check) { |
| 192 case RECEIVER_MAP_CHECK: | 208 case RECEIVER_MAP_CHECK: |
| 193 UNREACHABLE(); | 209 UNREACHABLE(); |
| 194 break; | 210 break; |
| 195 case STRING_CHECK: | 211 case STRING_CHECK: |
| 196 function = global_context_->string_function(); | 212 function = global_context_->string_function(); |
| 197 break; | 213 break; |
| (...skipping 19 matching lines...) Expand all Loading... |
| 217 Handle<Object> object = GetInfo(expr->id()); | 233 Handle<Object> object = GetInfo(expr->id()); |
| 218 TypeInfo unknown = TypeInfo::Unknown(); | 234 TypeInfo unknown = TypeInfo::Unknown(); |
| 219 if (!object->IsCode()) return unknown; | 235 if (!object->IsCode()) return unknown; |
| 220 Handle<Code> code = Handle<Code>::cast(object); | 236 Handle<Code> code = Handle<Code>::cast(object); |
| 221 if (!code->is_compare_ic_stub()) return unknown; | 237 if (!code->is_compare_ic_stub()) return unknown; |
| 222 | 238 |
| 223 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); | 239 CompareIC::State state = static_cast<CompareIC::State>(code->compare_state()); |
| 224 switch (state) { | 240 switch (state) { |
| 225 case CompareIC::UNINITIALIZED: | 241 case CompareIC::UNINITIALIZED: |
| 226 // Uninitialized means never executed. | 242 // Uninitialized means never executed. |
| 227 // TODO(fschneider): Introduce a separate value for never-executed ICs. | 243 return TypeInfo::Uninitialized(); |
| 228 return unknown; | |
| 229 case CompareIC::SMIS: | 244 case CompareIC::SMIS: |
| 230 return TypeInfo::Smi(); | 245 return TypeInfo::Smi(); |
| 231 case CompareIC::HEAP_NUMBERS: | 246 case CompareIC::HEAP_NUMBERS: |
| 232 return TypeInfo::Number(); | 247 return TypeInfo::Number(); |
| 233 case CompareIC::SYMBOLS: | 248 case CompareIC::SYMBOLS: |
| 234 case CompareIC::STRINGS: | 249 case CompareIC::STRINGS: |
| 235 return TypeInfo::String(); | 250 return TypeInfo::String(); |
| 236 case CompareIC::OBJECTS: | 251 case CompareIC::OBJECTS: |
| 237 // TODO(kasperl): We really need a type for JS objects here. | 252 // TODO(kasperl): We really need a type for JS objects here. |
| 238 return TypeInfo::NonPrimitive(); | 253 return TypeInfo::NonPrimitive(); |
| (...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 279 Handle<Code> code = Handle<Code>::cast(object); | 294 Handle<Code> code = Handle<Code>::cast(object); |
| 280 if (code->is_binary_op_stub()) { | 295 if (code->is_binary_op_stub()) { |
| 281 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( | 296 BinaryOpIC::TypeInfo type = static_cast<BinaryOpIC::TypeInfo>( |
| 282 code->binary_op_type()); | 297 code->binary_op_type()); |
| 283 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>( | 298 BinaryOpIC::TypeInfo result_type = static_cast<BinaryOpIC::TypeInfo>( |
| 284 code->binary_op_result_type()); | 299 code->binary_op_result_type()); |
| 285 | 300 |
| 286 switch (type) { | 301 switch (type) { |
| 287 case BinaryOpIC::UNINITIALIZED: | 302 case BinaryOpIC::UNINITIALIZED: |
| 288 // Uninitialized means never executed. | 303 // Uninitialized means never executed. |
| 289 // TODO(fschneider): Introduce a separate value for never-executed ICs | 304 return TypeInfo::Uninitialized(); |
| 290 return unknown; | |
| 291 case BinaryOpIC::SMI: | 305 case BinaryOpIC::SMI: |
| 292 switch (result_type) { | 306 switch (result_type) { |
| 293 case BinaryOpIC::UNINITIALIZED: | 307 case BinaryOpIC::UNINITIALIZED: |
| 294 case BinaryOpIC::SMI: | 308 case BinaryOpIC::SMI: |
| 295 return TypeInfo::Smi(); | 309 return TypeInfo::Smi(); |
| 296 case BinaryOpIC::INT32: | 310 case BinaryOpIC::INT32: |
| 297 return TypeInfo::Integer32(); | 311 return TypeInfo::Integer32(); |
| 298 case BinaryOpIC::HEAP_NUMBER: | 312 case BinaryOpIC::HEAP_NUMBER: |
| 299 return TypeInfo::Double(); | 313 return TypeInfo::Double(); |
| 300 default: | 314 default: |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 397 ZoneMapList* types = new ZoneMapList(4); | 411 ZoneMapList* types = new ZoneMapList(4); |
| 398 ASSERT(object->IsCode()); | 412 ASSERT(object->IsCode()); |
| 399 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags); | 413 isolate->stub_cache()->CollectMatchingMaps(types, *name, flags); |
| 400 return types->length() > 0 ? types : NULL; | 414 return types->length() > 0 ? types : NULL; |
| 401 } else { | 415 } else { |
| 402 return NULL; | 416 return NULL; |
| 403 } | 417 } |
| 404 } | 418 } |
| 405 | 419 |
| 406 | 420 |
| 421 void TypeFeedbackOracle::CollectKeyedReceiverTypes( |
| 422 unsigned ast_id, |
| 423 ZoneMapList* types) { |
| 424 Handle<Object> object = GetInfo(ast_id); |
| 425 if (!object->IsCode()) return; |
| 426 Handle<Code> code = Handle<Code>::cast(object); |
| 427 if (code->kind() == Code::KEYED_LOAD_IC || |
| 428 code->kind() == Code::KEYED_STORE_IC) { |
| 429 AssertNoAllocation no_allocation; |
| 430 int mask = RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT); |
| 431 for (RelocIterator it(*code, mask); !it.done(); it.next()) { |
| 432 RelocInfo* info = it.rinfo(); |
| 433 Object* object = info->target_object(); |
| 434 if (object->IsMap()) { |
| 435 types->Add(Handle<Map>(Map::cast(object))); |
| 436 } |
| 437 } |
| 438 } |
| 439 } |
| 440 |
| 441 |
| 442 // Things are a bit tricky here: The iterator for the RelocInfos and the infos |
| 443 // themselves are not GC-safe, so we first get all infos, then we create the |
| 444 // dictionary (possibly triggering GC), and finally we relocate the collected |
| 445 // infos before we process them. |
| 446 void TypeFeedbackOracle::BuildDictionary(Handle<Code> code) { |
| 447 AssertNoAllocation no_allocation; |
| 448 ZoneList<RelocInfo> infos(16); |
| 449 HandleScope scope; |
| 450 GetRelocInfos(code, &infos); |
| 451 CreateDictionary(code, &infos); |
| 452 ProcessRelocInfos(&infos); |
| 453 // Allocate handle in the parent scope. |
| 454 dictionary_ = scope.CloseAndEscape(dictionary_); |
| 455 } |
| 456 |
| 457 |
| 458 void TypeFeedbackOracle::GetRelocInfos(Handle<Code> code, |
| 459 ZoneList<RelocInfo>* infos) { |
| 460 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); |
| 461 for (RelocIterator it(*code, mask); !it.done(); it.next()) { |
| 462 infos->Add(*it.rinfo()); |
| 463 } |
| 464 } |
| 465 |
| 466 |
| 467 void TypeFeedbackOracle::CreateDictionary(Handle<Code> code, |
| 468 ZoneList<RelocInfo>* infos) { |
| 469 DisableAssertNoAllocation allocation_allowed; |
| 470 byte* old_start = code->instruction_start(); |
| 471 dictionary_ = FACTORY->NewNumberDictionary(infos->length()); |
| 472 byte* new_start = code->instruction_start(); |
| 473 RelocateRelocInfos(infos, old_start, new_start); |
| 474 } |
| 475 |
| 476 |
| 477 void TypeFeedbackOracle::RelocateRelocInfos(ZoneList<RelocInfo>* infos, |
| 478 byte* old_start, |
| 479 byte* new_start) { |
| 480 for (int i = 0; i < infos->length(); i++) { |
| 481 RelocInfo* info = &(*infos)[i]; |
| 482 info->set_pc(new_start + (info->pc() - old_start)); |
| 483 } |
| 484 } |
| 485 |
| 486 |
| 487 void TypeFeedbackOracle::ProcessRelocInfos(ZoneList<RelocInfo>* infos) { |
| 488 for (int i = 0; i < infos->length(); i++) { |
| 489 unsigned ast_id = static_cast<unsigned>((*infos)[i].data()); |
| 490 Code* target = Code::GetCodeFromTargetAddress((*infos)[i].target_address()); |
| 491 ProcessTarget(ast_id, target); |
| 492 } |
| 493 } |
| 494 |
| 495 |
| 496 void TypeFeedbackOracle::ProcessTarget(unsigned ast_id, Code* target) { |
| 497 switch (target->kind()) { |
| 498 case Code::LOAD_IC: |
| 499 case Code::STORE_IC: |
| 500 case Code::CALL_IC: |
| 501 case Code::KEYED_CALL_IC: |
| 502 if (target->ic_state() == MONOMORPHIC) { |
| 503 if (target->kind() == Code::CALL_IC && |
| 504 target->check_type() != RECEIVER_MAP_CHECK) { |
| 505 SetInfo(ast_id, Smi::FromInt(target->check_type())); |
| 506 } else { |
| 507 Object* map = target->FindFirstMap(); |
| 508 SetInfo(ast_id, map == NULL ? static_cast<Object*>(target) : map); |
| 509 } |
| 510 } else if (target->ic_state() == MEGAMORPHIC) { |
| 511 SetInfo(ast_id, target); |
| 512 } |
| 513 break; |
| 514 |
| 515 case Code::KEYED_LOAD_IC: |
| 516 case Code::KEYED_STORE_IC: |
| 517 if (target->ic_state() == MONOMORPHIC || |
| 518 target->ic_state() == MEGAMORPHIC) { |
| 519 SetInfo(ast_id, target); |
| 520 } |
| 521 break; |
| 522 |
| 523 case Code::UNARY_OP_IC: |
| 524 case Code::BINARY_OP_IC: |
| 525 case Code::COMPARE_IC: |
| 526 SetInfo(ast_id, target); |
| 527 break; |
| 528 |
| 529 default: |
| 530 break; |
| 531 } |
| 532 } |
| 533 |
| 534 |
| 407 void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) { | 535 void TypeFeedbackOracle::SetInfo(unsigned ast_id, Object* target) { |
| 408 ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound); | 536 ASSERT(dictionary_->FindEntry(ast_id) == NumberDictionary::kNotFound); |
| 409 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target); | 537 MaybeObject* maybe_result = dictionary_->AtNumberPut(ast_id, target); |
| 410 USE(maybe_result); | 538 USE(maybe_result); |
| 411 #ifdef DEBUG | 539 #ifdef DEBUG |
| 412 Object* result; | 540 Object* result = NULL; |
| 413 // Dictionary has been allocated with sufficient size for all elements. | 541 // Dictionary has been allocated with sufficient size for all elements. |
| 414 ASSERT(maybe_result->ToObject(&result)); | 542 ASSERT(maybe_result->ToObject(&result)); |
| 415 ASSERT(*dictionary_ == result); | 543 ASSERT(*dictionary_ == result); |
| 416 #endif | 544 #endif |
| 417 } | 545 } |
| 418 | 546 |
| 419 | |
| 420 void TypeFeedbackOracle::PopulateMap(Handle<Code> code) { | |
| 421 Isolate* isolate = Isolate::Current(); | |
| 422 HandleScope scope(isolate); | |
| 423 | |
| 424 const int kInitialCapacity = 16; | |
| 425 List<int> code_positions(kInitialCapacity); | |
| 426 List<unsigned> ast_ids(kInitialCapacity); | |
| 427 CollectIds(*code, &code_positions, &ast_ids); | |
| 428 | |
| 429 ASSERT(dictionary_.is_null()); // Only initialize once. | |
| 430 dictionary_ = isolate->factory()->NewNumberDictionary( | |
| 431 code_positions.length()); | |
| 432 | |
| 433 const int length = code_positions.length(); | |
| 434 ASSERT(ast_ids.length() == length); | |
| 435 for (int i = 0; i < length; i++) { | |
| 436 AssertNoAllocation no_allocation; | |
| 437 RelocInfo info(code->instruction_start() + code_positions[i], | |
| 438 RelocInfo::CODE_TARGET, 0); | |
| 439 Code* target = Code::GetCodeFromTargetAddress(info.target_address()); | |
| 440 unsigned id = ast_ids[i]; | |
| 441 InlineCacheState state = target->ic_state(); | |
| 442 Code::Kind kind = target->kind(); | |
| 443 | |
| 444 if (kind == Code::BINARY_OP_IC || | |
| 445 kind == Code::UNARY_OP_IC || | |
| 446 kind == Code::COMPARE_IC) { | |
| 447 SetInfo(id, target); | |
| 448 } else if (state == MONOMORPHIC) { | |
| 449 if (kind == Code::KEYED_LOAD_IC || | |
| 450 kind == Code::KEYED_STORE_IC) { | |
| 451 SetInfo(id, target); | |
| 452 } else if (kind != Code::CALL_IC || | |
| 453 target->check_type() == RECEIVER_MAP_CHECK) { | |
| 454 Map* map = target->FindFirstMap(); | |
| 455 if (map == NULL) { | |
| 456 SetInfo(id, target); | |
| 457 } else { | |
| 458 SetInfo(id, map); | |
| 459 } | |
| 460 } else { | |
| 461 ASSERT(target->kind() == Code::CALL_IC); | |
| 462 CheckType check = target->check_type(); | |
| 463 ASSERT(check != RECEIVER_MAP_CHECK); | |
| 464 SetInfo(id, Smi::FromInt(check)); | |
| 465 } | |
| 466 } else if (state == MEGAMORPHIC) { | |
| 467 SetInfo(id, target); | |
| 468 } | |
| 469 } | |
| 470 // Allocate handle in the parent scope. | |
| 471 dictionary_ = scope.CloseAndEscape(dictionary_); | |
| 472 } | |
| 473 | |
| 474 | |
| 475 void TypeFeedbackOracle::CollectIds(Code* code, | |
| 476 List<int>* code_positions, | |
| 477 List<unsigned>* ast_ids) { | |
| 478 AssertNoAllocation no_allocation; | |
| 479 int mask = RelocInfo::ModeMask(RelocInfo::CODE_TARGET_WITH_ID); | |
| 480 for (RelocIterator it(code, mask); !it.done(); it.next()) { | |
| 481 RelocInfo* info = it.rinfo(); | |
| 482 ASSERT(RelocInfo::IsCodeTarget(info->rmode())); | |
| 483 Code* target = Code::GetCodeFromTargetAddress(info->target_address()); | |
| 484 if (target->is_inline_cache_stub()) { | |
| 485 InlineCacheState state = target->ic_state(); | |
| 486 Code::Kind kind = target->kind(); | |
| 487 if (kind == Code::BINARY_OP_IC) { | |
| 488 if (target->binary_op_type() == | |
| 489 BinaryOpIC::GENERIC) { | |
| 490 continue; | |
| 491 } | |
| 492 } else if (kind == Code::COMPARE_IC) { | |
| 493 if (target->compare_state() == CompareIC::GENERIC) continue; | |
| 494 } else { | |
| 495 if (state != MONOMORPHIC && state != MEGAMORPHIC) continue; | |
| 496 } | |
| 497 code_positions->Add( | |
| 498 static_cast<int>(info->pc() - code->instruction_start())); | |
| 499 ASSERT(ast_ids->length() == 0 || | |
| 500 (*ast_ids)[ast_ids->length()-1] != | |
| 501 static_cast<unsigned>(info->data())); | |
| 502 ast_ids->Add(static_cast<unsigned>(info->data())); | |
| 503 } | |
| 504 } | |
| 505 } | |
| 506 | |
| 507 } } // namespace v8::internal | 547 } } // namespace v8::internal |
| OLD | NEW |