feedback-vector.cc 48.9 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/objects/feedback-vector.h"
6
#include "src/diagnostics/code-tracer.h"
7
#include "src/heap/off-thread-factory-inl.h"
8
#include "src/ic/handler-configuration-inl.h"
9
#include "src/ic/ic-inl.h"
10
#include "src/objects/data-handler-inl.h"
11
#include "src/objects/feedback-vector-inl.h"
12
#include "src/objects/hash-table-inl.h"
13
#include "src/objects/map-inl.h"
14
#include "src/objects/object-macros.h"
15
#include "src/objects/objects.h"
16 17 18 19

namespace v8 {
namespace internal {

20 21
FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
  int slot = slots();
22
  int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
23
  append(kind);
24
  for (int i = 1; i < entries_per_slot; i++) {
25
    append(FeedbackSlotKind::kInvalid);
26 27 28 29
  }
  return FeedbackSlot(slot);
}

30
FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
31 32 33 34 35 36
  FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
  CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
           FeedbackVector::GetIndex(slot));
  return slot;
}

37 38 39 40 41 42 43 44 45
bool FeedbackVectorSpec::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  if (slots() <= slot.ToInt()) {
    return false;
  }
  return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
}

46
static bool IsPropertyNameFeedback(MaybeObject feedback) {
47
  HeapObject heap_object;
48
  if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
49 50
  if (heap_object.IsString()) {
    DCHECK(heap_object.IsInternalizedString());
51 52
    return true;
  }
53
  if (!heap_object.IsSymbol()) return false;
54
  Symbol symbol = Symbol::cast(heap_object);
55
  ReadOnlyRoots roots = symbol.GetReadOnlyRoots();
56 57
  return symbol != roots.uninitialized_symbol() &&
         symbol != roots.megamorphic_symbol();
58 59
}

60
std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
61
  return os << FeedbackMetadata::Kind2String(kind);
62 63
}

64
FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
65 66
  int index = VectorICComputer::index(0, slot.ToInt());
  int data = get(index);
67
  return VectorICComputer::decode(data, slot.ToInt());
68 69
}

70
void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
71 72
  int index = VectorICComputer::index(0, slot.ToInt());
  int data = get(index);
73
  int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
74
  set(index, new_data);
75 76
}

77
// static
78 79
template <typename LocalIsolate>
Handle<FeedbackMetadata> FeedbackMetadata::New(LocalIsolate* isolate,
80
                                               const FeedbackVectorSpec* spec) {
81
  auto* factory = isolate->factory();
82

83
  const int slot_count = spec == nullptr ? 0 : spec->slots();
84 85 86
  const int closure_feedback_cell_count =
      spec == nullptr ? 0 : spec->closure_feedback_cells();
  if (slot_count == 0 && closure_feedback_cell_count == 0) {
87
    return factory->empty_feedback_metadata();
88
  }
89 90
#ifdef DEBUG
  for (int i = 0; i < slot_count;) {
91
    DCHECK(spec);
92
    FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
93
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
94
    for (int j = 1; j < entry_size; j++) {
95
      FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
96
      DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
97 98 99 100
    }
    i += entry_size;
  }
#endif
101

102 103
  Handle<FeedbackMetadata> metadata =
      factory->NewFeedbackMetadata(slot_count, closure_feedback_cell_count);
104

105 106
  // Initialize the slots. The raw data section has already been pre-zeroed in
  // NewFeedbackMetadata.
107
  for (int i = 0; i < slot_count; i++) {
108
    DCHECK(spec);
109 110
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = spec->GetKind(slot);
111
    metadata->SetKind(slot, kind);
112
  }
113

114 115 116
  return metadata;
}

117 118 119 120 121
template Handle<FeedbackMetadata> FeedbackMetadata::New(
    Isolate* isolate, const FeedbackVectorSpec* spec);
template Handle<FeedbackMetadata> FeedbackMetadata::New(
    OffThreadIsolate* isolate, const FeedbackVectorSpec* spec);

122
bool FeedbackMetadata::SpecDiffersFrom(
123 124 125 126 127 128
    const FeedbackVectorSpec* other_spec) const {
  if (other_spec->slots() != slot_count()) {
    return true;
  }

  int slots = slot_count();
129
  for (int i = 0; i < slots;) {
130 131
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = GetKind(slot);
132
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
133

134
    if (kind != other_spec->GetKind(slot)) {
135 136
      return true;
    }
137
    i += entry_size;
138 139 140 141
  }
  return false;
}

142
const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
143
  switch (kind) {
144
    case FeedbackSlotKind::kInvalid:
145
      return "Invalid";
146
    case FeedbackSlotKind::kCall:
147
      return "Call";
148
    case FeedbackSlotKind::kLoadProperty:
149
      return "LoadProperty";
150
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
151
      return "LoadGlobalInsideTypeof";
152
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
153
      return "LoadGlobalNotInsideTypeof";
154
    case FeedbackSlotKind::kLoadKeyed:
155
      return "LoadKeyed";
156 157
    case FeedbackSlotKind::kHasKeyed:
      return "HasKeyed";
158
    case FeedbackSlotKind::kStoreNamedSloppy:
159
      return "StoreNamedSloppy";
160
    case FeedbackSlotKind::kStoreNamedStrict:
161
      return "StoreNamedStrict";
162
    case FeedbackSlotKind::kStoreOwnNamed:
163 164 165 166 167
      return "StoreOwnNamed";
    case FeedbackSlotKind::kStoreGlobalSloppy:
      return "StoreGlobalSloppy";
    case FeedbackSlotKind::kStoreGlobalStrict:
      return "StoreGlobalStrict";
168
    case FeedbackSlotKind::kStoreKeyedSloppy:
169
      return "StoreKeyedSloppy";
170
    case FeedbackSlotKind::kStoreKeyedStrict:
171
      return "StoreKeyedStrict";
172 173
    case FeedbackSlotKind::kStoreInArrayLiteral:
      return "StoreInArrayLiteral";
174
    case FeedbackSlotKind::kBinaryOp:
175
      return "BinaryOp";
176
    case FeedbackSlotKind::kCompareOp:
177
      return "CompareOp";
178
    case FeedbackSlotKind::kStoreDataPropertyInLiteral:
179
      return "StoreDataPropertyInLiteral";
180
    case FeedbackSlotKind::kLiteral:
181
      return "Literal";
182
    case FeedbackSlotKind::kTypeProfile:
183
      return "TypeProfile";
184 185
    case FeedbackSlotKind::kForIn:
      return "ForIn";
186 187
    case FeedbackSlotKind::kInstanceOf:
      return "InstanceOf";
188 189
    case FeedbackSlotKind::kCloneObject:
      return "CloneObject";
190
    case FeedbackSlotKind::kKindsNumber:
191 192 193 194 195
      break;
  }
  UNREACHABLE();
}

196 197 198
bool FeedbackMetadata::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
199
  return slot.ToInt() < slot_count() &&
200
         GetKind(slot) == FeedbackSlotKind::kTypeProfile;
201 202
}

203
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
204
  DCHECK(!is_empty());
205
  return metadata().GetKind(slot);
206
}
207

208
FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
209
  DCHECK(metadata().HasTypeProfileSlot());
210 211 212 213
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
  return slot;
214 215
}

216 217 218 219 220 221
// static
Handle<ClosureFeedbackCellArray> ClosureFeedbackCellArray::New(
    Isolate* isolate, Handle<SharedFunctionInfo> shared) {
  Factory* factory = isolate->factory();

  int num_feedback_cells =
222
      shared->feedback_metadata().closure_feedback_cell_count();
223 224 225 226 227 228 229

  Handle<ClosureFeedbackCellArray> feedback_cell_array =
      factory->NewClosureFeedbackCellArray(num_feedback_cells);

  for (int i = 0; i < num_feedback_cells; i++) {
    Handle<FeedbackCell> cell =
        factory->NewNoClosuresCell(factory->undefined_value());
230
    feedback_cell_array->set(i, *cell);
231 232 233 234
  }
  return feedback_cell_array;
}

235
// static
236 237
Handle<FeedbackVector> FeedbackVector::New(
    Isolate* isolate, Handle<SharedFunctionInfo> shared,
238
    Handle<ClosureFeedbackCellArray> closure_feedback_cell_array) {
239 240
  Factory* factory = isolate->factory();

241
  const int slot_count = shared->feedback_metadata().slot_count();
242

243 244
  Handle<FeedbackVector> vector =
      factory->NewFeedbackVector(shared, closure_feedback_cell_array);
245 246 247 248

  DCHECK_EQ(vector->length(), slot_count);

  DCHECK_EQ(vector->shared_function_info(), *shared);
249 250 251 252 253
  DCHECK_EQ(
      vector->optimized_code_weak_or_smi(),
      MaybeObject::FromSmi(Smi::FromEnum(
          FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
                                   : OptimizationMarker::kNone)));
254
  DCHECK_EQ(vector->invocation_count(), 0);
255
  DCHECK_EQ(vector->profiler_ticks(), 0);
256

257 258
  // Ensure we can skip the write barrier
  Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
259 260
  DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
            *uninitialized_sentinel);
261
  for (int i = 0; i < slot_count;) {
262
    FeedbackSlot slot(i);
263
    FeedbackSlotKind kind = shared->feedback_metadata().GetKind(slot);
264 265
    int index = FeedbackVector::GetIndex(slot);
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
266

267
    Object extra_value = *uninitialized_sentinel;
268
    switch (kind) {
269 270
      case FeedbackSlotKind::kLoadGlobalInsideTypeof:
      case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
271 272
      case FeedbackSlotKind::kStoreGlobalSloppy:
      case FeedbackSlotKind::kStoreGlobalStrict:
273
        vector->set(index, HeapObjectReference::ClearedValue(isolate),
274
                    SKIP_WRITE_BARRIER);
275
        break;
276
      case FeedbackSlotKind::kForIn:
277 278
      case FeedbackSlotKind::kCompareOp:
      case FeedbackSlotKind::kBinaryOp:
279
        vector->set(index, Smi::zero(), SKIP_WRITE_BARRIER);
280
        break;
281
      case FeedbackSlotKind::kLiteral:
282
        vector->set(index, Smi::zero(), SKIP_WRITE_BARRIER);
283
        break;
284
      case FeedbackSlotKind::kCall:
285
        vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
286
        extra_value = Smi::zero();
287
        break;
288
      case FeedbackSlotKind::kCloneObject:
289 290
      case FeedbackSlotKind::kLoadProperty:
      case FeedbackSlotKind::kLoadKeyed:
291
      case FeedbackSlotKind::kHasKeyed:
292 293 294
      case FeedbackSlotKind::kStoreNamedSloppy:
      case FeedbackSlotKind::kStoreNamedStrict:
      case FeedbackSlotKind::kStoreOwnNamed:
295 296
      case FeedbackSlotKind::kStoreKeyedSloppy:
      case FeedbackSlotKind::kStoreKeyedStrict:
297
      case FeedbackSlotKind::kStoreInArrayLiteral:
298
      case FeedbackSlotKind::kStoreDataPropertyInLiteral:
299
      case FeedbackSlotKind::kTypeProfile:
300
      case FeedbackSlotKind::kInstanceOf:
301
        vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
302 303
        break;

304 305
      case FeedbackSlotKind::kInvalid:
      case FeedbackSlotKind::kKindsNumber:
306 307
        UNREACHABLE();
        break;
308
    }
309
    for (int j = 1; j < entry_size; j++) {
310
      vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
311 312 313
    }
    i += entry_size;
  }
314

315
  Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
316 317 318
  if (!isolate->is_best_effort_code_coverage() ||
      isolate->is_collecting_type_profile()) {
    AddToVectorsForProfilingTools(isolate, result);
319
  }
320 321
  return result;
}
322

323
// static
324 325 326 327
void FeedbackVector::AddToVectorsForProfilingTools(
    Isolate* isolate, Handle<FeedbackVector> vector) {
  DCHECK(!isolate->is_best_effort_code_coverage() ||
         isolate->is_collecting_type_profile());
328
  if (!vector->shared_function_info().IsSubjectToDebugging()) return;
329 330
  Handle<ArrayList> list = Handle<ArrayList>::cast(
      isolate->factory()->feedback_vectors_for_profiling_tools());
331
  list = ArrayList::Add(isolate, list, vector);
332
  isolate->SetFeedbackVectorsForProfilingTools(*list);
333 334
}

335 336 337 338
// static
void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
                                      Handle<Code> code) {
  DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
339
  vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
340 341
}

342 343 344
void FeedbackVector::ClearOptimizedCode() {
  DCHECK(has_optimized_code());
  SetOptimizationMarker(OptimizationMarker::kNone);
345 346
}

347 348 349 350 351 352
void FeedbackVector::ClearOptimizationMarker() {
  DCHECK(!has_optimized_code());
  SetOptimizationMarker(OptimizationMarker::kNone);
}

void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
353
  set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
354 355 356
}

void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
357
    SharedFunctionInfo shared, const char* reason) {
358
  MaybeObject slot = optimized_code_weak_or_smi();
359 360 361
  if (slot->IsSmi()) {
    return;
  }
362

363
  if (slot->IsCleared()) {
364
    ClearOptimizationMarker();
365 366 367
    return;
  }

368
  Code code = Code::cast(slot->GetHeapObject());
369
  if (code.marked_for_deoptimization()) {
370
    if (FLAG_trace_deopt) {
371 372 373
      CodeTracer::Scope scope(GetIsolate()->GetCodeTracer());
      PrintF(scope.file(),
             "[evicting optimizing code marked for deoptimization (%s) for ",
374
             reason);
375 376
      shared.ShortPrint(scope.file());
      PrintF(scope.file(), "]\n");
377
    }
378 379
    if (!code.deopt_already_counted()) {
      code.set_deopt_already_counted(true);
380
    }
381
    ClearOptimizedCode();
382 383 384
  }
}

385
bool FeedbackVector::ClearSlots(Isolate* isolate) {
386
  if (!shared_function_info().HasFeedbackMetadata()) return false;
387
  MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
388
      FeedbackVector::RawUninitializedSentinel(isolate));
389

390
  bool feedback_updated = false;
391
  FeedbackMetadataIterator iter(metadata());
392
  while (iter.HasNext()) {
393
    FeedbackSlot slot = iter.Next();
394

395
    MaybeObject obj = Get(slot);
396
    if (obj != uninitialized_sentinel) {
397
      FeedbackNexus nexus(*this, slot);
398
      feedback_updated |= nexus.Clear();
399 400
    }
  }
401
  return feedback_updated;
402
}
403

404
void FeedbackVector::AssertNoLegacyTypes(MaybeObject object) {
405
#ifdef DEBUG
406
  HeapObject heap_object;
407
  if (object->GetHeapObject(&heap_object)) {
408 409
    // Instead of FixedArray, the Feedback and the Extra should contain
    // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
410
    DCHECK_IMPLIES(heap_object.IsFixedArray(), heap_object.IsHashTable());
411 412
  }
#endif
413 414 415
}

Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
416
  Isolate* isolate = GetIsolate();
417
  HeapObject heap_object;
418
  if (GetFeedback()->GetHeapObjectIfStrong(&heap_object) &&
419 420
      heap_object.IsWeakFixedArray() &&
      WeakFixedArray::cast(heap_object).length() == length) {
421
    return handle(WeakFixedArray::cast(heap_object), isolate);
422
  }
423 424 425
  Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
  SetFeedback(*array);
  return array;
426 427
}

428
Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
429
  Isolate* isolate = GetIsolate();
430
  HeapObject heap_object;
431
  if (GetFeedbackExtra()->GetHeapObjectIfStrong(&heap_object) &&
432 433
      heap_object.IsWeakFixedArray() &&
      WeakFixedArray::cast(heap_object).length() == length) {
434
    return handle(WeakFixedArray::cast(heap_object), isolate);
435
  }
436 437 438
  Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
  SetFeedbackExtra(*array);
  return array;
439 440
}

441
void FeedbackNexus::ConfigureUninitialized() {
442 443 444 445 446 447
  Isolate* isolate = GetIsolate();
  switch (kind()) {
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
448 449
      SetFeedback(HeapObjectReference::ClearedValue(isolate),
                  SKIP_WRITE_BARRIER);
450 451 452 453
      SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                       SKIP_WRITE_BARRIER);
      break;
    }
454
    case FeedbackSlotKind::kCloneObject:
455 456 457
    case FeedbackSlotKind::kCall: {
      SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
                  SKIP_WRITE_BARRIER);
458
      SetFeedbackExtra(Smi::zero(), SKIP_WRITE_BARRIER);
459 460 461 462 463 464 465
      break;
    }
    case FeedbackSlotKind::kInstanceOf: {
      SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
                  SKIP_WRITE_BARRIER);
      break;
    }
466 467 468 469 470 471 472 473
    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict:
    case FeedbackSlotKind::kStoreInArrayLiteral:
    case FeedbackSlotKind::kStoreOwnNamed:
    case FeedbackSlotKind::kLoadProperty:
    case FeedbackSlotKind::kLoadKeyed:
474
    case FeedbackSlotKind::kHasKeyed:
475 476 477 478 479 480 481
    case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
      SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
                  SKIP_WRITE_BARRIER);
      SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                       SKIP_WRITE_BARRIER);
      break;
    }
482
    default:
483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
      UNREACHABLE();
  }
}

bool FeedbackNexus::Clear() {
  bool feedback_updated = false;

  switch (kind()) {
    case FeedbackSlotKind::kTypeProfile:
      // We don't clear these kinds ever.
      break;

    case FeedbackSlotKind::kCompareOp:
    case FeedbackSlotKind::kForIn:
    case FeedbackSlotKind::kBinaryOp:
      // We don't clear these, either.
      break;

    case FeedbackSlotKind::kLiteral:
502
      SetFeedback(Smi::zero(), SKIP_WRITE_BARRIER);
503 504 505 506 507 508 509
      feedback_updated = true;
      break;

    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict:
510
    case FeedbackSlotKind::kStoreInArrayLiteral:
511 512 513
    case FeedbackSlotKind::kStoreOwnNamed:
    case FeedbackSlotKind::kLoadProperty:
    case FeedbackSlotKind::kLoadKeyed:
514
    case FeedbackSlotKind::kHasKeyed:
515 516 517 518 519 520 521
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    case FeedbackSlotKind::kCall:
    case FeedbackSlotKind::kInstanceOf:
    case FeedbackSlotKind::kStoreDataPropertyInLiteral:
522
    case FeedbackSlotKind::kCloneObject:
523 524 525 526 527 528 529 530 531 532 533
      if (!IsCleared()) {
        ConfigureUninitialized();
        feedback_updated = true;
      }
      break;

    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
  }
  return feedback_updated;
534 535
}

536 537 538
bool FeedbackNexus::ConfigureMegamorphic() {
  DisallowHeapAllocation no_gc;
  Isolate* isolate = GetIsolate();
539
  MaybeObject sentinel =
540 541 542
      MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
  if (GetFeedback() != sentinel) {
    SetFeedback(sentinel, SKIP_WRITE_BARRIER);
543
    SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
544 545 546 547 548 549
    return true;
  }

  return false;
}

550 551
bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
  DisallowHeapAllocation no_gc;
552
  Isolate* isolate = GetIsolate();
553
  bool changed = false;
554
  MaybeObject sentinel =
555
      MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
556 557 558 559 560
  if (GetFeedback() != sentinel) {
    SetFeedback(sentinel, SKIP_WRITE_BARRIER);
    changed = true;
  }

561
  Smi extra = Smi::FromInt(static_cast<int>(property_type));
562
  if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
563 564 565 566
    SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
    changed = true;
  }
  return changed;
567
}
568

569
Map FeedbackNexus::GetFirstMap() const {
570 571
  MapHandles maps;
  ExtractMaps(&maps);
572
  if (!maps.empty()) return *maps.at(0);
573 574 575
  return Map();
}

576
InlineCacheState FeedbackNexus::ic_state() const {
577
  Isolate* isolate = GetIsolate();
578
  MaybeObject feedback = GetFeedback();
579

580 581
  switch (kind()) {
    case FeedbackSlotKind::kLiteral:
582 583
      if (feedback->IsSmi()) return UNINITIALIZED;
      return MONOMORPHIC;
584

585 586 587 588 589
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
      if (feedback->IsSmi()) return MONOMORPHIC;
590

591
      DCHECK(feedback->IsWeakOrCleared());
592
      MaybeObject extra = GetFeedbackExtra();
593
      if (!feedback->IsCleared() ||
594 595
          extra != MaybeObject::FromObject(
                       *FeedbackVector::UninitializedSentinel(isolate))) {
596 597 598 599
        return MONOMORPHIC;
      }
      return UNINITIALIZED;
    }
600

601 602 603 604
    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict:
605
    case FeedbackSlotKind::kStoreInArrayLiteral:
606 607
    case FeedbackSlotKind::kStoreOwnNamed:
    case FeedbackSlotKind::kLoadProperty:
608 609
    case FeedbackSlotKind::kLoadKeyed:
    case FeedbackSlotKind::kHasKeyed: {
610 611
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
612
        return UNINITIALIZED;
613
      }
614 615
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::MegamorphicSentinel(isolate))) {
616
        return MEGAMORPHIC;
617
      }
618
      if (feedback->IsWeakOrCleared()) {
619 620
        // Don't check if the map is cleared.
        return MONOMORPHIC;
621
      }
622
      HeapObject heap_object;
623
      if (feedback->GetHeapObjectIfStrong(&heap_object)) {
624
        if (heap_object.IsWeakFixedArray()) {
625 626 627 628
          // Determine state purely by our structure, don't check if the maps
          // are cleared.
          return POLYMORPHIC;
        }
629
        if (heap_object.IsName()) {
630 631
          DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
                 IsKeyedHasICKind(kind()));
632
          Object extra = GetFeedbackExtra()->GetHeapObjectAssumeStrong();
633
          WeakFixedArray extra_array = WeakFixedArray::cast(extra);
634
          return extra_array.length() > 2 ? POLYMORPHIC : MONOMORPHIC;
635
        }
636
      }
637
      UNREACHABLE();
638 639
    }
    case FeedbackSlotKind::kCall: {
640
      HeapObject heap_object;
641 642
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::MegamorphicSentinel(isolate))) {
643
        return GENERIC;
644 645 646 647 648 649 650 651 652 653
      } else if (feedback->IsWeakOrCleared()) {
        if (feedback->GetHeapObjectIfWeak(&heap_object)) {
          if (heap_object.IsFeedbackCell()) {
            return POLYMORPHIC;
          }
          CHECK(heap_object.IsJSFunction() || heap_object.IsJSBoundFunction());
        }
        return MONOMORPHIC;
      } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
                 heap_object.IsAllocationSite()) {
654 655
        return MONOMORPHIC;
      }
656

657 658
      CHECK_EQ(feedback, MaybeObject::FromObject(
                             *FeedbackVector::UninitializedSentinel(isolate)));
659 660 661 662 663 664 665 666 667
      return UNINITIALIZED;
    }
    case FeedbackSlotKind::kBinaryOp: {
      BinaryOperationHint hint = GetBinaryOperationFeedback();
      if (hint == BinaryOperationHint::kNone) {
        return UNINITIALIZED;
      } else if (hint == BinaryOperationHint::kAny) {
        return GENERIC;
      }
668

669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690
      return MONOMORPHIC;
    }
    case FeedbackSlotKind::kCompareOp: {
      CompareOperationHint hint = GetCompareOperationFeedback();
      if (hint == CompareOperationHint::kNone) {
        return UNINITIALIZED;
      } else if (hint == CompareOperationHint::kAny) {
        return GENERIC;
      }

      return MONOMORPHIC;
    }
    case FeedbackSlotKind::kForIn: {
      ForInHint hint = GetForInFeedback();
      if (hint == ForInHint::kNone) {
        return UNINITIALIZED;
      } else if (hint == ForInHint::kAny) {
        return GENERIC;
      }
      return MONOMORPHIC;
    }
    case FeedbackSlotKind::kInstanceOf: {
691 692
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
693
        return UNINITIALIZED;
694 695 696
      } else if (feedback ==
                 MaybeObject::FromObject(
                     *FeedbackVector::MegamorphicSentinel(isolate))) {
697 698 699 700 701
        return MEGAMORPHIC;
      }
      return MONOMORPHIC;
    }
    case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
702 703
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
704
        return UNINITIALIZED;
705
      } else if (feedback->IsWeakOrCleared()) {
706 707 708 709 710 711 712
        // Don't check if the map is cleared.
        return MONOMORPHIC;
      }

      return MEGAMORPHIC;
    }
    case FeedbackSlotKind::kTypeProfile: {
713 714
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
715 716 717 718 719
        return UNINITIALIZED;
      }
      return MONOMORPHIC;
    }

720 721 722 723 724 725 726 727 728
    case FeedbackSlotKind::kCloneObject: {
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
        return UNINITIALIZED;
      }
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::MegamorphicSentinel(isolate))) {
        return MEGAMORPHIC;
      }
729
      if (feedback->IsWeakOrCleared()) {
730 731 732
        return MONOMORPHIC;
      }

733
      DCHECK(feedback->GetHeapObjectAssumeStrong().IsWeakFixedArray());
734 735 736
      return POLYMORPHIC;
    }

737 738 739 740 741
    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
  }
  return UNINITIALIZED;
742 743
}

744 745
void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
  DCHECK(IsGlobalICKind(kind()));
746
  Isolate* isolate = GetIsolate();
747
  SetFeedback(HeapObjectReference::Weak(*cell));
748 749 750 751
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                   SKIP_WRITE_BARRIER);
}

752
bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
753 754
                                            int context_slot_index,
                                            bool immutable) {
755
  DCHECK(IsGlobalICKind(kind()));
756 757 758
  DCHECK_LE(0, script_context_index);
  DCHECK_LE(0, context_slot_index);
  if (!ContextIndexBits::is_valid(script_context_index) ||
759 760
      !SlotIndexBits::is_valid(context_slot_index) ||
      !ImmutabilityBit::is_valid(immutable)) {
761 762 763
    return false;
  }
  int config = ContextIndexBits::encode(script_context_index) |
764 765 766
               SlotIndexBits::encode(context_slot_index) |
               ImmutabilityBit::encode(immutable);

767
  SetFeedback(Smi::From31BitPattern(config));
768 769 770 771 772 773
  Isolate* isolate = GetIsolate();
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                   SKIP_WRITE_BARRIER);
  return true;
}

774
void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
775
  DCHECK(IsGlobalICKind(kind()));
776
  DCHECK(IC::IsHandler(*handler));
777
  SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()));
778
  SetFeedbackExtra(*handler);
779 780
}

781 782 783
void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
                                         Handle<Map> result_map) {
  Isolate* isolate = GetIsolate();
784 785 786 787 788 789 790 791 792
  Handle<HeapObject> feedback;
  {
    MaybeObject maybe_feedback = GetFeedback();
    if (maybe_feedback->IsStrongOrWeak()) {
      feedback = handle(maybe_feedback->GetHeapObject(), isolate);
    } else {
      DCHECK(maybe_feedback->IsCleared());
    }
  }
793 794 795 796 797 798 799
  switch (ic_state()) {
    case UNINITIALIZED:
      // Cache the first map seen which meets the fast case requirements.
      SetFeedback(HeapObjectReference::Weak(*source_map));
      SetFeedbackExtra(*result_map);
      break;
    case MONOMORPHIC:
800
      if (feedback.is_null() || feedback.is_identical_to(source_map) ||
801
          Map::cast(*feedback).is_deprecated()) {
802 803 804 805 806 807
        SetFeedback(HeapObjectReference::Weak(*source_map));
        SetFeedbackExtra(*result_map);
      } else {
        // Transition to POLYMORPHIC.
        Handle<WeakFixedArray> array =
            EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
808
        array->Set(0, HeapObjectReference::Weak(*feedback));
809 810 811
        array->Set(1, GetFeedbackExtra());
        array->Set(2, HeapObjectReference::Weak(*source_map));
        array->Set(3, MaybeObject::FromObject(*result_map));
812
        SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
813 814 815
      }
      break;
    case POLYMORPHIC: {
816 817
      const int kMaxElements =
          FLAG_max_polymorphic_map_count * kCloneObjectPolymorphicEntrySize;
818 819 820
      Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
      int i = 0;
      for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
821 822 823 824
        MaybeObject feedback_map = array->Get(i);
        if (feedback_map->IsCleared()) break;
        Handle<Map> cached_map(Map::cast(feedback_map->GetHeapObject()),
                               isolate);
825 826
        if (cached_map.is_identical_to(source_map) ||
            cached_map->is_deprecated())
827 828 829 830 831 832
          break;
      }

      if (i >= array->length()) {
        if (i == kMaxElements) {
          // Transition to MEGAMORPHIC.
833
          MaybeObject sentinel = MaybeObject::FromObject(
834 835
              *FeedbackVector::MegamorphicSentinel(isolate));
          SetFeedback(sentinel, SKIP_WRITE_BARRIER);
836
          SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858
          break;
        }

        // Grow polymorphic feedback array.
        Handle<WeakFixedArray> new_array = EnsureArrayOfSize(
            array->length() + kCloneObjectPolymorphicEntrySize);
        for (int j = 0; j < array->length(); ++j) {
          new_array->Set(j, array->Get(j));
        }
        array = new_array;
      }

      array->Set(i, HeapObjectReference::Weak(*source_map));
      array->Set(i + 1, MaybeObject::FromObject(*result_map));
      break;
    }

    default:
      UNREACHABLE();
  }
}

859 860
int FeedbackNexus::GetCallCount() {
  DCHECK(IsCallICKind(kind()));
861

862
  Object call_count = GetFeedbackExtra()->cast<Object>();
863
  CHECK(call_count.IsSmi());
864 865
  uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
  return CallCountField::decode(value);
866 867
}

868 869 870
void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
  DCHECK(IsCallICKind(kind()));

871
  Object call_count = GetFeedbackExtra()->cast<Object>();
872
  CHECK(call_count.IsSmi());
873 874 875
  uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
  uint32_t value = CallCountField::encode(CallCountField::decode(count));
  int result = static_cast<int>(value | SpeculationModeField::encode(mode));
876 877 878
  SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
}

879 880 881
SpeculationMode FeedbackNexus::GetSpeculationMode() {
  DCHECK(IsCallICKind(kind()));

882
  Object call_count = GetFeedbackExtra()->cast<Object>();
883
  CHECK(call_count.IsSmi());
884 885 886
  uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
  return SpeculationModeField::decode(value);
}
887 888 889 890

float FeedbackNexus::ComputeCallFrequency() {
  DCHECK(IsCallICKind(kind()));

891
  double const invocation_count = vector().invocation_count();
892
  double const call_count = GetCallCount();
893
  if (invocation_count == 0.0) {  // Prevent division by 0.
894 895
    return 0.0f;
  }
896 897 898
  return static_cast<float>(call_count / invocation_count);
}

899 900
void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
                                         Handle<Map> receiver_map,
901
                                         const MaybeObjectHandle& handler) {
902
  DCHECK(handler.is_null() || IC::IsHandler(*handler));
903
  if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
904
    SetFeedback(HeapObjectReference::Weak(*receiver_map));
905
    SetFeedbackExtra(*name);
906
  } else {
907
    if (name.is_null()) {
908
      SetFeedback(HeapObjectReference::Weak(*receiver_map));
909
      SetFeedbackExtra(*handler);
910
    } else {
911
      Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
912
      SetFeedback(*name);
913
      array->Set(0, HeapObjectReference::Weak(*receiver_map));
914
      array->Set(1, *handler);
915
    }
916
  }
917 918
}

919 920 921
void FeedbackNexus::ConfigurePolymorphic(
    Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers) {
  int receiver_count = static_cast<int>(maps_and_handlers.size());
922
  DCHECK_GT(receiver_count, 1);
923
  Handle<WeakFixedArray> array;
924
  if (name.is_null()) {
925
    array = EnsureArrayOfSize(receiver_count * 2);
926
    SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
927
                     SKIP_WRITE_BARRIER);
928
  } else {
929
    array = EnsureExtraArrayOfSize(receiver_count * 2);
930
    SetFeedback(*name);
931
  }
932

933
  for (int current = 0; current < receiver_count; ++current) {
934
    Handle<Map> map = maps_and_handlers[current].first;
935
    array->Set(current * 2, HeapObjectReference::Weak(*map));
936 937 938
    MaybeObjectHandle handler = maps_and_handlers[current].second;
    DCHECK(IC::IsHandler(*handler));
    array->Set(current * 2 + 1, *handler);
939
  }
940 941
}

942
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
943 944
  DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
         IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
945
         IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
946
         IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
947

948
  DisallowHeapAllocation no_gc;
949
  Isolate* isolate = GetIsolate();
950
  MaybeObject feedback = GetFeedback();
951
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
952
  HeapObject heap_object;
953
  if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
954
       heap_object.IsWeakFixedArray()) ||
955
      is_named_feedback) {
956
    int found = 0;
957
    WeakFixedArray array;
958
    if (is_named_feedback) {
959 960
      array =
          WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
961
    } else {
962
      array = WeakFixedArray::cast(heap_object);
963
    }
964
    const int increment = 2;
965
    HeapObject heap_object;
966 967 968
    for (int i = 0; i < array.length(); i += increment) {
      DCHECK(array.Get(i)->IsWeakOrCleared());
      if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) {
969
        Map map = Map::cast(heap_object);
970
        maps->push_back(handle(map, isolate));
971 972
        found++;
      }
973
    }
974
    return found;
975
  } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
976
    Map map = Map::cast(heap_object);
977 978
    maps->push_back(handle(map, isolate));
    return 1;
979 980 981 982 983
  }

  return 0;
}

984 985
int FeedbackNexus::ExtractMapsAndHandlers(
    std::vector<std::pair<Handle<Map>, MaybeObjectHandle>>* maps_and_handlers,
986
    bool try_update_deprecated) const {
987 988 989 990
  DCHECK(IsLoadICKind(kind()) ||
         IsStoreICKind(kind()) | IsKeyedLoadICKind(kind()) ||
         IsKeyedStoreICKind(kind()) || IsStoreOwnICKind(kind()) ||
         IsStoreDataPropertyInLiteralKind(kind()) ||
991
         IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
992

993
  DisallowHeapAllocation no_gc;
994
  Isolate* isolate = GetIsolate();
995
  MaybeObject feedback = GetFeedback();
996
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
997
  HeapObject heap_object;
998
  if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
999
       heap_object.IsWeakFixedArray()) ||
1000
      is_named_feedback) {
1001
    int found = 0;
1002
    WeakFixedArray array;
1003
    if (is_named_feedback) {
1004 1005
      array =
          WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1006
    } else {
1007
      array = WeakFixedArray::cast(heap_object);
1008
    }
1009
    const int increment = 2;
1010
    HeapObject heap_object;
1011
    maps_and_handlers->reserve(array.length() / increment);
1012 1013 1014
    for (int i = 0; i < array.length(); i += increment) {
      DCHECK(array.Get(i)->IsWeakOrCleared());
      if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) {
1015 1016
        MaybeObject handler = array.Get(i + 1);
        if (!handler->IsCleared()) {
1017
          DCHECK(IC::IsHandler(handler));
1018 1019 1020 1021 1022
          Handle<Map> map(Map::cast(heap_object), isolate);
          if (try_update_deprecated &&
              !Map::TryUpdate(isolate, map).ToHandle(&map)) {
            continue;
          }
1023
          maps_and_handlers->push_back(
1024
              MapAndHandler(map, handle(handler, isolate)));
1025
          found++;
1026
        }
1027 1028
      }
    }
1029
    return found;
1030
  } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1031 1032
    MaybeObject handler = GetFeedbackExtra();
    if (!handler->IsCleared()) {
1033
      DCHECK(IC::IsHandler(handler));
1034 1035 1036 1037 1038
      Handle<Map> map = handle(Map::cast(heap_object), isolate);
      if (try_update_deprecated &&
          !Map::TryUpdate(isolate, map).ToHandle(&map)) {
        return 0;
      }
1039
      maps_and_handlers->push_back(
1040
          MapAndHandler(map, handle(handler, isolate)));
1041
      return 1;
1042
    }
1043 1044
  }

1045
  return 0;
1046 1047
}

1048
MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
1049 1050
  DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
         IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
1051
         IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
1052
         IsKeyedHasICKind(kind()));
1053

1054
  MaybeObject feedback = GetFeedback();
1055
  Isolate* isolate = GetIsolate();
1056
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
1057
  HeapObject heap_object;
1058
  if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1059
       heap_object.IsWeakFixedArray()) ||
1060
      is_named_feedback) {
1061
    WeakFixedArray array;
1062
    if (is_named_feedback) {
1063 1064
      array =
          WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1065
    } else {
1066
      array = WeakFixedArray::cast(heap_object);
1067
    }
1068
    const int increment = 2;
1069
    HeapObject heap_object;
1070 1071
    for (int i = 0; i < array.length(); i += increment) {
      DCHECK(array.Get(i)->IsWeakOrCleared());
1072 1073 1074 1075 1076 1077 1078
      if (array.Get(i)->GetHeapObjectIfWeak(&heap_object)) {
        Map array_map = Map::cast(heap_object);
        if (array_map == *map && !array.Get(i + increment - 1)->IsCleared()) {
          MaybeObject handler = array.Get(i + increment - 1);
          DCHECK(IC::IsHandler(handler));
          return handle(handler, isolate);
        }
1079
      }
1080
    }
1081
  } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1082 1083 1084 1085 1086
    Map cell_map = Map::cast(heap_object);
    if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) {
      MaybeObject handler = GetFeedbackExtra();
      DCHECK(IC::IsHandler(handler));
      return handle(handler, isolate);
1087
    }
1088
  }
1089 1090

  return MaybeObjectHandle();
1091
}
1092

1093
Name FeedbackNexus::GetName() const {
1094 1095
  if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
      IsKeyedHasICKind(kind())) {
1096
    MaybeObject feedback = GetFeedback();
1097
    if (IsPropertyNameFeedback(feedback)) {
1098
      return Name::cast(feedback->GetHeapObjectAssumeStrong());
1099
    }
1100
  }
1101 1102 1103 1104 1105 1106
  if (IsStoreDataPropertyInLiteralKind(kind())) {
    MaybeObject extra = GetFeedbackExtra();
    if (IsPropertyNameFeedback(extra)) {
      return Name::cast(extra->GetHeapObjectAssumeStrong());
    }
  }
1107
  return Name();
1108 1109
}

1110
KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1111
  DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedHasICKind(kind()));
1112

1113
  if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1114

1115 1116 1117 1118 1119
  std::vector<MapAndHandler> maps_and_handlers;
  ExtractMapsAndHandlers(&maps_and_handlers);
  for (MapAndHandler map_and_handler : maps_and_handlers) {
    KeyedAccessLoadMode mode =
        LoadHandler::GetKeyedAccessLoadMode(*map_and_handler.second);
1120
    if (mode != STANDARD_LOAD) return mode;
1121 1122
  }

1123
  return STANDARD_LOAD;
1124 1125
}

1126 1127 1128 1129 1130 1131 1132 1133 1134
namespace {

bool BuiltinHasKeyedAccessStoreMode(int builtin_index) {
  DCHECK(Builtins::IsBuiltinId(builtin_index));
  switch (builtin_index) {
    case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
    case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
    case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
    case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1135 1136 1137 1138 1139 1140 1141 1142
    case Builtins::kStoreFastElementIC_Standard:
    case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
    case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
    case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
    case Builtins::kElementsTransitionAndStore_Standard:
    case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
    case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
    case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
      return true;
    default:
      return false;
  }
  UNREACHABLE();
}

KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
  DCHECK(BuiltinHasKeyedAccessStoreMode(builtin_index));
  switch (builtin_index) {
    case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1154 1155
    case Builtins::kStoreFastElementIC_Standard:
    case Builtins::kElementsTransitionAndStore_Standard:
1156 1157
      return STANDARD_STORE;
    case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1158 1159
    case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
    case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1160
      return STORE_AND_GROW_HANDLE_COW;
1161
    case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1162 1163
    case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
    case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1164
      return STORE_IGNORE_OUT_OF_BOUNDS;
1165
    case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1166 1167
    case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
    case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1168
      return STORE_HANDLE_COW;
1169 1170 1171 1172 1173 1174 1175
    default:
      UNREACHABLE();
  }
}

}  // namespace

1176
KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1177 1178
  DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()) ||
         IsStoreDataPropertyInLiteralKind(kind()));
1179 1180 1181 1182
  KeyedAccessStoreMode mode = STANDARD_STORE;

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

1183 1184 1185 1186
  std::vector<MapAndHandler> maps_and_handlers;
  ExtractMapsAndHandlers(&maps_and_handlers);
  for (const MapAndHandler& map_and_handler : maps_and_handlers) {
    const MaybeObjectHandle maybe_code_handler = map_and_handler.second;
1187
    // The first handler that isn't the slow handler will have the bits we need.
1188
    Handle<Code> handler;
1189
    if (maybe_code_handler.object()->IsStoreHandler()) {
1190
      Handle<StoreHandler> data_handler =
1191
          Handle<StoreHandler>::cast(maybe_code_handler.object());
1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203

      if ((data_handler->smi_handler()).IsSmi()) {
        // Decode the KeyedAccessStoreMode information from the Handler.
        mode = StoreHandler::GetKeyedAccessStoreMode(
            MaybeObject::FromObject(data_handler->smi_handler()));
        if (mode != STANDARD_STORE) return mode;
        continue;
      } else {
        handler = handle(Code::cast(data_handler->smi_handler()),
                         vector().GetIsolate());
      }

1204
    } else if (maybe_code_handler.object()->IsSmi()) {
1205 1206 1207 1208 1209 1210 1211
      // Skip for Proxy Handlers.
      if (*(maybe_code_handler.object()) ==
          *StoreHandler::StoreProxy(GetIsolate()))
        continue;
      // Decode the KeyedAccessStoreMode information from the Handler.
      mode = StoreHandler::GetKeyedAccessStoreMode(*maybe_code_handler);
      if (mode != STANDARD_STORE) return mode;
1212
      continue;
1213
    } else {
1214
      // Element store without prototype chain check.
1215
      handler = Handle<Code>::cast(maybe_code_handler.object());
1216
    }
1217 1218 1219 1220 1221 1222

    if (handler->is_builtin()) {
      const int builtin_index = handler->builtin_index();
      if (!BuiltinHasKeyedAccessStoreMode(builtin_index)) continue;

      mode = KeyedAccessStoreModeForBuiltin(builtin_index);
1223 1224 1225 1226 1227 1228 1229
      break;
    }
  }

  return mode;
}

1230
IcCheckType FeedbackNexus::GetKeyType() const {
1231
  DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1232 1233
         IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()) ||
         IsStoreDataPropertyInLiteralKind(kind()));
1234
  MaybeObject feedback = GetFeedback();
1235 1236
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
1237 1238
    return static_cast<IcCheckType>(
        Smi::ToInt(GetFeedbackExtra()->cast<Object>()));
1239
  }
1240 1241 1242
  MaybeObject maybe_name =
      IsStoreDataPropertyInLiteralKind(kind()) ? GetFeedbackExtra() : feedback;
  return IsPropertyNameFeedback(maybe_name) ? PROPERTY : ELEMENT;
1243
}
1244

1245 1246
BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1247
  int feedback = GetFeedback().ToSmi().value();
1248 1249 1250
  return BinaryOperationHintFromFeedback(feedback);
}

1251 1252
CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1253
  int feedback = GetFeedback().ToSmi().value();
1254 1255 1256
  return CompareOperationHintFromFeedback(feedback);
}

1257 1258
ForInHint FeedbackNexus::GetForInFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1259
  int feedback = GetFeedback().ToSmi().value();
1260
  return ForInHintFromFeedback(feedback);
1261 1262
}

1263 1264
MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1265
  Isolate* isolate = GetIsolate();
1266
  MaybeObject feedback = GetFeedback();
1267
  HeapObject heap_object;
1268
  if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1269
    return handle(JSObject::cast(heap_object), isolate);
1270 1271 1272 1273
  }
  return MaybeHandle<JSObject>();
}

1274 1275 1276 1277
namespace {

bool InList(Handle<ArrayList> types, Handle<String> type) {
  for (int i = 0; i < types->Length(); i++) {
1278
    Object obj = types->Get(i);
1279
    if (String::cast(obj).Equals(*type)) {
1280 1281 1282 1283 1284 1285 1286
      return true;
    }
  }
  return false;
}
}  // anonymous namespace

1287 1288
void FeedbackNexus::Collect(Handle<String> type, int position) {
  DCHECK(IsTypeProfileKind(kind()));
1289
  DCHECK_GE(position, 0);
1290 1291
  Isolate* isolate = GetIsolate();

1292
  MaybeObject const feedback = GetFeedback();
1293 1294

  // Map source position to collection of types
1295
  Handle<SimpleNumberDictionary> types;
1296

1297 1298
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1299
    types = SimpleNumberDictionary::New(isolate, 1);
1300
  } else {
1301 1302 1303
    types = handle(
        SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
        isolate);
1304
  }
1305

1306
  Handle<ArrayList> position_specific_types;
1307

1308 1309
  InternalIndex entry = types->FindEntry(isolate, position);
  if (entry.is_not_found()) {
1310
    position_specific_types = ArrayList::New(isolate, 1);
1311
    types = SimpleNumberDictionary::Set(
1312 1313
        isolate, types, position,
        ArrayList::Add(isolate, position_specific_types, type));
1314
  } else {
1315
    DCHECK(types->ValueAt(entry).IsArrayList());
1316 1317
    position_specific_types =
        handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1318
    if (!InList(position_specific_types, type)) {  // Add type
1319
      types = SimpleNumberDictionary::Set(
1320 1321
          isolate, types, position,
          ArrayList::Add(isolate, position_specific_types, type));
1322
    }
1323 1324
  }
  SetFeedback(*types);
1325 1326
}

1327 1328
std::vector<int> FeedbackNexus::GetSourcePositions() const {
  DCHECK(IsTypeProfileKind(kind()));
1329 1330 1331
  std::vector<int> source_positions;
  Isolate* isolate = GetIsolate();

1332
  MaybeObject const feedback = GetFeedback();
1333

1334 1335
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1336 1337 1338
    return source_positions;
  }

1339
  Handle<SimpleNumberDictionary> types(
1340 1341
      SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
      isolate);
1342

1343 1344 1345
  for (int index = SimpleNumberDictionary::kElementsStartIndex;
       index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
    int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1346
    Object key = types->get(key_index);
1347 1348
    if (key.IsSmi()) {
      int position = Smi::cast(key).value();
1349 1350 1351 1352 1353 1354
      source_positions.push_back(position);
    }
  }
  return source_positions;
}

1355
std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1356
    uint32_t position) const {
1357
  DCHECK(IsTypeProfileKind(kind()));
1358 1359
  Isolate* isolate = GetIsolate();

1360
  MaybeObject const feedback = GetFeedback();
1361
  std::vector<Handle<String>> types_for_position;
1362 1363
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1364 1365 1366
    return types_for_position;
  }

1367
  Handle<SimpleNumberDictionary> types(
1368 1369
      SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
      isolate);
1370

1371 1372 1373
  InternalIndex entry = types->FindEntry(isolate, position);
  if (entry.is_not_found()) return types_for_position;

1374
  DCHECK(types->ValueAt(entry).IsArrayList());
1375
  Handle<ArrayList> position_specific_types =
1376
      Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1377
  for (int i = 0; i < position_specific_types->Length(); i++) {
1378
    Object t = position_specific_types->Get(i);
1379 1380 1381 1382 1383 1384
    types_for_position.push_back(Handle<String>(String::cast(t), isolate));
  }

  return types_for_position;
}

1385 1386
namespace {

1387
Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1388
                                   Handle<SimpleNumberDictionary> feedback) {
1389 1390
  Handle<JSObject> type_profile =
      isolate->factory()->NewJSObject(isolate->object_function());
1391

1392 1393 1394 1395
  for (int index = SimpleNumberDictionary::kElementsStartIndex;
       index < feedback->length();
       index += SimpleNumberDictionary::kEntrySize) {
    int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1396
    Object key = feedback->get(key_index);
1397
    if (key.IsSmi()) {
1398
      int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1399

1400
      Handle<ArrayList> position_specific_types(
1401
          ArrayList::cast(feedback->get(value_index)), isolate);
1402

jgruber's avatar
jgruber committed
1403
      int position = Smi::ToInt(key);
1404 1405 1406
      JSObject::AddDataElement(
          type_profile, position,
          isolate->factory()->NewJSArrayWithElements(
1407
              ArrayList::Elements(isolate, position_specific_types)),
1408
          PropertyAttributes::NONE);
1409 1410
    }
  }
1411
  return type_profile;
1412 1413 1414
}
}  // namespace

1415
JSObject FeedbackNexus::GetTypeProfile() const {
1416
  DCHECK(IsTypeProfileKind(kind()));
1417 1418
  Isolate* isolate = GetIsolate();

1419
  MaybeObject const feedback = GetFeedback();
1420

1421 1422
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1423
    return *isolate->factory()->NewJSObject(isolate->object_function());
1424 1425
  }

1426 1427 1428 1429
  return *ConvertToJSObject(isolate,
                            handle(SimpleNumberDictionary::cast(
                                       feedback->GetHeapObjectAssumeStrong()),
                                   isolate));
1430 1431
}

1432 1433 1434 1435 1436
void FeedbackNexus::ResetTypeProfile() {
  DCHECK(IsTypeProfileKind(kind()));
  SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
}

1437 1438
}  // namespace internal
}  // namespace v8