feedback-vector.cc 33.8 KB
Newer Older
1 2 3 4
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
#include "src/feedback-vector.h"
6
#include "src/code-stubs.h"
7
#include "src/feedback-vector-inl.h"
8
#include "src/ic/ic-inl.h"
9
#include "src/ic/ic-state.h"
10 11 12 13 14
#include "src/objects.h"

namespace v8 {
namespace internal {

15 16 17 18 19 20 21 22 23
bool FeedbackVectorSpec::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  if (slots() <= slot.ToInt()) {
    return false;
  }
  return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
}

24
static bool IsPropertyNameFeedback(Object* feedback) {
25 26 27 28 29 30 31
  if (feedback->IsString()) return true;
  if (!feedback->IsSymbol()) return false;
  Symbol* symbol = Symbol::cast(feedback);
  Heap* heap = symbol->GetHeap();
  return symbol != heap->uninitialized_symbol() &&
         symbol != heap->premonomorphic_symbol() &&
         symbol != heap->megamorphic_symbol();
32 33
}

34
std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
35
  return os << FeedbackMetadata::Kind2String(kind);
36 37
}

38
FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
39 40
  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
  int data = Smi::cast(get(index))->value();
41
  return VectorICComputer::decode(data, slot.ToInt());
42 43
}

44
void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
45 46
  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
  int data = Smi::cast(get(index))->value();
47
  int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
48 49 50
  set(index, Smi::FromInt(new_data));
}

51
template Handle<FeedbackMetadata> FeedbackMetadata::New(
52
    Isolate* isolate, const StaticFeedbackVectorSpec* spec);
53
template Handle<FeedbackMetadata> FeedbackMetadata::New(
54
    Isolate* isolate, const FeedbackVectorSpec* spec);
55

56
// static
57
template <typename Spec>
58 59
Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
                                               const Spec* spec) {
60 61
  Factory* factory = isolate->factory();

62
  const int slot_count = spec->slots();
63 64
  const int slot_kinds_length = VectorICComputer::word_count(slot_count);
  const int length = slot_kinds_length + kReservedIndexCount;
65
  if (length == kReservedIndexCount) {
66
    return Handle<FeedbackMetadata>::cast(factory->empty_fixed_array());
67
  }
68 69
#ifdef DEBUG
  for (int i = 0; i < slot_count;) {
70
    FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
71
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
72
    for (int j = 1; j < entry_size; j++) {
73
      FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
74
      DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
75 76 77 78
    }
    i += entry_size;
  }
#endif
79

80
  Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
81
  array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
82 83
  // Fill the bit-vector part with zeros.
  for (int i = 0; i < slot_kinds_length; i++) {
84
    array->set(kReservedIndexCount + i, Smi::kZero);
85
  }
86

87
  Handle<FeedbackMetadata> metadata = Handle<FeedbackMetadata>::cast(array);
88

89
  for (int i = 0; i < slot_count; i++) {
90 91
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = spec->GetKind(slot);
92
    metadata->SetKind(slot, kind);
93
  }
94

95
  // It's important that the FeedbackMetadata have a COW map, since it's
96
  // pointed to by both a SharedFunctionInfo and indirectly by closures through
97
  // the FeedbackVector. The serializer uses the COW map type to decide
98 99 100 101
  // this object belongs in the startup snapshot and not the partial
  // snapshot(s).
  metadata->set_map(isolate->heap()->fixed_cow_array_map());

102 103 104
  return metadata;
}

105
bool FeedbackMetadata::SpecDiffersFrom(
106 107 108 109 110 111
    const FeedbackVectorSpec* other_spec) const {
  if (other_spec->slots() != slot_count()) {
    return true;
  }

  int slots = slot_count();
112
  for (int i = 0; i < slots;) {
113 114
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = GetKind(slot);
115
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
116

117
    if (kind != other_spec->GetKind(slot)) {
118 119
      return true;
    }
120
    i += entry_size;
121 122 123 124
  }
  return false;
}

125
const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
126
  switch (kind) {
127
    case FeedbackSlotKind::kInvalid:
128
      return "Invalid";
129
    case FeedbackSlotKind::kCall:
130
      return "Call";
131
    case FeedbackSlotKind::kLoadProperty:
132
      return "LoadProperty";
133
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
134
      return "LoadGlobalInsideTypeof";
135
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
136
      return "LoadGlobalNotInsideTypeof";
137
    case FeedbackSlotKind::kLoadKeyed:
138
      return "LoadKeyed";
139
    case FeedbackSlotKind::kStoreNamedSloppy:
140
      return "StoreNamedSloppy";
141
    case FeedbackSlotKind::kStoreNamedStrict:
142
      return "StoreNamedStrict";
143
    case FeedbackSlotKind::kStoreOwnNamed:
144 145 146 147 148
      return "StoreOwnNamed";
    case FeedbackSlotKind::kStoreGlobalSloppy:
      return "StoreGlobalSloppy";
    case FeedbackSlotKind::kStoreGlobalStrict:
      return "StoreGlobalStrict";
149
    case FeedbackSlotKind::kStoreKeyedSloppy:
150
      return "StoreKeyedSloppy";
151
    case FeedbackSlotKind::kStoreKeyedStrict:
152
      return "StoreKeyedStrict";
153
    case FeedbackSlotKind::kBinaryOp:
154
      return "BinaryOp";
155
    case FeedbackSlotKind::kCompareOp:
156
      return "CompareOp";
157
    case FeedbackSlotKind::kStoreDataPropertyInLiteral:
158
      return "StoreDataPropertyInLiteral";
159 160 161
    case FeedbackSlotKind::kCreateClosure:
      return "kCreateClosure";
    case FeedbackSlotKind::kLiteral:
162
      return "Literal";
163
    case FeedbackSlotKind::kTypeProfile:
164
      return "TypeProfile";
165
    case FeedbackSlotKind::kGeneral:
166
      return "General";
167
    case FeedbackSlotKind::kKindsNumber:
168 169 170 171 172
      break;
  }
  UNREACHABLE();
}

173 174 175 176
bool FeedbackMetadata::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
177 178
}

179
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
180 181 182
  DCHECK(!is_empty());
  return metadata()->GetKind(slot);
}
183

184
FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
185 186 187 188 189
  DCHECK(metadata()->HasTypeProfileSlot());
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
  return slot;
190 191
}

192
// static
193
Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
194
                                           Handle<SharedFunctionInfo> shared) {
195 196
  Factory* factory = isolate->factory();

197
  const int slot_count = shared->feedback_metadata()->slot_count();
198 199 200
  const int length = slot_count + kReservedIndexCount;

  Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
201
  array->set_map_no_write_barrier(isolate->heap()->feedback_vector_map());
202
  array->set(kSharedFunctionInfoIndex, *shared);
203
  array->set(kOptimizedCodeIndex, Smi::FromEnum(OptimizationMarker::kNone));
204
  array->set(kInvocationCountIndex, Smi::kZero);
205

206 207
  // Ensure we can skip the write barrier
  Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
208
  DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
209
  Handle<Oddball> undefined_value = factory->undefined_value();
210
  for (int i = 0; i < slot_count;) {
211
    FeedbackSlot slot(i);
212
    FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
213 214
    int index = FeedbackVector::GetIndex(slot);
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
215

216 217
    Object* extra_value = *uninitialized_sentinel;
    switch (kind) {
218 219
      case FeedbackSlotKind::kLoadGlobalInsideTypeof:
      case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
220 221
        array->set(index, isolate->heap()->empty_weak_cell(),
                   SKIP_WRITE_BARRIER);
222
        break;
223 224
      case FeedbackSlotKind::kCompareOp:
      case FeedbackSlotKind::kBinaryOp:
225
        array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
226
        break;
227
      case FeedbackSlotKind::kCreateClosure: {
228
        Handle<Cell> cell = factory->NewNoClosuresCell(undefined_value);
229
        array->set(index, *cell);
230
        break;
231
      }
232
      case FeedbackSlotKind::kLiteral:
233
        array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
234
        break;
235
      case FeedbackSlotKind::kCall:
236
        array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
237 238
        extra_value = Smi::kZero;
        break;
239 240
      case FeedbackSlotKind::kLoadProperty:
      case FeedbackSlotKind::kLoadKeyed:
241 242 243
      case FeedbackSlotKind::kStoreNamedSloppy:
      case FeedbackSlotKind::kStoreNamedStrict:
      case FeedbackSlotKind::kStoreOwnNamed:
244 245
      case FeedbackSlotKind::kStoreGlobalSloppy:
      case FeedbackSlotKind::kStoreGlobalStrict:
246 247 248 249
      case FeedbackSlotKind::kStoreKeyedSloppy:
      case FeedbackSlotKind::kStoreKeyedStrict:
      case FeedbackSlotKind::kStoreDataPropertyInLiteral:
      case FeedbackSlotKind::kGeneral:
250
      case FeedbackSlotKind::kTypeProfile:
251
        array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
252 253
        break;

254 255
      case FeedbackSlotKind::kInvalid:
      case FeedbackSlotKind::kKindsNumber:
256
        UNREACHABLE();
257
        array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
258
        break;
259
    }
260 261
    for (int j = 1; j < entry_size; j++) {
      array->set(index + j, extra_value, SKIP_WRITE_BARRIER);
262 263 264
    }
    i += entry_size;
  }
265 266

  Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(array);
267 268 269
  if (!isolate->is_best_effort_code_coverage()) {
    AddToCodeCoverageList(isolate, result);
  }
270
  return result;
271 272
}

273
// static
274 275 276 277
Handle<FeedbackVector> FeedbackVector::Copy(Isolate* isolate,
                                            Handle<FeedbackVector> vector) {
  Handle<FeedbackVector> result;
  result = Handle<FeedbackVector>::cast(
278
      isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
279 280 281
  if (!isolate->is_best_effort_code_coverage()) {
    AddToCodeCoverageList(isolate, result);
  }
282 283
  return result;
}
284

285 286 287
// static
void FeedbackVector::AddToCodeCoverageList(Isolate* isolate,
                                           Handle<FeedbackVector> vector) {
288
  DCHECK(!isolate->is_best_effort_code_coverage());
289 290 291 292 293 294 295
  if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
  Handle<ArrayList> list =
      Handle<ArrayList>::cast(isolate->factory()->code_coverage_list());
  list = ArrayList::Add(list, vector);
  isolate->SetCodeCoverageList(*list);
}

296 297 298 299 300 301 302 303 304
// static
void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
                                      Handle<Code> code) {
  DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
  Factory* factory = vector->GetIsolate()->factory();
  Handle<WeakCell> cell = factory->NewWeakCell(code);
  vector->set(kOptimizedCodeIndex, *cell);
}

305 306 307 308
void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
  set(kOptimizedCodeIndex, Smi::FromEnum(marker));
}

309
void FeedbackVector::ClearOptimizedCode() {
310
  set(kOptimizedCodeIndex, Smi::FromEnum(OptimizationMarker::kNone));
311 312 313 314
}

void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
    SharedFunctionInfo* shared, const char* reason) {
315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
  Object* slot = get(kOptimizedCodeIndex);
  if (slot->IsSmi()) return;

  WeakCell* cell = WeakCell::cast(slot);
  if (cell->cleared()) {
    ClearOptimizedCode();
    return;
  }

  Code* code = Code::cast(cell->value());
  if (code->marked_for_deoptimization()) {
    if (FLAG_trace_deopt) {
      PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
             reason);
      shared->ShortPrint();
      PrintF("]\n");
    }
    if (!code->deopt_already_counted()) {
      shared->increment_deopt_count();
      code->set_deopt_already_counted(true);
335
    }
336
    ClearOptimizedCode();
337 338 339
  }
}

340
void FeedbackVector::ClearSlots(JSFunction* host_function) {
341
  Isolate* isolate = GetIsolate();
342

343
  Object* uninitialized_sentinel =
344
      FeedbackVector::RawUninitializedSentinel(isolate);
345

346
  bool feedback_updated = false;
347
  FeedbackMetadataIterator iter(metadata());
348
  while (iter.HasNext()) {
349 350
    FeedbackSlot slot = iter.Next();
    FeedbackSlotKind kind = iter.kind();
351

352 353
    Object* obj = Get(slot);
    if (obj != uninitialized_sentinel) {
354
      switch (kind) {
355
        case FeedbackSlotKind::kCall: {
356
          CallICNexus nexus(this, slot);
357 358 359 360
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
361 362
          break;
        }
363
        case FeedbackSlotKind::kLoadProperty: {
364
          LoadICNexus nexus(this, slot);
365 366 367 368
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
369 370
          break;
        }
371 372
        case FeedbackSlotKind::kLoadGlobalInsideTypeof:
        case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: {
373
          LoadGlobalICNexus nexus(this, slot);
374 375 376 377
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
378 379
          break;
        }
380
        case FeedbackSlotKind::kLoadKeyed: {
381
          KeyedLoadICNexus nexus(this, slot);
382 383 384 385
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
386 387
          break;
        }
388 389
        case FeedbackSlotKind::kStoreNamedSloppy:
        case FeedbackSlotKind::kStoreNamedStrict:
390 391 392
        case FeedbackSlotKind::kStoreOwnNamed:
        case FeedbackSlotKind::kStoreGlobalSloppy:
        case FeedbackSlotKind::kStoreGlobalStrict: {
393
          StoreICNexus nexus(this, slot);
394 395 396 397
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
398 399
          break;
        }
400 401
        case FeedbackSlotKind::kStoreKeyedSloppy:
        case FeedbackSlotKind::kStoreKeyedStrict: {
402
          KeyedStoreICNexus nexus(this, slot);
403 404 405 406
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
407 408
          break;
        }
409 410
        case FeedbackSlotKind::kBinaryOp:
        case FeedbackSlotKind::kCompareOp: {
411 412
          DCHECK(Get(slot)->IsSmi());
          // don't clear these smi slots.
413
          // Set(slot, Smi::kZero);
414 415
          break;
        }
416
        case FeedbackSlotKind::kCreateClosure: {
417 418
          case FeedbackSlotKind::kTypeProfile:
            break;
419
        }
420
        case FeedbackSlotKind::kGeneral: {
421 422 423 424 425 426 427 428
          if (obj->IsHeapObject()) {
            InstanceType instance_type =
                HeapObject::cast(obj)->map()->instance_type();
            // AllocationSites are exempt from clearing. They don't store Maps
            // or Code pointers which can cause memory leaks if not cleared
            // regularly.
            if (instance_type != ALLOCATION_SITE_TYPE) {
              Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
429
              feedback_updated = true;
430 431
            }
          }
432 433
          break;
        }
434
        case FeedbackSlotKind::kLiteral: {
435
          Set(slot, Smi::kZero, SKIP_WRITE_BARRIER);
436
          feedback_updated = true;
437 438
          break;
        }
439
        case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
440
          StoreDataPropertyInLiteralICNexus nexus(this, slot);
441 442 443 444
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
445 446
          break;
        }
447 448
        case FeedbackSlotKind::kInvalid:
        case FeedbackSlotKind::kKindsNumber:
449 450
          UNREACHABLE();
          break;
451
      }
452 453
    }
  }
454 455 456
  if (feedback_updated) {
    IC::OnFeedbackChanged(isolate, host_function);
  }
457
}
458 459 460 461 462 463 464 465 466 467 468 469 470

Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
  Isolate* isolate = GetIsolate();
  Handle<Object> feedback = handle(GetFeedback(), isolate);
  if (!feedback->IsFixedArray() ||
      FixedArray::cast(*feedback)->length() != length) {
    Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
    SetFeedback(*array);
    return array;
  }
  return Handle<FixedArray>::cast(feedback);
}

471
Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
472
  Isolate* isolate = GetIsolate();
473 474 475 476 477 478 479 480 481 482
  Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
  if (!feedback_extra->IsFixedArray() ||
      FixedArray::cast(*feedback_extra)->length() != length) {
    Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
    SetFeedbackExtra(*array);
    return array;
  }
  return Handle<FixedArray>::cast(feedback_extra);
}

483
void FeedbackNexus::ConfigureUninitialized() {
484
  SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()),
485
              SKIP_WRITE_BARRIER);
486
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
487 488 489 490
                   SKIP_WRITE_BARRIER);
}

void FeedbackNexus::ConfigurePremonomorphic() {
491
  SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
492
              SKIP_WRITE_BARRIER);
493
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
494 495 496
                   SKIP_WRITE_BARRIER);
}

497
void FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
498
  Isolate* isolate = GetIsolate();
499
  SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate),
500 501 502 503
              SKIP_WRITE_BARRIER);
  SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
                   SKIP_WRITE_BARRIER);
}
504

505 506 507
InlineCacheState LoadICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
508

509
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
510
    return UNINITIALIZED;
511
  } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
512
    return MEGAMORPHIC;
513
  } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
514 515
    return PREMONOMORPHIC;
  } else if (feedback->IsFixedArray()) {
516 517
    // Determine state purely by our structure, don't check if the maps are
    // cleared.
518 519 520 521
    return POLYMORPHIC;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
522 523 524 525 526
  }

  return UNINITIALIZED;
}

527 528 529 530
InlineCacheState LoadGlobalICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();

531 532
  Object* extra = GetFeedbackExtra();
  if (!WeakCell::cast(feedback)->cleared() ||
533
      extra != *FeedbackVector::UninitializedSentinel(isolate)) {
534
    return MONOMORPHIC;
535
  }
536 537
  return UNINITIALIZED;
}
538 539 540 541

InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
542

543
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
544
    return UNINITIALIZED;
545
  } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
546
    return PREMONOMORPHIC;
547
  } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
548
    return MEGAMORPHIC;
549
  } else if (feedback->IsFixedArray()) {
550 551
    // Determine state purely by our structure, don't check if the maps are
    // cleared.
552 553 554 555 556 557 558 559
    return POLYMORPHIC;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
  } else if (feedback->IsName()) {
    Object* extra = GetFeedbackExtra();
    FixedArray* extra_array = FixedArray::cast(extra);
    return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
560 561 562 563 564
  }

  return UNINITIALIZED;
}

565 566 567 568
InlineCacheState StoreICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();

569
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
570
    return UNINITIALIZED;
571
  } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
572
    return MEGAMORPHIC;
573
  } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590
    return PREMONOMORPHIC;
  } else if (feedback->IsFixedArray()) {
    // Determine state purely by our structure, don't check if the maps are
    // cleared.
    return POLYMORPHIC;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
  }

  return UNINITIALIZED;
}

InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();

591
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
592
    return UNINITIALIZED;
593
  } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
594
    return PREMONOMORPHIC;
595
  } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612
    return MEGAMORPHIC;
  } else if (feedback->IsFixedArray()) {
    // Determine state purely by our structure, don't check if the maps are
    // cleared.
    return POLYMORPHIC;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
  } else if (feedback->IsName()) {
    Object* extra = GetFeedbackExtra();
    FixedArray* extra_array = FixedArray::cast(extra);
    return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
  }

  return UNINITIALIZED;
}

613 614 615
InlineCacheState CallICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
616
  DCHECK(GetFeedbackExtra() ==
617
             *FeedbackVector::UninitializedSentinel(isolate) ||
618
         GetFeedbackExtra()->IsSmi());
619

620
  if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
621
    return GENERIC;
622
  } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
623
    return MONOMORPHIC;
624 625
  }

626
  CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate));
627
  return UNINITIALIZED;
628 629
}

630 631
int CallICNexus::ExtractCallCount() {
  Object* call_count = GetFeedbackExtra();
632 633 634
  CHECK(call_count->IsSmi());
  int value = Smi::cast(call_count)->value();
  return value;
635 636
}

637 638 639
float CallICNexus::ComputeCallFrequency() {
  double const invocation_count = vector()->invocation_count();
  double const call_count = ExtractCallCount();
640 641 642 643
  if (invocation_count == 0) {
    // Prevent division by 0.
    return 0.0f;
  }
644 645 646
  return static_cast<float>(call_count / invocation_count);
}

647 648
void CallICNexus::ConfigureUninitialized() {
  Isolate* isolate = GetIsolate();
649
  SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
650
              SKIP_WRITE_BARRIER);
651
  SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
652
}
653

654 655 656
void LoadGlobalICNexus::ConfigureUninitialized() {
  Isolate* isolate = GetIsolate();
  SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
657
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
658 659 660 661 662 663
                   SKIP_WRITE_BARRIER);
}

void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
  Isolate* isolate = GetIsolate();
  SetFeedback(*isolate->factory()->NewWeakCell(cell));
664
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
665 666 667
                   SKIP_WRITE_BARRIER);
}

668
void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) {
669 670 671 672
  SetFeedback(GetIsolate()->heap()->empty_weak_cell());
  SetFeedbackExtra(*handler);
}

673 674 675
void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
                                         Handle<Map> receiver_map,
                                         Handle<Object> handler) {
676 677 678 679 680 681
  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
  if (name.is_null()) {
    SetFeedback(*cell);
    SetFeedbackExtra(*handler);
  } else {
    Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
682
    SetFeedback(*name);
683 684 685
    array->set(0, *cell);
    array->set(1, *handler);
  }
686 687
}

688 689
void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
                                         MapHandles const& maps,
690
                                         List<Handle<Object>>* handlers) {
691
  int receiver_count = static_cast<int>(maps.size());
692 693
  DCHECK(receiver_count > 1);
  Handle<FixedArray> array;
694
  if (name.is_null()) {
695
    array = EnsureArrayOfSize(receiver_count * 2);
696
    SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
697
                     SKIP_WRITE_BARRIER);
698
  } else {
699
    array = EnsureExtraArrayOfSize(receiver_count * 2);
700
    SetFeedback(*name);
701
  }
702

703
  for (int current = 0; current < receiver_count; ++current) {
704
    Handle<Map> map = maps[current];
705 706 707
    Handle<WeakCell> cell = Map::WeakCellForMap(map);
    array->set(current * 2, *cell);
    array->set(current * 2 + 1, *handlers->at(current));
708
  }
709 710
}

711
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
712 713
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
714 715
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
  if (feedback->IsFixedArray() || is_named_feedback) {
716
    int found = 0;
717
    if (is_named_feedback) {
718 719
      feedback = GetFeedbackExtra();
    }
720
    FixedArray* array = FixedArray::cast(feedback);
721
    const int increment = 2;
722
    for (int i = 0; i < array->length(); i += increment) {
723
      DCHECK(array->get(i)->IsWeakCell());
724 725 726
      WeakCell* cell = WeakCell::cast(array->get(i));
      if (!cell->cleared()) {
        Map* map = Map::cast(cell->value());
727
        maps->push_back(handle(map, isolate));
728 729
        found++;
      }
730
    }
731
    return found;
732 733 734 735
  } else if (feedback->IsWeakCell()) {
    WeakCell* cell = WeakCell::cast(feedback);
    if (!cell->cleared()) {
      Map* map = Map::cast(cell->value());
736
      maps->push_back(handle(map, isolate));
737 738
      return 1;
    }
739 740 741 742 743
  }

  return 0;
}

744
MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
745
  Object* feedback = GetFeedback();
746
  Isolate* isolate = GetIsolate();
747 748 749
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
  if (feedback->IsFixedArray() || is_named_feedback) {
    if (is_named_feedback) {
750 751
      feedback = GetFeedbackExtra();
    }
752
    FixedArray* array = FixedArray::cast(feedback);
753
    const int increment = 2;
754
    for (int i = 0; i < array->length(); i += increment) {
755
      DCHECK(array->get(i)->IsWeakCell());
756 757 758 759
      WeakCell* cell = WeakCell::cast(array->get(i));
      if (!cell->cleared()) {
        Map* array_map = Map::cast(cell->value());
        if (array_map == *map) {
760
          Object* code = array->get(i + increment - 1);
761
          DCHECK(IC::IsHandler(code));
762
          return handle(code, isolate);
763
        }
764 765
      }
    }
766 767 768 769 770
  } else if (feedback->IsWeakCell()) {
    WeakCell* cell = WeakCell::cast(feedback);
    if (!cell->cleared()) {
      Map* cell_map = Map::cast(cell->value());
      if (cell_map == *map) {
771
        Object* code = GetFeedbackExtra();
772
        DCHECK(IC::IsHandler(code));
773
        return handle(code, isolate);
774 775
      }
    }
776 777 778 779 780
  }

  return MaybeHandle<Code>();
}

781 782
bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
                                 int length) const {
783
  Object* feedback = GetFeedback();
784
  Isolate* isolate = GetIsolate();
785
  int count = 0;
786 787 788
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
  if (feedback->IsFixedArray() || is_named_feedback) {
    if (is_named_feedback) {
789 790
      feedback = GetFeedbackExtra();
    }
791
    FixedArray* array = FixedArray::cast(feedback);
792
    const int increment = 2;
793
    for (int i = 0; i < array->length(); i += increment) {
794
      DCHECK(array->get(i)->IsWeakCell());
795
      WeakCell* cell = WeakCell::cast(array->get(i));
796
      // Be sure to skip handlers whose maps have been cleared.
797
      if (!cell->cleared()) {
798
        Object* code = array->get(i + increment - 1);
799
        DCHECK(IC::IsHandler(code));
800
        code_list->Add(handle(code, isolate));
801 802
        count++;
      }
803
    }
804 805 806
  } else if (feedback->IsWeakCell()) {
    WeakCell* cell = WeakCell::cast(feedback);
    if (!cell->cleared()) {
807
      Object* code = GetFeedbackExtra();
808
      DCHECK(IC::IsHandler(code));
809
      code_list->Add(handle(code, isolate));
810 811
      count++;
    }
812 813 814
  }
  return count == length;
}
815 816 817

Name* KeyedLoadICNexus::FindFirstName() const {
  Object* feedback = GetFeedback();
818
  if (IsPropertyNameFeedback(feedback)) {
819
    return Name::cast(feedback);
820 821 822
  }
  return NULL;
}
823 824 825

Name* KeyedStoreICNexus::FindFirstName() const {
  Object* feedback = GetFeedback();
826
  if (IsPropertyNameFeedback(feedback)) {
827 828 829 830 831
    return Name::cast(feedback);
  }
  return NULL;
}

832 833
KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
  KeyedAccessStoreMode mode = STANDARD_STORE;
834
  MapHandles maps;
835
  List<Handle<Object>> handlers;
836 837 838 839

  if (GetKeyType() == PROPERTY) return mode;

  ExtractMaps(&maps);
840
  FindHandlers(&handlers, static_cast<int>(maps.size()));
841 842
  for (int i = 0; i < handlers.length(); i++) {
    // The first handler that isn't the slow handler will have the bits we need.
843 844
    Handle<Object> maybe_code_handler = handlers.at(i);
    Handle<Code> handler;
845 846 847 848 849 850
    if (maybe_code_handler->IsTuple3()) {
      // Elements transition.
      Handle<Tuple3> data_handler = Handle<Tuple3>::cast(maybe_code_handler);
      handler = handle(Code::cast(data_handler->value2()));
    } else if (maybe_code_handler->IsTuple2()) {
      // Element store with prototype chain check.
851 852 853
      Handle<Tuple2> data_handler = Handle<Tuple2>::cast(maybe_code_handler);
      handler = handle(Code::cast(data_handler->value2()));
    } else {
854
      // Element store without prototype chain check.
855 856
      handler = Handle<Code>::cast(maybe_code_handler);
    }
857 858 859 860
    CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
    uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
    CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
          major_key == CodeStub::StoreFastElement ||
861
          major_key == CodeStub::StoreSlowElement ||
862 863 864 865 866 867 868 869 870 871 872
          major_key == CodeStub::ElementsTransitionAndStore ||
          major_key == CodeStub::NoCache);
    if (major_key != CodeStub::NoCache) {
      mode = CommonStoreModeBits::decode(minor_key);
      break;
    }
  }

  return mode;
}

873 874
IcCheckType KeyedLoadICNexus::GetKeyType() const {
  Object* feedback = GetFeedback();
875
  if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
876 877 878 879
    return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
  }
  return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
}
880 881

IcCheckType KeyedStoreICNexus::GetKeyType() const {
882
  Object* feedback = GetFeedback();
883
  if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
884 885 886
    return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
  }
  return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
887
}
888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920

InlineCacheState BinaryOpICNexus::StateFromFeedback() const {
  BinaryOperationHint hint = GetBinaryOperationFeedback();
  if (hint == BinaryOperationHint::kNone) {
    return UNINITIALIZED;
  } else if (hint == BinaryOperationHint::kAny) {
    return GENERIC;
  }

  return MONOMORPHIC;
}

InlineCacheState CompareICNexus::StateFromFeedback() const {
  CompareOperationHint hint = GetCompareOperationFeedback();
  if (hint == CompareOperationHint::kNone) {
    return UNINITIALIZED;
  } else if (hint == CompareOperationHint::kAny) {
    return GENERIC;
  }

  return MONOMORPHIC;
}

BinaryOperationHint BinaryOpICNexus::GetBinaryOperationFeedback() const {
  int feedback = Smi::cast(GetFeedback())->value();
  return BinaryOperationHintFromFeedback(feedback);
}

CompareOperationHint CompareICNexus::GetCompareOperationFeedback() const {
  int feedback = Smi::cast(GetFeedback())->value();
  return CompareOperationHintFromFeedback(feedback);
}

921 922 923 924
InlineCacheState StoreDataPropertyInLiteralICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();

925
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942
    return UNINITIALIZED;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
  }

  return MEGAMORPHIC;
}

void StoreDataPropertyInLiteralICNexus::ConfigureMonomorphic(
    Handle<Name> name, Handle<Map> receiver_map) {
  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);

  SetFeedback(*cell);
  SetFeedbackExtra(*name);
}

943 944 945 946 947 948 949 950 951 952
InlineCacheState CollectTypeProfileNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* const feedback = GetFeedback();

  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
    return UNINITIALIZED;
  }
  return MONOMORPHIC;
}

953
void CollectTypeProfileNexus::Collect(Handle<String> type, int position) {
954
  DCHECK_GE(position, 0);
955 956 957
  Isolate* isolate = GetIsolate();

  Object* const feedback = GetFeedback();
958 959 960

  // Map source position to collection of types
  Handle<UnseededNumberDictionary> types;
961 962

  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
963
    types = UnseededNumberDictionary::New(isolate, 1);
964
  } else {
965
    types = handle(UnseededNumberDictionary::cast(feedback));
966
  }
967

968
  Handle<ArrayList> position_specific_types;
969

970 971 972 973
  int entry = types->FindEntry(position);
  if (entry == UnseededNumberDictionary::kNotFound) {
    position_specific_types = ArrayList::New(isolate, 1);
  } else {
974
    DCHECK(types->ValueAt(entry)->IsArrayList());
975
    position_specific_types = handle(ArrayList::cast(types->ValueAt(entry)));
976
  }
977

978
  types = UnseededNumberDictionary::Set(
979
      types, position, ArrayList::Add(position_specific_types, type));
980
  SetFeedback(*types);
981 982
}

983 984
namespace {

985 986 987 988
Handle<JSObject> ConvertToJSObject(Isolate* isolate,
                                   Handle<UnseededNumberDictionary> feedback) {
  Handle<JSObject> type_profile =
      isolate->factory()->NewJSObject(isolate->object_function());
989 990

  for (int index = UnseededNumberDictionary::kElementsStartIndex;
991
       index < feedback->length();
992 993
       index += UnseededNumberDictionary::kEntrySize) {
    int key_index = index + UnseededNumberDictionary::kEntryKeyIndex;
994
    Object* key = feedback->get(key_index);
995 996 997
    if (key->IsSmi()) {
      int value_index = index + UnseededNumberDictionary::kEntryValueIndex;

998 999
      Handle<ArrayList> position_specific_types(
          ArrayList::cast(feedback->get(value_index)));
1000

1001 1002 1003 1004 1005
      int position = Smi::cast(key)->value();
      JSObject::AddDataElement(type_profile, position,
                               isolate->factory()->NewJSArrayWithElements(
                                   position_specific_types->Elements()),
                               PropertyAttributes::NONE)
1006
          .ToHandleChecked();
1007 1008
    }
  }
1009
  return type_profile;
1010 1011 1012
}
}  // namespace

1013
JSObject* CollectTypeProfileNexus::GetTypeProfile() const {
1014 1015 1016 1017 1018
  Isolate* isolate = GetIsolate();

  Object* const feedback = GetFeedback();

  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
1019
    return *isolate->factory()->NewJSObject(isolate->object_function());
1020 1021
  }

1022 1023
  return *ConvertToJSObject(isolate,
                            handle(UnseededNumberDictionary::cast(feedback)));
1024 1025
}

1026 1027
}  // namespace internal
}  // namespace v8