Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 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/v8.h" |
| 6 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 7 | #include "src/ic/ic.h" |
| 8 | #include "src/ic/ic-state.h" |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 9 | #include "src/objects.h" |
| 10 | #include "src/type-feedback-vector-inl.h" |
| 11 | |
| 12 | namespace v8 { |
| 13 | namespace internal { |
| 14 | |
| 15 | // static |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 16 | TypeFeedbackVector::VectorICKind TypeFeedbackVector::FromCodeKind( |
| 17 | Code::Kind kind) { |
| 18 | switch (kind) { |
| 19 | case Code::CALL_IC: |
| 20 | return KindCallIC; |
| 21 | case Code::LOAD_IC: |
| 22 | return KindLoadIC; |
| 23 | case Code::KEYED_LOAD_IC: |
| 24 | return KindKeyedLoadIC; |
| 25 | default: |
| 26 | // Shouldn't get here. |
| 27 | UNREACHABLE(); |
| 28 | } |
| 29 | |
| 30 | return KindUnused; |
| 31 | } |
| 32 | |
| 33 | |
| 34 | // static |
| 35 | Code::Kind TypeFeedbackVector::FromVectorICKind(VectorICKind kind) { |
| 36 | switch (kind) { |
| 37 | case KindCallIC: |
| 38 | return Code::CALL_IC; |
| 39 | case KindLoadIC: |
| 40 | return Code::LOAD_IC; |
| 41 | case KindKeyedLoadIC: |
| 42 | return Code::KEYED_LOAD_IC; |
| 43 | case KindUnused: |
| 44 | break; |
| 45 | } |
| 46 | // Sentinel for no information. |
| 47 | return Code::NUMBER_OF_KINDS; |
| 48 | } |
| 49 | |
| 50 | |
| 51 | Code::Kind TypeFeedbackVector::GetKind(FeedbackVectorICSlot slot) const { |
| 52 | if (!FLAG_vector_ics) { |
| 53 | // We only have CALL_ICs |
| 54 | return Code::CALL_IC; |
| 55 | } |
| 56 | |
| 57 | int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); |
| 58 | int data = Smi::cast(get(index))->value(); |
| 59 | VectorICKind b = VectorICComputer::decode(data, slot.ToInt()); |
| 60 | return FromVectorICKind(b); |
| 61 | } |
| 62 | |
| 63 | |
| 64 | void TypeFeedbackVector::SetKind(FeedbackVectorICSlot slot, Code::Kind kind) { |
| 65 | if (!FLAG_vector_ics) { |
| 66 | // Nothing to do if we only have CALL_ICs |
| 67 | return; |
| 68 | } |
| 69 | |
| 70 | VectorICKind b = FromCodeKind(kind); |
| 71 | int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt()); |
| 72 | int data = Smi::cast(get(index))->value(); |
| 73 | int new_data = VectorICComputer::encode(data, slot.ToInt(), b); |
| 74 | set(index, Smi::FromInt(new_data)); |
| 75 | } |
| 76 | |
| 77 | |
| 78 | // static |
| 79 | Handle<TypeFeedbackVector> TypeFeedbackVector::Allocate( |
| 80 | Isolate* isolate, const FeedbackVectorSpec& spec) { |
| 81 | const int slot_count = spec.slots(); |
| 82 | const int ic_slot_count = spec.ic_slots(); |
| 83 | const int index_count = |
| 84 | FLAG_vector_ics ? VectorICComputer::word_count(ic_slot_count) : 0; |
| 85 | const int length = |
| 86 | slot_count + ic_slot_count + index_count + kReservedIndexCount; |
| 87 | if (length == kReservedIndexCount) { |
| 88 | return Handle<TypeFeedbackVector>::cast( |
| 89 | isolate->factory()->empty_fixed_array()); |
| 90 | } |
| 91 | |
| 92 | Handle<FixedArray> array = isolate->factory()->NewFixedArray(length, TENURED); |
| 93 | if (ic_slot_count > 0) { |
| 94 | array->set(kFirstICSlotIndex, |
| 95 | Smi::FromInt(slot_count + index_count + kReservedIndexCount)); |
| 96 | } else { |
| 97 | array->set(kFirstICSlotIndex, Smi::FromInt(length)); |
| 98 | } |
| 99 | array->set(kWithTypesIndex, Smi::FromInt(0)); |
| 100 | array->set(kGenericCountIndex, Smi::FromInt(0)); |
| 101 | // Fill the indexes with zeros. |
| 102 | for (int i = 0; i < index_count; i++) { |
| 103 | array->set(kReservedIndexCount + i, Smi::FromInt(0)); |
| 104 | } |
| 105 | |
| 106 | // Ensure we can skip the write barrier |
| 107 | Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate); |
| 108 | DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel); |
| 109 | for (int i = kReservedIndexCount + index_count; i < length; i++) { |
| 110 | array->set(i, *uninitialized_sentinel, SKIP_WRITE_BARRIER); |
| 111 | } |
| 112 | |
| 113 | Handle<TypeFeedbackVector> vector = Handle<TypeFeedbackVector>::cast(array); |
| 114 | if (FLAG_vector_ics) { |
| 115 | for (int i = 0; i < ic_slot_count; i++) { |
| 116 | vector->SetKind(FeedbackVectorICSlot(i), spec.GetKind(i)); |
| 117 | } |
| 118 | } |
| 119 | return vector; |
| 120 | } |
| 121 | |
| 122 | |
| 123 | // static |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 124 | Handle<TypeFeedbackVector> TypeFeedbackVector::Copy( |
| 125 | Isolate* isolate, Handle<TypeFeedbackVector> vector) { |
| 126 | Handle<TypeFeedbackVector> result; |
| 127 | result = Handle<TypeFeedbackVector>::cast( |
| 128 | isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector))); |
| 129 | return result; |
| 130 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame^] | 131 | |
| 132 | |
| 133 | // This logic is copied from |
| 134 | // StaticMarkingVisitor<StaticVisitor>::VisitCodeTarget. |
| 135 | // TODO(mvstanton): with weak handling of all vector ics, this logic should |
| 136 | // actually be completely eliminated and we no longer need to clear the |
| 137 | // vector ICs. |
| 138 | static bool ClearLogic(Heap* heap, int ic_age, Code::Kind kind, |
| 139 | InlineCacheState state) { |
| 140 | if (FLAG_cleanup_code_caches_at_gc && |
| 141 | (kind == Code::CALL_IC || heap->flush_monomorphic_ics() || |
| 142 | // TODO(mvstanton): is this ic_age granular enough? it comes from |
| 143 | // the SharedFunctionInfo which may change on a different schedule |
| 144 | // than ic targets. |
| 145 | // ic_age != heap->global_ic_age() || |
| 146 | // is_invalidated_weak_stub || |
| 147 | heap->isolate()->serializer_enabled())) { |
| 148 | return true; |
| 149 | } |
| 150 | return false; |
| 151 | } |
| 152 | |
| 153 | |
| 154 | void TypeFeedbackVector::ClearSlots(SharedFunctionInfo* shared) { |
| 155 | int slots = Slots(); |
| 156 | Isolate* isolate = GetIsolate(); |
| 157 | Object* uninitialized_sentinel = |
| 158 | TypeFeedbackVector::RawUninitializedSentinel(isolate->heap()); |
| 159 | |
| 160 | for (int i = 0; i < slots; i++) { |
| 161 | FeedbackVectorSlot slot(i); |
| 162 | Object* obj = Get(slot); |
| 163 | if (obj->IsHeapObject()) { |
| 164 | InstanceType instance_type = |
| 165 | HeapObject::cast(obj)->map()->instance_type(); |
| 166 | // AllocationSites are exempt from clearing. They don't store Maps |
| 167 | // or Code pointers which can cause memory leaks if not cleared |
| 168 | // regularly. |
| 169 | if (instance_type != ALLOCATION_SITE_TYPE) { |
| 170 | Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER); |
| 171 | } |
| 172 | } |
| 173 | } |
| 174 | |
| 175 | slots = ICSlots(); |
| 176 | if (slots == 0) return; |
| 177 | |
| 178 | // Now clear vector-based ICs. |
| 179 | // Try and pass the containing code (the "host"). |
| 180 | Heap* heap = isolate->heap(); |
| 181 | Code* host = shared->code(); |
| 182 | // I'm not sure yet if this ic age is the correct one. |
| 183 | int ic_age = shared->ic_age(); |
| 184 | for (int i = 0; i < slots; i++) { |
| 185 | FeedbackVectorICSlot slot(i); |
| 186 | Object* obj = Get(slot); |
| 187 | if (obj != uninitialized_sentinel) { |
| 188 | Code::Kind kind = GetKind(slot); |
| 189 | if (kind == Code::CALL_IC) { |
| 190 | CallICNexus nexus(this, slot); |
| 191 | if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) { |
| 192 | nexus.Clear(host); |
| 193 | } |
| 194 | } else if (kind == Code::LOAD_IC) { |
| 195 | LoadICNexus nexus(this, slot); |
| 196 | if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) { |
| 197 | nexus.Clear(host); |
| 198 | } |
| 199 | } else if (kind == Code::KEYED_LOAD_IC) { |
| 200 | KeyedLoadICNexus nexus(this, slot); |
| 201 | if (ClearLogic(heap, ic_age, kind, nexus.StateFromFeedback())) { |
| 202 | nexus.Clear(host); |
| 203 | } |
| 204 | } |
| 205 | } |
| 206 | } |
| 207 | } |
| 208 | |
| 209 | |
| 210 | Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) { |
| 211 | Isolate* isolate = GetIsolate(); |
| 212 | Handle<Object> feedback = handle(GetFeedback(), isolate); |
| 213 | if (!feedback->IsFixedArray() || |
| 214 | FixedArray::cast(*feedback)->length() != length) { |
| 215 | Handle<FixedArray> array = isolate->factory()->NewFixedArray(length); |
| 216 | SetFeedback(*array); |
| 217 | return array; |
| 218 | } |
| 219 | return Handle<FixedArray>::cast(feedback); |
| 220 | } |
| 221 | |
| 222 | |
| 223 | void FeedbackNexus::InstallHandlers(int start_index, TypeHandleList* types, |
| 224 | CodeHandleList* handlers) { |
| 225 | Isolate* isolate = GetIsolate(); |
| 226 | Handle<FixedArray> array = handle(FixedArray::cast(GetFeedback()), isolate); |
| 227 | int receiver_count = types->length(); |
| 228 | for (int current = 0; current < receiver_count; ++current) { |
| 229 | Handle<HeapType> type = types->at(current); |
| 230 | Handle<Map> map = IC::TypeToMap(*type, isolate); |
| 231 | Handle<WeakCell> cell = Map::WeakCellForMap(map); |
| 232 | array->set(start_index + (current * 2), *cell); |
| 233 | array->set(start_index + (current * 2 + 1), *handlers->at(current)); |
| 234 | } |
| 235 | } |
| 236 | |
| 237 | |
| 238 | InlineCacheState LoadICNexus::StateFromFeedback() const { |
| 239 | Isolate* isolate = GetIsolate(); |
| 240 | Object* feedback = GetFeedback(); |
| 241 | if (feedback == *vector()->UninitializedSentinel(isolate)) { |
| 242 | return UNINITIALIZED; |
| 243 | } else if (feedback == *vector()->MegamorphicSentinel(isolate)) { |
| 244 | return MEGAMORPHIC; |
| 245 | } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) { |
| 246 | return PREMONOMORPHIC; |
| 247 | } else if (feedback->IsFixedArray()) { |
| 248 | // Determine state purely by our structure, don't check if the maps are |
| 249 | // cleared. |
| 250 | FixedArray* array = FixedArray::cast(feedback); |
| 251 | int length = array->length(); |
| 252 | DCHECK(length >= 2); |
| 253 | return length == 2 ? MONOMORPHIC : POLYMORPHIC; |
| 254 | } |
| 255 | |
| 256 | return UNINITIALIZED; |
| 257 | } |
| 258 | |
| 259 | |
| 260 | InlineCacheState KeyedLoadICNexus::StateFromFeedback() const { |
| 261 | Isolate* isolate = GetIsolate(); |
| 262 | Object* feedback = GetFeedback(); |
| 263 | if (feedback == *vector()->UninitializedSentinel(isolate)) { |
| 264 | return UNINITIALIZED; |
| 265 | } else if (feedback == *vector()->PremonomorphicSentinel(isolate)) { |
| 266 | return PREMONOMORPHIC; |
| 267 | } else if (feedback == *vector()->GenericSentinel(isolate)) { |
| 268 | return GENERIC; |
| 269 | } else if (feedback->IsFixedArray()) { |
| 270 | // Determine state purely by our structure, don't check if the maps are |
| 271 | // cleared. |
| 272 | FixedArray* array = FixedArray::cast(feedback); |
| 273 | int length = array->length(); |
| 274 | DCHECK(length >= 3); |
| 275 | return length == 3 ? MONOMORPHIC : POLYMORPHIC; |
| 276 | } |
| 277 | |
| 278 | return UNINITIALIZED; |
| 279 | } |
| 280 | |
| 281 | |
| 282 | InlineCacheState CallICNexus::StateFromFeedback() const { |
| 283 | Isolate* isolate = GetIsolate(); |
| 284 | Object* feedback = GetFeedback(); |
| 285 | |
| 286 | if (feedback == *vector()->MegamorphicSentinel(isolate)) { |
| 287 | return GENERIC; |
| 288 | } else if (feedback->IsAllocationSite() || feedback->IsJSFunction()) { |
| 289 | return MONOMORPHIC; |
| 290 | } |
| 291 | |
| 292 | CHECK(feedback == *vector()->UninitializedSentinel(isolate)); |
| 293 | return UNINITIALIZED; |
| 294 | } |
| 295 | |
| 296 | |
| 297 | void CallICNexus::Clear(Code* host) { CallIC::Clear(GetIsolate(), host, this); } |
| 298 | |
| 299 | |
| 300 | void CallICNexus::ConfigureGeneric() { |
| 301 | SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER); |
| 302 | } |
| 303 | |
| 304 | |
| 305 | void CallICNexus::ConfigureMonomorphicArray() { |
| 306 | Object* feedback = GetFeedback(); |
| 307 | if (!feedback->IsAllocationSite()) { |
| 308 | Handle<AllocationSite> new_site = |
| 309 | GetIsolate()->factory()->NewAllocationSite(); |
| 310 | SetFeedback(*new_site); |
| 311 | } |
| 312 | } |
| 313 | |
| 314 | |
| 315 | void CallICNexus::ConfigureUninitialized() { |
| 316 | SetFeedback(*vector()->UninitializedSentinel(GetIsolate()), |
| 317 | SKIP_WRITE_BARRIER); |
| 318 | } |
| 319 | |
| 320 | |
| 321 | void CallICNexus::ConfigureMonomorphic(Handle<JSFunction> function) { |
| 322 | SetFeedback(*function); |
| 323 | } |
| 324 | |
| 325 | |
| 326 | void KeyedLoadICNexus::ConfigureGeneric() { |
| 327 | SetFeedback(*vector()->GenericSentinel(GetIsolate()), SKIP_WRITE_BARRIER); |
| 328 | } |
| 329 | |
| 330 | |
| 331 | void LoadICNexus::ConfigureMegamorphic() { |
| 332 | SetFeedback(*vector()->MegamorphicSentinel(GetIsolate()), SKIP_WRITE_BARRIER); |
| 333 | } |
| 334 | |
| 335 | |
| 336 | void LoadICNexus::ConfigurePremonomorphic() { |
| 337 | SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()), |
| 338 | SKIP_WRITE_BARRIER); |
| 339 | } |
| 340 | |
| 341 | |
| 342 | void KeyedLoadICNexus::ConfigurePremonomorphic() { |
| 343 | SetFeedback(*vector()->PremonomorphicSentinel(GetIsolate()), |
| 344 | SKIP_WRITE_BARRIER); |
| 345 | } |
| 346 | |
| 347 | |
| 348 | void LoadICNexus::ConfigureMonomorphic(Handle<HeapType> type, |
| 349 | Handle<Code> handler) { |
| 350 | Handle<FixedArray> array = EnsureArrayOfSize(2); |
| 351 | Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate()); |
| 352 | Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); |
| 353 | array->set(0, *cell); |
| 354 | array->set(1, *handler); |
| 355 | } |
| 356 | |
| 357 | |
| 358 | void KeyedLoadICNexus::ConfigureMonomorphic(Handle<Name> name, |
| 359 | Handle<HeapType> type, |
| 360 | Handle<Code> handler) { |
| 361 | Handle<FixedArray> array = EnsureArrayOfSize(3); |
| 362 | Handle<Map> receiver_map = IC::TypeToMap(*type, GetIsolate()); |
| 363 | if (name.is_null()) { |
| 364 | array->set(0, Smi::FromInt(0)); |
| 365 | } else { |
| 366 | array->set(0, *name); |
| 367 | } |
| 368 | Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map); |
| 369 | array->set(1, *cell); |
| 370 | array->set(2, *handler); |
| 371 | } |
| 372 | |
| 373 | |
| 374 | void LoadICNexus::ConfigurePolymorphic(TypeHandleList* types, |
| 375 | CodeHandleList* handlers) { |
| 376 | int receiver_count = types->length(); |
| 377 | EnsureArrayOfSize(receiver_count * 2); |
| 378 | InstallHandlers(0, types, handlers); |
| 379 | } |
| 380 | |
| 381 | |
| 382 | void KeyedLoadICNexus::ConfigurePolymorphic(Handle<Name> name, |
| 383 | TypeHandleList* types, |
| 384 | CodeHandleList* handlers) { |
| 385 | int receiver_count = types->length(); |
| 386 | Handle<FixedArray> array = EnsureArrayOfSize(1 + receiver_count * 2); |
| 387 | if (name.is_null()) { |
| 388 | array->set(0, Smi::FromInt(0)); |
| 389 | } else { |
| 390 | array->set(0, *name); |
| 391 | } |
| 392 | InstallHandlers(1, types, handlers); |
| 393 | } |
| 394 | |
| 395 | |
| 396 | int FeedbackNexus::ExtractMaps(int start_index, MapHandleList* maps) const { |
| 397 | Isolate* isolate = GetIsolate(); |
| 398 | Object* feedback = GetFeedback(); |
| 399 | if (feedback->IsFixedArray()) { |
| 400 | int found = 0; |
| 401 | FixedArray* array = FixedArray::cast(feedback); |
| 402 | // The array should be of the form [<optional name>], then |
| 403 | // [map, handler, map, handler, ... ] |
| 404 | DCHECK(array->length() >= (2 + start_index)); |
| 405 | for (int i = start_index; i < array->length(); i += 2) { |
| 406 | WeakCell* cell = WeakCell::cast(array->get(i)); |
| 407 | if (!cell->cleared()) { |
| 408 | Map* map = Map::cast(cell->value()); |
| 409 | maps->Add(handle(map, isolate)); |
| 410 | found++; |
| 411 | } |
| 412 | } |
| 413 | return found; |
| 414 | } |
| 415 | |
| 416 | return 0; |
| 417 | } |
| 418 | |
| 419 | |
| 420 | MaybeHandle<Code> FeedbackNexus::FindHandlerForMap(int start_index, |
| 421 | Handle<Map> map) const { |
| 422 | Object* feedback = GetFeedback(); |
| 423 | if (feedback->IsFixedArray()) { |
| 424 | FixedArray* array = FixedArray::cast(feedback); |
| 425 | for (int i = start_index; i < array->length(); i += 2) { |
| 426 | WeakCell* cell = WeakCell::cast(array->get(i)); |
| 427 | if (!cell->cleared()) { |
| 428 | Map* array_map = Map::cast(cell->value()); |
| 429 | if (array_map == *map) { |
| 430 | Code* code = Code::cast(array->get(i + 1)); |
| 431 | DCHECK(code->kind() == Code::HANDLER); |
| 432 | return handle(code); |
| 433 | } |
| 434 | } |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | return MaybeHandle<Code>(); |
| 439 | } |
| 440 | |
| 441 | |
| 442 | bool FeedbackNexus::FindHandlers(int start_index, CodeHandleList* code_list, |
| 443 | int length) const { |
| 444 | Object* feedback = GetFeedback(); |
| 445 | int count = 0; |
| 446 | if (feedback->IsFixedArray()) { |
| 447 | FixedArray* array = FixedArray::cast(feedback); |
| 448 | // The array should be of the form [<optional name>], then |
| 449 | // [map, handler, map, handler, ... ]. Be sure to skip handlers whose maps |
| 450 | // have been cleared. |
| 451 | DCHECK(array->length() >= (2 + start_index)); |
| 452 | for (int i = start_index; i < array->length(); i += 2) { |
| 453 | WeakCell* cell = WeakCell::cast(array->get(i)); |
| 454 | if (!cell->cleared()) { |
| 455 | Code* code = Code::cast(array->get(i + 1)); |
| 456 | DCHECK(code->kind() == Code::HANDLER); |
| 457 | code_list->Add(handle(code)); |
| 458 | count++; |
| 459 | } |
| 460 | } |
| 461 | } |
| 462 | return count == length; |
| 463 | } |
| 464 | |
| 465 | |
| 466 | int LoadICNexus::ExtractMaps(MapHandleList* maps) const { |
| 467 | return FeedbackNexus::ExtractMaps(0, maps); |
| 468 | } |
| 469 | |
| 470 | |
| 471 | void LoadICNexus::Clear(Code* host) { LoadIC::Clear(GetIsolate(), host, this); } |
| 472 | |
| 473 | |
| 474 | void KeyedLoadICNexus::Clear(Code* host) { |
| 475 | KeyedLoadIC::Clear(GetIsolate(), host, this); |
| 476 | } |
| 477 | |
| 478 | |
| 479 | int KeyedLoadICNexus::ExtractMaps(MapHandleList* maps) const { |
| 480 | return FeedbackNexus::ExtractMaps(1, maps); |
| 481 | } |
| 482 | |
| 483 | |
| 484 | MaybeHandle<Code> LoadICNexus::FindHandlerForMap(Handle<Map> map) const { |
| 485 | return FeedbackNexus::FindHandlerForMap(0, map); |
| 486 | } |
| 487 | |
| 488 | |
| 489 | MaybeHandle<Code> KeyedLoadICNexus::FindHandlerForMap(Handle<Map> map) const { |
| 490 | return FeedbackNexus::FindHandlerForMap(1, map); |
| 491 | } |
| 492 | |
| 493 | |
| 494 | bool LoadICNexus::FindHandlers(CodeHandleList* code_list, int length) const { |
| 495 | return FeedbackNexus::FindHandlers(0, code_list, length); |
| 496 | } |
| 497 | |
| 498 | |
| 499 | bool KeyedLoadICNexus::FindHandlers(CodeHandleList* code_list, |
| 500 | int length) const { |
| 501 | return FeedbackNexus::FindHandlers(1, code_list, length); |
| 502 | } |
| 503 | |
| 504 | |
| 505 | Name* KeyedLoadICNexus::FindFirstName() const { |
| 506 | Object* feedback = GetFeedback(); |
| 507 | if (feedback->IsFixedArray()) { |
| 508 | FixedArray* array = FixedArray::cast(feedback); |
| 509 | DCHECK(array->length() >= 3); |
| 510 | Object* name = array->get(0); |
| 511 | if (name->IsName()) return Name::cast(name); |
| 512 | } |
| 513 | return NULL; |
| 514 | } |
Ben Murdoch | b8a8cc1 | 2014-11-26 15:28:44 +0000 | [diff] [blame] | 515 | } |
| 516 | } // namespace v8::internal |