feedback-vector.cc 51.1 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

7
#include "src/common/globals.h"
8
#include "src/deoptimizer/deoptimizer.h"
9
#include "src/diagnostics/code-tracer.h"
10
#include "src/heap/heap-inl.h"
11
#include "src/heap/local-factory-inl.h"
12
#include "src/ic/handler-configuration-inl.h"
13
#include "src/ic/ic-inl.h"
14
#include "src/objects/data-handler-inl.h"
15
#include "src/objects/feedback-vector-inl.h"
16
#include "src/objects/hash-table-inl.h"
17
#include "src/objects/map-inl.h"
18
#include "src/objects/object-macros.h"
19
#include "src/objects/objects.h"
20 21 22 23

namespace v8 {
namespace internal {

24
FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
25
  int slot = slot_count();
26
  int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
27
  append(kind);
28
  for (int i = 1; i < entries_per_slot; i++) {
29
    append(FeedbackSlotKind::kInvalid);
30 31 32 33
  }
  return FeedbackSlot(slot);
}

34
FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
35 36 37 38 39 40
  FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
  CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
           FeedbackVector::GetIndex(slot));
  return slot;
}

41 42 43
bool FeedbackVectorSpec::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
44
  if (slot_count() <= slot.ToInt()) return false;
45 46 47
  return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
}

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

63
std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
64
  return os << FeedbackMetadata::Kind2String(kind);
65 66
}

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

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

80
// static
81 82
template <typename IsolateT>
Handle<FeedbackMetadata> FeedbackMetadata::New(IsolateT* isolate,
83
                                               const FeedbackVectorSpec* spec) {
84
  auto* factory = isolate->factory();
85

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

105
  Handle<FeedbackMetadata> metadata =
106
      factory->NewFeedbackMetadata(slot_count, create_closure_slot_count);
107

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

117 118 119
  return metadata;
}

120 121 122
template Handle<FeedbackMetadata> FeedbackMetadata::New(
    Isolate* isolate, const FeedbackVectorSpec* spec);
template Handle<FeedbackMetadata> FeedbackMetadata::New(
123
    LocalIsolate* isolate, const FeedbackVectorSpec* spec);
124

125
bool FeedbackMetadata::SpecDiffersFrom(
126
    const FeedbackVectorSpec* other_spec) const {
127
  if (other_spec->slot_count() != slot_count()) {
128 129 130 131
    return true;
  }

  int slots = slot_count();
132
  for (int i = 0; i < slots;) {
133 134
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = GetKind(slot);
135
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
136

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

145
const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
146
  switch (kind) {
147
    case FeedbackSlotKind::kInvalid:
148
      return "Invalid";
149
    case FeedbackSlotKind::kCall:
150
      return "Call";
151
    case FeedbackSlotKind::kLoadProperty:
152
      return "LoadProperty";
153
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
154
      return "LoadGlobalInsideTypeof";
155
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
156
      return "LoadGlobalNotInsideTypeof";
157
    case FeedbackSlotKind::kLoadKeyed:
158
      return "LoadKeyed";
159 160
    case FeedbackSlotKind::kHasKeyed:
      return "HasKeyed";
161 162 163 164 165 166 167 168
    case FeedbackSlotKind::kSetNamedSloppy:
      return "SetNamedSloppy";
    case FeedbackSlotKind::kSetNamedStrict:
      return "SetNamedStrict";
    case FeedbackSlotKind::kDefineNamedOwn:
      return "DefineNamedOwn";
    case FeedbackSlotKind::kDefineKeyedOwn:
      return "DefineKeyedOwn";
169 170 171 172
    case FeedbackSlotKind::kStoreGlobalSloppy:
      return "StoreGlobalSloppy";
    case FeedbackSlotKind::kStoreGlobalStrict:
      return "StoreGlobalStrict";
173
    case FeedbackSlotKind::kSetKeyedSloppy:
174
      return "StoreKeyedSloppy";
175
    case FeedbackSlotKind::kSetKeyedStrict:
176
      return "StoreKeyedStrict";
177 178
    case FeedbackSlotKind::kStoreInArrayLiteral:
      return "StoreInArrayLiteral";
179
    case FeedbackSlotKind::kBinaryOp:
180
      return "BinaryOp";
181
    case FeedbackSlotKind::kCompareOp:
182
      return "CompareOp";
183 184
    case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral:
      return "DefineKeyedOwnPropertyInLiteral";
185
    case FeedbackSlotKind::kLiteral:
186
      return "Literal";
187
    case FeedbackSlotKind::kTypeProfile:
188
      return "TypeProfile";
189 190
    case FeedbackSlotKind::kForIn:
      return "ForIn";
191 192
    case FeedbackSlotKind::kInstanceOf:
      return "InstanceOf";
193 194
    case FeedbackSlotKind::kCloneObject:
      return "CloneObject";
195
    case FeedbackSlotKind::kKindsNumber:
196 197 198 199 200
      break;
  }
  UNREACHABLE();
}

201 202 203
bool FeedbackMetadata::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
204
  return slot.ToInt() < slot_count() &&
205
         GetKind(slot) == FeedbackSlotKind::kTypeProfile;
206 207
}

208
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
209
  DCHECK(!is_empty());
210
  return metadata().GetKind(slot);
211
}
212

213 214 215 216 217 218
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot,
                                         AcquireLoadTag tag) const {
  DCHECK(!is_empty());
  return metadata(tag).GetKind(slot);
}

219
FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
220
  DCHECK(metadata().HasTypeProfileSlot());
221 222 223 224
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
  return slot;
225 226
}

227 228 229 230 231 232
// static
Handle<ClosureFeedbackCellArray> ClosureFeedbackCellArray::New(
    Isolate* isolate, Handle<SharedFunctionInfo> shared) {
  Factory* factory = isolate->factory();

  int num_feedback_cells =
233
      shared->feedback_metadata().create_closure_slot_count();
234 235 236 237 238 239 240

  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());
241
    feedback_cell_array->set(i, *cell);
242 243 244 245
  }
  return feedback_cell_array;
}

246
// static
247 248
Handle<FeedbackVector> FeedbackVector::New(
    Isolate* isolate, Handle<SharedFunctionInfo> shared,
249 250 251
    Handle<ClosureFeedbackCellArray> closure_feedback_cell_array,
    IsCompiledScope* is_compiled_scope) {
  DCHECK(is_compiled_scope->is_compiled());
252 253 254 255 256 257 258 259
  Factory* factory = isolate->factory();

  Handle<FeedbackMetadata> feedback_metadata(shared->feedback_metadata(),
                                             isolate);
  const int slot_count = feedback_metadata->slot_count();

  Handle<FeedbackVector> vector =
      factory->NewFeedbackVector(shared, closure_feedback_cell_array);
260

261 262 263
  DCHECK_EQ(vector->length(), slot_count);

  DCHECK_EQ(vector->shared_function_info(), *shared);
264
  DCHECK_EQ(vector->optimization_marker(), OptimizationMarker::kNone);
265
  DCHECK(!vector->maybe_has_optimized_code());
266 267 268 269 270 271 272 273 274
  DCHECK_EQ(vector->invocation_count(), 0);
  DCHECK_EQ(vector->profiler_ticks(), 0);
  DCHECK(vector->maybe_optimized_code()->IsCleared());

  // Ensure we can skip the write barrier
  Handle<Symbol> uninitialized_sentinel = UninitializedSentinel(isolate);
  DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
            *uninitialized_sentinel);
  for (int i = 0; i < slot_count;) {
275
    FeedbackSlot slot(i);
276 277 278 279
    FeedbackSlotKind kind = feedback_metadata->GetKind(slot);
    int entry_size = FeedbackMetadata::GetSlotSize(kind);

    MaybeObject extra_value = MaybeObject::FromObject(*uninitialized_sentinel);
280
    switch (kind) {
281 282
      case FeedbackSlotKind::kLoadGlobalInsideTypeof:
      case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
283 284
      case FeedbackSlotKind::kStoreGlobalSloppy:
      case FeedbackSlotKind::kStoreGlobalStrict:
285 286
        vector->Set(slot, HeapObjectReference::ClearedValue(isolate),
                    SKIP_WRITE_BARRIER);
287
        break;
288
      case FeedbackSlotKind::kForIn:
289 290
      case FeedbackSlotKind::kCompareOp:
      case FeedbackSlotKind::kBinaryOp:
291
        vector->Set(slot, Smi::zero(), SKIP_WRITE_BARRIER);
292
        break;
293
      case FeedbackSlotKind::kLiteral:
294
        vector->Set(slot, Smi::zero(), SKIP_WRITE_BARRIER);
295
        break;
296
      case FeedbackSlotKind::kCall:
297
        vector->Set(slot, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
298
        extra_value = MaybeObject::FromObject(Smi::zero());
299
        break;
300
      case FeedbackSlotKind::kCloneObject:
301 302
      case FeedbackSlotKind::kLoadProperty:
      case FeedbackSlotKind::kLoadKeyed:
303
      case FeedbackSlotKind::kHasKeyed:
304 305 306 307 308 309
      case FeedbackSlotKind::kSetNamedSloppy:
      case FeedbackSlotKind::kSetNamedStrict:
      case FeedbackSlotKind::kDefineNamedOwn:
      case FeedbackSlotKind::kDefineKeyedOwn:
      case FeedbackSlotKind::kSetKeyedSloppy:
      case FeedbackSlotKind::kSetKeyedStrict:
310
      case FeedbackSlotKind::kStoreInArrayLiteral:
311
      case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral:
312
      case FeedbackSlotKind::kTypeProfile:
313
      case FeedbackSlotKind::kInstanceOf:
314
        vector->Set(slot, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
315 316
        break;

317 318
      case FeedbackSlotKind::kInvalid:
      case FeedbackSlotKind::kKindsNumber:
319
        UNREACHABLE();
320
    }
321
    for (int j = 1; j < entry_size; j++) {
322
      vector->Set(slot.WithOffset(j), extra_value, SKIP_WRITE_BARRIER);
323 324 325
    }
    i += entry_size;
  }
326

327
  Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
328 329
  if (!isolate->is_best_effort_code_coverage() ||
      isolate->is_collecting_type_profile()) {
330
    AddToVectorsForProfilingTools(isolate, result);
331
  }
332
  return result;
333
}
334

335
namespace {
336

337 338 339
Handle<FeedbackVector> NewFeedbackVectorForTesting(
    Isolate* isolate, const FeedbackVectorSpec* spec) {
  Handle<FeedbackMetadata> metadata = FeedbackMetadata::New(isolate, spec);
340 341
  Handle<SharedFunctionInfo> shared =
      isolate->factory()->NewSharedFunctionInfoForBuiltin(
342
          isolate->factory()->empty_string(), Builtin::kIllegal);
343 344 345 346 347 348
  // Set the raw feedback metadata to circumvent checks that we are not
  // overwriting existing metadata.
  shared->set_raw_outer_scope_info_or_feedback_metadata(*metadata);
  Handle<ClosureFeedbackCellArray> closure_feedback_cell_array =
      ClosureFeedbackCellArray::New(isolate, shared);

349
  IsCompiledScope is_compiled_scope(shared->is_compiled_scope(isolate));
350 351
  return FeedbackVector::New(isolate, shared, closure_feedback_cell_array,
                             &is_compiled_scope);
352 353
}

354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
}  // namespace

// static
Handle<FeedbackVector> FeedbackVector::NewWithOneBinarySlotForTesting(
    Zone* zone, Isolate* isolate) {
  FeedbackVectorSpec one_slot(zone);
  one_slot.AddBinaryOpICSlot();
  return NewFeedbackVectorForTesting(isolate, &one_slot);
}

// static
Handle<FeedbackVector> FeedbackVector::NewWithOneCompareSlotForTesting(
    Zone* zone, Isolate* isolate) {
  FeedbackVectorSpec one_slot(zone);
  one_slot.AddCompareICSlot();
  return NewFeedbackVectorForTesting(isolate, &one_slot);
}

372
// static
373 374 375 376
void FeedbackVector::AddToVectorsForProfilingTools(
    Isolate* isolate, Handle<FeedbackVector> vector) {
  DCHECK(!isolate->is_best_effort_code_coverage() ||
         isolate->is_collecting_type_profile());
377
  if (!vector->shared_function_info().IsSubjectToDebugging()) return;
378 379
  Handle<ArrayList> list = Handle<ArrayList>::cast(
      isolate->factory()->feedback_vectors_for_profiling_tools());
380
  list = ArrayList::Add(isolate, list, vector);
381
  isolate->SetFeedbackVectorsForProfilingTools(*list);
382 383
}

384 385 386 387 388
void FeedbackVector::SaturatingIncrementProfilerTicks() {
  int ticks = profiler_ticks();
  if (ticks < Smi::kMaxValue) set_profiler_ticks(ticks + 1);
}

389 390
// static
void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
391
                                      Handle<CodeT> code) {
392
  DCHECK(CodeKindIsOptimizedJSFunction(code->kind()));
393
  // We should set optimized code only when there is no valid optimized code.
394 395
  DCHECK(!vector->has_optimized_code() ||
         vector->optimized_code().marked_for_deoptimization() ||
Georg Neis's avatar
Georg Neis committed
396
         FLAG_stress_concurrent_inlining_attach_code);
397
  // TODO(mythria): We could see a CompileOptimized marker here either from
398 399 400 401
  // tests that use %OptimizeFunctionOnNextCall, --always-opt or because we
  // re-mark the function for non-concurrent optimization after an OSR. We
  // should avoid these cases and also check that marker isn't
  // kCompileOptimized or kCompileOptimizedConcurrent.
402
  vector->set_maybe_optimized_code(HeapObjectReference::Weak(*code),
403
                                   kReleaseStore);
404 405
  int32_t state = vector->flags();
  state = OptimizationMarkerBits::update(state, OptimizationMarker::kNone);
406
  state = MaybeHasOptimizedCodeBit::update(state, true);
407
  vector->set_flags(state);
408 409
}

410
void FeedbackVector::ClearOptimizedCode() {
411
  DCHECK(has_optimized_code());
412
  DCHECK(maybe_has_optimized_code());
413 414
  set_maybe_optimized_code(HeapObjectReference::ClearedValue(GetIsolate()),
                           kReleaseStore);
415
  set_maybe_has_optimized_code(false);
416 417
}

418 419 420 421 422
void FeedbackVector::ClearOptimizationMarker() {
  SetOptimizationMarker(OptimizationMarker::kNone);
}

void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
423 424 425 426 427 428
  int32_t state = flags();
  state = OptimizationMarkerBits::update(state, marker);
  set_flags(state);
}

void FeedbackVector::InitializeOptimizationState() {
429 430
  set_flags(OptimizationMarkerBits::encode(OptimizationMarker::kNone) |
            MaybeHasOptimizedCodeBit::encode(false));
431 432 433
}

void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
434
    SharedFunctionInfo shared, const char* reason) {
435
  MaybeObject slot = maybe_optimized_code(kAcquireLoad);
436
  if (slot->IsCleared()) {
437
    set_maybe_has_optimized_code(false);
438 439 440
    return;
  }

441
  Code code = FromCodeT(CodeT::cast(slot->GetHeapObject()));
442
  if (code.marked_for_deoptimization()) {
443
    Deoptimizer::TraceEvictFromOptimizedCodeCache(shared, reason);
444 445
    if (!code.deopt_already_counted()) {
      code.set_deopt_already_counted(true);
446
    }
447
    ClearOptimizedCode();
448 449 450
  }
}

451
bool FeedbackVector::ClearSlots(Isolate* isolate) {
452
  if (!shared_function_info().HasFeedbackMetadata()) return false;
453
  MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
454
      FeedbackVector::RawUninitializedSentinel(isolate));
455

456
  bool feedback_updated = false;
457
  FeedbackMetadataIterator iter(metadata());
458
  while (iter.HasNext()) {
459
    FeedbackSlot slot = iter.Next();
460

461
    MaybeObject obj = Get(slot);
462
    if (obj != uninitialized_sentinel) {
463
      FeedbackNexus nexus(*this, slot);
464
      feedback_updated |= nexus.Clear();
465 466
    }
  }
467
  return feedback_updated;
468
}
469

470 471 472
MaybeObjectHandle NexusConfig::NewHandle(MaybeObject object) const {
  if (mode() == Mode::MainThread) {
    return handle(object, isolate_);
473
  }
474 475
  DCHECK_EQ(mode(), Mode::BackgroundThread);
  return handle(object, local_heap_);
476 477
}

478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501
template <typename T>
Handle<T> NexusConfig::NewHandle(T object) const {
  if (mode() == Mode::MainThread) {
    return handle(object, isolate_);
  }
  DCHECK_EQ(mode(), Mode::BackgroundThread);
  return handle(object, local_heap_);
}

void NexusConfig::SetFeedbackPair(FeedbackVector vector,
                                  FeedbackSlot start_slot, MaybeObject feedback,
                                  WriteBarrierMode mode,
                                  MaybeObject feedback_extra,
                                  WriteBarrierMode mode_extra) const {
  CHECK(can_write());
  CHECK_GT(vector.length(), start_slot.WithOffset(1).ToInt());
  base::SharedMutexGuard<base::kExclusive> shared_mutex_guard(
      isolate()->feedback_vector_access());
  vector.Set(start_slot, feedback, mode);
  vector.Set(start_slot.WithOffset(1), feedback_extra, mode_extra);
}

std::pair<MaybeObject, MaybeObject> NexusConfig::GetFeedbackPair(
    FeedbackVector vector, FeedbackSlot slot) const {
502 503
  base::SharedMutexGuardIf<base::kShared> scope(
      isolate()->feedback_vector_access(), mode() == BackgroundThread);
504 505
  MaybeObject feedback = vector.Get(slot);
  MaybeObject feedback_extra = vector.Get(slot.WithOffset(1));
506
  return std::make_pair(feedback, feedback_extra);
507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528
}

FeedbackNexus::FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot)
    : vector_handle_(vector),
      slot_(slot),
      config_(NexusConfig::FromMainThread(
          vector.is_null() ? nullptr : vector->GetIsolate())) {
  kind_ = vector.is_null() ? FeedbackSlotKind::kInvalid : vector->GetKind(slot);
}

FeedbackNexus::FeedbackNexus(FeedbackVector vector, FeedbackSlot slot)
    : vector_(vector),
      slot_(slot),
      config_(NexusConfig::FromMainThread(
          vector.is_null() ? nullptr : vector.GetIsolate())) {
  kind_ = vector.is_null() ? FeedbackSlotKind::kInvalid : vector.GetKind(slot);
}

FeedbackNexus::FeedbackNexus(Handle<FeedbackVector> vector, FeedbackSlot slot,
                             const NexusConfig& config)
    : vector_handle_(vector),
      slot_(slot),
529
      kind_(vector->GetKind(slot, kAcquireLoad)),
530 531
      config_(config) {}

532
Handle<WeakFixedArray> FeedbackNexus::CreateArrayOfSize(int length) {
533 534 535
  DCHECK(config()->can_write());
  Handle<WeakFixedArray> array =
      GetIsolate()->factory()->NewWeakFixedArray(length);
536
  return array;
537 538
}

539
void FeedbackNexus::ConfigureUninitialized() {
540 541 542 543 544 545
  Isolate* isolate = GetIsolate();
  switch (kind()) {
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
546
      SetFeedback(HeapObjectReference::ClearedValue(isolate),
547
                  SKIP_WRITE_BARRIER, UninitializedSentinel(),
548
                  SKIP_WRITE_BARRIER);
549 550
      break;
    }
551
    case FeedbackSlotKind::kCloneObject:
552
    case FeedbackSlotKind::kCall: {
553
      SetFeedback(UninitializedSentinel(), SKIP_WRITE_BARRIER, Smi::zero(),
554 555 556 557
                  SKIP_WRITE_BARRIER);
      break;
    }
    case FeedbackSlotKind::kInstanceOf: {
558
      SetFeedback(UninitializedSentinel(), SKIP_WRITE_BARRIER);
559 560
      break;
    }
561 562 563 564
    case FeedbackSlotKind::kSetNamedSloppy:
    case FeedbackSlotKind::kSetNamedStrict:
    case FeedbackSlotKind::kSetKeyedSloppy:
    case FeedbackSlotKind::kSetKeyedStrict:
565
    case FeedbackSlotKind::kStoreInArrayLiteral:
566 567
    case FeedbackSlotKind::kDefineNamedOwn:
    case FeedbackSlotKind::kDefineKeyedOwn:
568 569
    case FeedbackSlotKind::kLoadProperty:
    case FeedbackSlotKind::kLoadKeyed:
570
    case FeedbackSlotKind::kHasKeyed:
571
    case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral: {
572 573
      SetFeedback(UninitializedSentinel(), SKIP_WRITE_BARRIER,
                  UninitializedSentinel(), SKIP_WRITE_BARRIER);
574 575
      break;
    }
576
    default:
577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595
      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:
596
      SetFeedback(Smi::zero(), SKIP_WRITE_BARRIER);
597 598 599
      feedback_updated = true;
      break;

600 601 602 603
    case FeedbackSlotKind::kSetNamedSloppy:
    case FeedbackSlotKind::kSetNamedStrict:
    case FeedbackSlotKind::kSetKeyedSloppy:
    case FeedbackSlotKind::kSetKeyedStrict:
604
    case FeedbackSlotKind::kStoreInArrayLiteral:
605 606
    case FeedbackSlotKind::kDefineNamedOwn:
    case FeedbackSlotKind::kDefineKeyedOwn:
607 608
    case FeedbackSlotKind::kLoadProperty:
    case FeedbackSlotKind::kLoadKeyed:
609
    case FeedbackSlotKind::kHasKeyed:
610 611 612 613 614 615
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    case FeedbackSlotKind::kCall:
    case FeedbackSlotKind::kInstanceOf:
616
    case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral:
617
    case FeedbackSlotKind::kCloneObject:
618 619 620 621 622 623 624 625 626 627 628
      if (!IsCleared()) {
        ConfigureUninitialized();
        feedback_updated = true;
      }
      break;

    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
  }
  return feedback_updated;
629 630
}

631
bool FeedbackNexus::ConfigureMegamorphic() {
632
  DisallowGarbageCollection no_gc;
633
  Isolate* isolate = GetIsolate();
634
  MaybeObject sentinel = MegamorphicSentinel();
635
  if (GetFeedback() != sentinel) {
636 637
    SetFeedback(sentinel, SKIP_WRITE_BARRIER,
                HeapObjectReference::ClearedValue(isolate));
638 639 640 641 642 643
    return true;
  }

  return false;
}

644 645 646 647 648 649 650
void FeedbackNexus::ConfigureMegaDOM(const MaybeObjectHandle& handler) {
  DisallowGarbageCollection no_gc;
  MaybeObject sentinel = MegaDOMSentinel();

  SetFeedback(sentinel, SKIP_WRITE_BARRIER, *handler, UPDATE_WRITE_BARRIER);
}

651
bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
652
  DisallowGarbageCollection no_gc;
653 654 655 656 657 658 659 660 661
  MaybeObject sentinel = MegamorphicSentinel();
  MaybeObject maybe_extra =
      MaybeObject::FromSmi(Smi::FromInt(static_cast<int>(property_type)));

  auto feedback = GetFeedbackPair();
  bool update_required =
      feedback.first != sentinel || feedback.second != maybe_extra;
  if (update_required) {
    SetFeedback(sentinel, SKIP_WRITE_BARRIER, maybe_extra, SKIP_WRITE_BARRIER);
662
  }
663
  return update_required;
664
}
665

666
Map FeedbackNexus::GetFirstMap() const {
667 668 669 670 671
  FeedbackIterator it(this);
  if (!it.done()) {
    return it.map();
  }

672 673 674
  return Map();
}

675
InlineCacheState FeedbackNexus::ic_state() const {
676 677
  MaybeObject feedback, extra;
  std::tie(feedback, extra) = GetFeedbackPair();
678

679 680
  switch (kind()) {
    case FeedbackSlotKind::kLiteral:
681 682
      if (feedback->IsSmi()) return InlineCacheState::UNINITIALIZED;
      return InlineCacheState::MONOMORPHIC;
683

684 685 686 687
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
688
      if (feedback->IsSmi()) return InlineCacheState::MONOMORPHIC;
689

690
      DCHECK(feedback->IsWeakOrCleared());
691
      if (!feedback->IsCleared() || extra != UninitializedSentinel()) {
692
        return InlineCacheState::MONOMORPHIC;
693
      }
694
      return InlineCacheState::UNINITIALIZED;
695
    }
696

697 698 699 700
    case FeedbackSlotKind::kSetNamedSloppy:
    case FeedbackSlotKind::kSetNamedStrict:
    case FeedbackSlotKind::kSetKeyedSloppy:
    case FeedbackSlotKind::kSetKeyedStrict:
701
    case FeedbackSlotKind::kStoreInArrayLiteral:
702 703
    case FeedbackSlotKind::kDefineNamedOwn:
    case FeedbackSlotKind::kDefineKeyedOwn:
704
    case FeedbackSlotKind::kLoadProperty:
705 706
    case FeedbackSlotKind::kLoadKeyed:
    case FeedbackSlotKind::kHasKeyed: {
707
      if (feedback == UninitializedSentinel()) {
708
        return InlineCacheState::UNINITIALIZED;
709
      }
710
      if (feedback == MegamorphicSentinel()) {
711
        return InlineCacheState::MEGAMORPHIC;
712
      }
713 714
      if (feedback == MegaDOMSentinel()) {
        DCHECK(IsLoadICKind(kind()));
715
        return InlineCacheState::MEGADOM;
716
      }
717
      if (feedback->IsWeakOrCleared()) {
718
        // Don't check if the map is cleared.
719
        return InlineCacheState::MONOMORPHIC;
720
      }
721
      HeapObject heap_object;
722
      if (feedback->GetHeapObjectIfStrong(&heap_object)) {
723
        if (heap_object.IsWeakFixedArray()) {
724 725
          // Determine state purely by our structure, don't check if the maps
          // are cleared.
726
          return InlineCacheState::POLYMORPHIC;
727
        }
728
        if (heap_object.IsName()) {
729
          DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
730
                 IsKeyedHasICKind(kind()) || IsDefineKeyedOwnICKind(kind()));
731 732
          Object extra_object = extra->GetHeapObjectAssumeStrong();
          WeakFixedArray extra_array = WeakFixedArray::cast(extra_object);
733 734
          return extra_array.length() > 2 ? InlineCacheState::POLYMORPHIC
                                          : InlineCacheState::MONOMORPHIC;
735
        }
736
      }
737
      UNREACHABLE();
738 739
    }
    case FeedbackSlotKind::kCall: {
740
      HeapObject heap_object;
741
      if (feedback == MegamorphicSentinel()) {
742
        return InlineCacheState::GENERIC;
743 744 745
      } else if (feedback->IsWeakOrCleared()) {
        if (feedback->GetHeapObjectIfWeak(&heap_object)) {
          if (heap_object.IsFeedbackCell()) {
746
            return InlineCacheState::POLYMORPHIC;
747 748 749
          }
          CHECK(heap_object.IsJSFunction() || heap_object.IsJSBoundFunction());
        }
750
        return InlineCacheState::MONOMORPHIC;
751 752
      } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
                 heap_object.IsAllocationSite()) {
753
        return InlineCacheState::MONOMORPHIC;
754
      }
755

756
      CHECK_EQ(feedback, UninitializedSentinel());
757
      return InlineCacheState::UNINITIALIZED;
758 759 760 761
    }
    case FeedbackSlotKind::kBinaryOp: {
      BinaryOperationHint hint = GetBinaryOperationFeedback();
      if (hint == BinaryOperationHint::kNone) {
762
        return InlineCacheState::UNINITIALIZED;
763
      } else if (hint == BinaryOperationHint::kAny) {
764
        return InlineCacheState::GENERIC;
765
      }
766

767
      return InlineCacheState::MONOMORPHIC;
768 769 770 771
    }
    case FeedbackSlotKind::kCompareOp: {
      CompareOperationHint hint = GetCompareOperationFeedback();
      if (hint == CompareOperationHint::kNone) {
772
        return InlineCacheState::UNINITIALIZED;
773
      } else if (hint == CompareOperationHint::kAny) {
774
        return InlineCacheState::GENERIC;
775 776
      }

777
      return InlineCacheState::MONOMORPHIC;
778 779 780 781
    }
    case FeedbackSlotKind::kForIn: {
      ForInHint hint = GetForInFeedback();
      if (hint == ForInHint::kNone) {
782
        return InlineCacheState::UNINITIALIZED;
783
      } else if (hint == ForInHint::kAny) {
784
        return InlineCacheState::GENERIC;
785
      }
786
      return InlineCacheState::MONOMORPHIC;
787 788
    }
    case FeedbackSlotKind::kInstanceOf: {
789
      if (feedback == UninitializedSentinel()) {
790
        return InlineCacheState::UNINITIALIZED;
791
      } else if (feedback == MegamorphicSentinel()) {
792
        return InlineCacheState::MEGAMORPHIC;
793
      }
794
      return InlineCacheState::MONOMORPHIC;
795
    }
796
    case FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral: {
797
      if (feedback == UninitializedSentinel()) {
798
        return InlineCacheState::UNINITIALIZED;
799
      } else if (feedback->IsWeakOrCleared()) {
800
        // Don't check if the map is cleared.
801
        return InlineCacheState::MONOMORPHIC;
802 803
      }

804
      return InlineCacheState::MEGAMORPHIC;
805 806
    }
    case FeedbackSlotKind::kTypeProfile: {
807
      if (feedback == UninitializedSentinel()) {
808
        return InlineCacheState::UNINITIALIZED;
809
      }
810
      return InlineCacheState::MONOMORPHIC;
811 812
    }

813
    case FeedbackSlotKind::kCloneObject: {
814
      if (feedback == UninitializedSentinel()) {
815
        return InlineCacheState::UNINITIALIZED;
816
      }
817
      if (feedback == MegamorphicSentinel()) {
818
        return InlineCacheState::MEGAMORPHIC;
819
      }
820
      if (feedback->IsWeakOrCleared()) {
821
        return InlineCacheState::MONOMORPHIC;
822 823
      }

824
      DCHECK(feedback->GetHeapObjectAssumeStrong().IsWeakFixedArray());
825
      return InlineCacheState::POLYMORPHIC;
826 827
    }

828 829 830 831
    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
  }
832
  return InlineCacheState::UNINITIALIZED;
833 834
}

835 836
void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
  DCHECK(IsGlobalICKind(kind()));
837 838
  SetFeedback(HeapObjectReference::Weak(*cell), UPDATE_WRITE_BARRIER,
              UninitializedSentinel(), SKIP_WRITE_BARRIER);
839 840
}

841
bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
842 843
                                            int context_slot_index,
                                            bool immutable) {
844
  DCHECK(IsGlobalICKind(kind()));
845 846 847
  DCHECK_LE(0, script_context_index);
  DCHECK_LE(0, context_slot_index);
  if (!ContextIndexBits::is_valid(script_context_index) ||
848 849
      !SlotIndexBits::is_valid(context_slot_index) ||
      !ImmutabilityBit::is_valid(immutable)) {
850 851 852
    return false;
  }
  int config = ContextIndexBits::encode(script_context_index) |
853 854 855
               SlotIndexBits::encode(context_slot_index) |
               ImmutabilityBit::encode(immutable);

856 857
  SetFeedback(Smi::From31BitPattern(config), SKIP_WRITE_BARRIER,
              UninitializedSentinel(), SKIP_WRITE_BARRIER);
858 859 860
  return true;
}

861
void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
862
  DCHECK(IsGlobalICKind(kind()));
863
  DCHECK(IC::IsHandler(*handler));
864 865
  SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()),
              UPDATE_WRITE_BARRIER, *handler, UPDATE_WRITE_BARRIER);
866 867
}

868 869
void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
                                         Handle<Map> result_map) {
870
  DCHECK(config()->can_write());
871
  Isolate* isolate = GetIsolate();
872 873 874 875 876 877 878 879 880
  Handle<HeapObject> feedback;
  {
    MaybeObject maybe_feedback = GetFeedback();
    if (maybe_feedback->IsStrongOrWeak()) {
      feedback = handle(maybe_feedback->GetHeapObject(), isolate);
    } else {
      DCHECK(maybe_feedback->IsCleared());
    }
  }
881
  switch (ic_state()) {
882
    case InlineCacheState::UNINITIALIZED:
883
      // Cache the first map seen which meets the fast case requirements.
884 885
      SetFeedback(HeapObjectReference::Weak(*source_map), UPDATE_WRITE_BARRIER,
                  *result_map);
886
      break;
887
    case InlineCacheState::MONOMORPHIC:
888
      if (feedback.is_null() || feedback.is_identical_to(source_map) ||
889
          Map::cast(*feedback).is_deprecated()) {
890 891
        SetFeedback(HeapObjectReference::Weak(*source_map),
                    UPDATE_WRITE_BARRIER, *result_map);
892 893 894
      } else {
        // Transition to POLYMORPHIC.
        Handle<WeakFixedArray> array =
895
            CreateArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
896
        array->Set(0, HeapObjectReference::Weak(*feedback));
897 898 899
        array->Set(1, GetFeedbackExtra());
        array->Set(2, HeapObjectReference::Weak(*source_map));
        array->Set(3, MaybeObject::FromObject(*result_map));
900 901
        SetFeedback(*array, UPDATE_WRITE_BARRIER,
                    HeapObjectReference::ClearedValue(isolate));
902 903
      }
      break;
904
    case InlineCacheState::POLYMORPHIC: {
905 906
      const int kMaxElements = FLAG_max_valid_polymorphic_map_count *
                               kCloneObjectPolymorphicEntrySize;
907 908 909
      Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
      int i = 0;
      for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
910 911 912 913
        MaybeObject feedback_map = array->Get(i);
        if (feedback_map->IsCleared()) break;
        Handle<Map> cached_map(Map::cast(feedback_map->GetHeapObject()),
                               isolate);
914 915
        if (cached_map.is_identical_to(source_map) ||
            cached_map->is_deprecated())
916 917 918 919 920 921
          break;
      }

      if (i >= array->length()) {
        if (i == kMaxElements) {
          // Transition to MEGAMORPHIC.
922 923 924
          MaybeObject sentinel = MegamorphicSentinel();
          SetFeedback(sentinel, SKIP_WRITE_BARRIER,
                      HeapObjectReference::ClearedValue(isolate));
925 926 927 928
          break;
        }

        // Grow polymorphic feedback array.
929
        Handle<WeakFixedArray> new_array = CreateArrayOfSize(
930 931 932 933
            array->length() + kCloneObjectPolymorphicEntrySize);
        for (int j = 0; j < array->length(); ++j) {
          new_array->Set(j, array->Get(j));
        }
934
        SetFeedback(*new_array);
935 936 937 938 939 940 941 942 943 944 945 946 947
        array = new_array;
      }

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

    default:
      UNREACHABLE();
  }
}

948 949
int FeedbackNexus::GetCallCount() {
  DCHECK(IsCallICKind(kind()));
950

951
  Object call_count = GetFeedbackExtra()->cast<Object>();
952
  CHECK(call_count.IsSmi());
953 954
  uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
  return CallCountField::decode(value);
955 956
}

957 958 959
void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
  DCHECK(IsCallICKind(kind()));

960
  Object call_count = GetFeedbackExtra()->cast<Object>();
961
  CHECK(call_count.IsSmi());
962
  uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
963
  count = SpeculationModeField::update(count, mode);
964
  MaybeObject feedback = GetFeedback();
965 966 967
  // We could've skipped WB here (since we set the slot to the same value again)
  // but we don't to make WB verification happy.
  SetFeedback(feedback, UPDATE_WRITE_BARRIER, Smi::FromInt(count),
968
              SKIP_WRITE_BARRIER);
969 970
}

971 972 973
SpeculationMode FeedbackNexus::GetSpeculationMode() {
  DCHECK(IsCallICKind(kind()));

974
  Object call_count = GetFeedbackExtra()->cast<Object>();
975
  CHECK(call_count.IsSmi());
976 977 978
  uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
  return SpeculationModeField::decode(value);
}
979

980 981 982 983 984 985 986 987 988
CallFeedbackContent FeedbackNexus::GetCallFeedbackContent() {
  DCHECK(IsCallICKind(kind()));

  Object call_count = GetFeedbackExtra()->cast<Object>();
  CHECK(call_count.IsSmi());
  uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
  return CallFeedbackContentField::decode(value);
}

989 990 991
float FeedbackNexus::ComputeCallFrequency() {
  DCHECK(IsCallICKind(kind()));

992
  double const invocation_count = vector().invocation_count(kRelaxedLoad);
993
  double const call_count = GetCallCount();
994
  if (invocation_count == 0.0) {  // Prevent division by 0.
995 996
    return 0.0f;
  }
997 998 999
  return static_cast<float>(call_count / invocation_count);
}

1000 1001
void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
                                         Handle<Map> receiver_map,
1002
                                         const MaybeObjectHandle& handler) {
1003
  DCHECK(handler.is_null() || IC::IsHandler(*handler));
1004
  if (kind() == FeedbackSlotKind::kDefineKeyedOwnPropertyInLiteral) {
1005 1006
    SetFeedback(HeapObjectReference::Weak(*receiver_map), UPDATE_WRITE_BARRIER,
                *name);
1007
  } else {
1008
    if (name.is_null()) {
1009 1010
      SetFeedback(HeapObjectReference::Weak(*receiver_map),
                  UPDATE_WRITE_BARRIER, *handler);
1011
    } else {
1012
      Handle<WeakFixedArray> array = CreateArrayOfSize(2);
1013
      array->Set(0, HeapObjectReference::Weak(*receiver_map));
1014
      array->Set(1, *handler);
1015
      SetFeedback(*name, UPDATE_WRITE_BARRIER, *array);
1016
    }
1017
  }
1018 1019
}

1020 1021 1022
void FeedbackNexus::ConfigurePolymorphic(
    Handle<Name> name, std::vector<MapAndHandler> const& maps_and_handlers) {
  int receiver_count = static_cast<int>(maps_and_handlers.size());
1023
  DCHECK_GT(receiver_count, 1);
1024
  Handle<WeakFixedArray> array = CreateArrayOfSize(receiver_count * 2);
1025

1026
  for (int current = 0; current < receiver_count; ++current) {
1027
    Handle<Map> map = maps_and_handlers[current].first;
1028
    array->Set(current * 2, HeapObjectReference::Weak(*map));
1029 1030 1031
    MaybeObjectHandle handler = maps_and_handlers[current].second;
    DCHECK(IC::IsHandler(*handler));
    array->Set(current * 2 + 1, *handler);
1032
  }
1033

1034
  if (name.is_null()) {
1035 1036
    SetFeedback(*array, UPDATE_WRITE_BARRIER, UninitializedSentinel(),
                SKIP_WRITE_BARRIER);
1037
  } else {
1038
    SetFeedback(*name, UPDATE_WRITE_BARRIER, *array);
1039
  }
1040 1041
}

1042
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
1043
  DisallowGarbageCollection no_gc;
1044 1045
  int found = 0;
  for (FeedbackIterator it(this); !it.done(); it.Advance()) {
1046
    maps->push_back(config()->NewHandle(it.map()));
1047
    found++;
1048 1049
  }

1050
  return found;
1051 1052
}

1053 1054
int FeedbackNexus::ExtractMapsAndFeedback(
    std::vector<MapAndFeedback>* maps_and_feedback) const {
1055
  DisallowGarbageCollection no_gc;
1056 1057 1058
  int found = 0;

  for (FeedbackIterator it(this); !it.done(); it.Advance()) {
1059
    Handle<Map> map = config()->NewHandle(it.map());
1060 1061 1062
    MaybeObject maybe_handler = it.handler();
    if (!maybe_handler->IsCleared()) {
      DCHECK(IC::IsHandler(maybe_handler) ||
1063
             IsDefineKeyedOwnPropertyInLiteralKind(kind()));
1064
      MaybeObjectHandle handler = config()->NewHandle(maybe_handler);
1065 1066
      maps_and_feedback->push_back(MapAndHandler(map, handler));
      found++;
1067
    }
1068 1069
  }

1070
  return found;
1071 1072 1073 1074
}

int FeedbackNexus::ExtractMapsAndHandlers(
    std::vector<MapAndHandler>* maps_and_handlers,
1075
    TryUpdateHandler map_handler) const {
1076
  DCHECK(!IsDefineKeyedOwnPropertyInLiteralKind(kind()));
1077
  DisallowGarbageCollection no_gc;
1078 1079 1080
  int found = 0;

  for (FeedbackIterator it(this); !it.done(); it.Advance()) {
1081
    Handle<Map> map = config()->NewHandle(it.map());
1082 1083 1084
    MaybeObject maybe_handler = it.handler();
    if (!maybe_handler->IsCleared()) {
      DCHECK(IC::IsHandler(maybe_handler));
1085 1086
      MaybeObjectHandle handler = config()->NewHandle(maybe_handler);
      if (map_handler && !(map_handler(map).ToHandle(&map))) {
1087 1088 1089 1090 1091
        continue;
      }
      maps_and_handlers->push_back(MapAndHandler(map, handler));
      found++;
    }
1092
  }
1093 1094

  return found;
1095 1096
}

1097
MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
1098
  DCHECK(!IsStoreInArrayLiteralICKind(kind()));
1099

1100 1101
  for (FeedbackIterator it(this); !it.done(); it.Advance()) {
    if (it.map() == *map && !it.handler()->IsCleared()) {
1102
      return config()->NewHandle(it.handler());
1103
    }
1104
  }
1105
  return MaybeObjectHandle();
1106
}
1107

1108
Name FeedbackNexus::GetName() const {
1109
  if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1110
      IsKeyedHasICKind(kind()) || IsDefineKeyedOwnICKind(kind())) {
1111
    MaybeObject feedback = GetFeedback();
1112
    if (IsPropertyNameFeedback(feedback)) {
1113
      return Name::cast(feedback->GetHeapObjectAssumeStrong());
1114
    }
1115
  }
1116
  if (IsDefineKeyedOwnPropertyInLiteralKind(kind())) {
1117 1118 1119 1120 1121
    MaybeObject extra = GetFeedbackExtra();
    if (IsPropertyNameFeedback(extra)) {
      return Name::cast(extra->GetHeapObjectAssumeStrong());
    }
  }
1122
  return Name();
1123 1124
}

1125
KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1126
  DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedHasICKind(kind()));
1127

1128
  if (GetKeyType() == IcCheckType::kProperty) return STANDARD_LOAD;
1129

1130 1131 1132 1133 1134
  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);
1135
    if (mode != STANDARD_LOAD) return mode;
1136 1137
  }

1138
  return STANDARD_LOAD;
1139 1140
}

1141 1142
namespace {

1143 1144 1145
bool BuiltinHasKeyedAccessStoreMode(Builtin builtin) {
  DCHECK(Builtins::IsBuiltinId(builtin));
  switch (builtin) {
1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157
    case Builtin::kKeyedStoreIC_SloppyArguments_Standard:
    case Builtin::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
    case Builtin::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
    case Builtin::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
    case Builtin::kStoreFastElementIC_Standard:
    case Builtin::kStoreFastElementIC_GrowNoTransitionHandleCOW:
    case Builtin::kStoreFastElementIC_NoTransitionIgnoreOOB:
    case Builtin::kStoreFastElementIC_NoTransitionHandleCOW:
    case Builtin::kElementsTransitionAndStore_Standard:
    case Builtin::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
    case Builtin::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
    case Builtin::kElementsTransitionAndStore_NoTransitionHandleCOW:
1158 1159 1160 1161 1162 1163 1164
      return true;
    default:
      return false;
  }
  UNREACHABLE();
}

1165 1166 1167
KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(Builtin builtin) {
  DCHECK(BuiltinHasKeyedAccessStoreMode(builtin));
  switch (builtin) {
1168 1169 1170
    case Builtin::kKeyedStoreIC_SloppyArguments_Standard:
    case Builtin::kStoreFastElementIC_Standard:
    case Builtin::kElementsTransitionAndStore_Standard:
1171
      return STANDARD_STORE;
1172 1173 1174
    case Builtin::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
    case Builtin::kStoreFastElementIC_GrowNoTransitionHandleCOW:
    case Builtin::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1175
      return STORE_AND_GROW_HANDLE_COW;
1176 1177 1178
    case Builtin::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
    case Builtin::kStoreFastElementIC_NoTransitionIgnoreOOB:
    case Builtin::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1179
      return STORE_IGNORE_OUT_OF_BOUNDS;
1180 1181 1182
    case Builtin::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
    case Builtin::kStoreFastElementIC_NoTransitionHandleCOW:
    case Builtin::kElementsTransitionAndStore_NoTransitionHandleCOW:
1183
      return STORE_HANDLE_COW;
1184 1185 1186 1187 1188 1189 1190
    default:
      UNREACHABLE();
  }
}

}  // namespace

1191
KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1192
  DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()) ||
1193 1194
         IsDefineKeyedOwnPropertyInLiteralKind(kind()) ||
         IsDefineKeyedOwnICKind(kind()));
1195 1196
  KeyedAccessStoreMode mode = STANDARD_STORE;

1197
  if (GetKeyType() == IcCheckType::kProperty) return mode;
1198

1199 1200 1201 1202
  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;
1203
    // The first handler that isn't the slow handler will have the bits we need.
1204
    Handle<Code> handler;
1205
    if (maybe_code_handler.object()->IsStoreHandler()) {
1206
      Handle<StoreHandler> data_handler =
1207
          Handle<StoreHandler>::cast(maybe_code_handler.object());
1208 1209 1210 1211 1212 1213 1214 1215

      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 {
1216
        Code code = FromCodeT(CodeT::cast(data_handler->smi_handler()));
1217
        handler = config()->NewHandle(code);
1218 1219
      }

1220
    } else if (maybe_code_handler.object()->IsSmi()) {
1221
      // Skip for Proxy Handlers.
1222
      if (*maybe_code_handler.object() == StoreHandler::StoreProxy()) {
1223
        continue;
1224
      }
1225 1226 1227
      // Decode the KeyedAccessStoreMode information from the Handler.
      mode = StoreHandler::GetKeyedAccessStoreMode(*maybe_code_handler);
      if (mode != STANDARD_STORE) return mode;
1228
      continue;
1229
    } else if (IsDefineKeyedOwnICKind(kind())) {
1230 1231 1232
      mode = StoreHandler::GetKeyedAccessStoreMode(*maybe_code_handler);
      if (mode != STANDARD_STORE) return mode;
      continue;
1233
    } else {
1234
      // Element store without prototype chain check.
1235 1236
      if (V8_EXTERNAL_CODE_SPACE_BOOL) {
        Code code = FromCodeT(CodeT::cast(*maybe_code_handler.object()));
1237
        handler = config()->NewHandle(code);
1238 1239 1240
      } else {
        handler = Handle<Code>::cast(maybe_code_handler.object());
      }
1241
    }
1242 1243

    if (handler->is_builtin()) {
1244 1245
      Builtin builtin = handler->builtin_id();
      if (!BuiltinHasKeyedAccessStoreMode(builtin)) continue;
1246

1247
      mode = KeyedAccessStoreModeForBuiltin(builtin);
1248 1249 1250 1251 1252 1253 1254
      break;
    }
  }

  return mode;
}

1255
IcCheckType FeedbackNexus::GetKeyType() const {
1256
  DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1257
         IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()) ||
1258 1259
         IsDefineKeyedOwnPropertyInLiteralKind(kind()) ||
         IsDefineKeyedOwnICKind(kind()));
1260 1261 1262
  auto pair = GetFeedbackPair();
  MaybeObject feedback = pair.first;
  if (feedback == MegamorphicSentinel()) {
1263
    return static_cast<IcCheckType>(
1264
        Smi::ToInt(pair.second->template cast<Object>()));
1265
  }
1266 1267 1268 1269
  MaybeObject maybe_name = IsDefineKeyedOwnPropertyInLiteralKind(kind()) ||
                                   IsDefineKeyedOwnICKind(kind())
                               ? pair.second
                               : feedback;
1270 1271
  return IsPropertyNameFeedback(maybe_name) ? IcCheckType::kProperty
                                            : IcCheckType::kElement;
1272
}
1273

1274 1275
BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1276
  int feedback = GetFeedback().ToSmi().value();
1277 1278 1279
  return BinaryOperationHintFromFeedback(feedback);
}

1280 1281
CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1282
  int feedback = GetFeedback().ToSmi().value();
1283 1284 1285
  return CompareOperationHintFromFeedback(feedback);
}

1286 1287
ForInHint FeedbackNexus::GetForInFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1288
  int feedback = GetFeedback().ToSmi().value();
1289
  return ForInHintFromFeedback(static_cast<ForInFeedback>(feedback));
1290 1291
}

1292 1293
MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1294
  MaybeObject feedback = GetFeedback();
1295
  HeapObject heap_object;
1296
  if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1297
    return config()->NewHandle(JSObject::cast(heap_object));
1298 1299 1300 1301
  }
  return MaybeHandle<JSObject>();
}

1302 1303 1304 1305
namespace {

bool InList(Handle<ArrayList> types, Handle<String> type) {
  for (int i = 0; i < types->Length(); i++) {
1306
    Object obj = types->Get(i);
1307
    if (String::cast(obj).Equals(*type)) {
1308 1309 1310 1311 1312 1313 1314
      return true;
    }
  }
  return false;
}
}  // anonymous namespace

1315 1316
void FeedbackNexus::Collect(Handle<String> type, int position) {
  DCHECK(IsTypeProfileKind(kind()));
1317
  DCHECK_GE(position, 0);
1318
  DCHECK(config()->can_write());
1319 1320
  Isolate* isolate = GetIsolate();

1321
  MaybeObject const feedback = GetFeedback();
1322 1323

  // Map source position to collection of types
1324
  Handle<SimpleNumberDictionary> types;
1325

1326
  if (feedback == UninitializedSentinel()) {
1327
    types = SimpleNumberDictionary::New(isolate, 1);
1328
  } else {
1329 1330 1331
    types = handle(
        SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
        isolate);
1332
  }
1333

1334
  Handle<ArrayList> position_specific_types;
1335

1336 1337
  InternalIndex entry = types->FindEntry(isolate, position);
  if (entry.is_not_found()) {
1338
    position_specific_types = ArrayList::New(isolate, 1);
1339
    types = SimpleNumberDictionary::Set(
1340 1341
        isolate, types, position,
        ArrayList::Add(isolate, position_specific_types, type));
1342
  } else {
1343
    DCHECK(types->ValueAt(entry).IsArrayList());
1344 1345
    position_specific_types =
        handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1346
    if (!InList(position_specific_types, type)) {  // Add type
1347
      types = SimpleNumberDictionary::Set(
1348 1349
          isolate, types, position,
          ArrayList::Add(isolate, position_specific_types, type));
1350
    }
1351 1352
  }
  SetFeedback(*types);
1353 1354
}

1355 1356
std::vector<int> FeedbackNexus::GetSourcePositions() const {
  DCHECK(IsTypeProfileKind(kind()));
1357 1358 1359
  std::vector<int> source_positions;
  Isolate* isolate = GetIsolate();

1360
  MaybeObject const feedback = GetFeedback();
1361

1362
  if (feedback == UninitializedSentinel()) {
1363 1364 1365
    return source_positions;
  }

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

1370 1371 1372
  for (int index = SimpleNumberDictionary::kElementsStartIndex;
       index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
    int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1373
    Object key = types->get(key_index);
1374 1375
    if (key.IsSmi()) {
      int position = Smi::cast(key).value();
1376 1377 1378 1379 1380 1381
      source_positions.push_back(position);
    }
  }
  return source_positions;
}

1382
std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1383
    uint32_t position) const {
1384
  DCHECK(IsTypeProfileKind(kind()));
1385 1386
  Isolate* isolate = GetIsolate();

1387
  MaybeObject const feedback = GetFeedback();
1388
  std::vector<Handle<String>> types_for_position;
1389
  if (feedback == UninitializedSentinel()) {
1390 1391 1392
    return types_for_position;
  }

1393
  Handle<SimpleNumberDictionary> types(
1394 1395
      SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
      isolate);
1396

1397 1398 1399
  InternalIndex entry = types->FindEntry(isolate, position);
  if (entry.is_not_found()) return types_for_position;

1400
  DCHECK(types->ValueAt(entry).IsArrayList());
1401
  Handle<ArrayList> position_specific_types =
1402
      Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1403
  for (int i = 0; i < position_specific_types->Length(); i++) {
1404
    Object t = position_specific_types->Get(i);
1405 1406 1407 1408 1409 1410
    types_for_position.push_back(Handle<String>(String::cast(t), isolate));
  }

  return types_for_position;
}

1411 1412
void FeedbackNexus::ResetTypeProfile() {
  DCHECK(IsTypeProfileKind(kind()));
1413
  SetFeedback(UninitializedSentinel());
1414 1415
}

1416 1417
FeedbackIterator::FeedbackIterator(const FeedbackNexus* nexus)
    : done_(false), index_(-1), state_(kOther) {
1418 1419 1420 1421 1422 1423 1424
  DCHECK(
      IsLoadICKind(nexus->kind()) || IsStoreICKind(nexus->kind()) ||
      IsKeyedLoadICKind(nexus->kind()) || IsKeyedStoreICKind(nexus->kind()) ||
      IsDefineNamedOwnICKind(nexus->kind()) ||
      IsDefineKeyedOwnPropertyInLiteralKind(nexus->kind()) ||
      IsStoreInArrayLiteralICKind(nexus->kind()) ||
      IsKeyedHasICKind(nexus->kind()) || IsDefineKeyedOwnICKind(nexus->kind()));
1425

1426
  DisallowGarbageCollection no_gc;
1427 1428
  auto pair = nexus->GetFeedbackPair();
  MaybeObject feedback = pair.first;
1429 1430 1431 1432 1433 1434 1435 1436 1437 1438
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
  HeapObject heap_object;

  if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
       heap_object.IsWeakFixedArray()) ||
      is_named_feedback) {
    index_ = 0;
    state_ = kPolymorphic;
    heap_object = feedback->GetHeapObjectAssumeStrong();
    if (is_named_feedback) {
1439 1440
      polymorphic_feedback_ = nexus->config()->NewHandle(
          WeakFixedArray::cast(pair.second->GetHeapObjectAssumeStrong()));
1441 1442
    } else {
      polymorphic_feedback_ =
1443
          nexus->config()->NewHandle(WeakFixedArray::cast(heap_object));
1444 1445 1446 1447
    }
    AdvancePolymorphic();
  } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
    state_ = kMonomorphic;
1448
    MaybeObject handler = pair.second;
1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
    map_ = Map::cast(heap_object);
    handler_ = handler;
  } else {
    done_ = true;
  }
}

void FeedbackIterator::Advance() {
  CHECK(!done_);

  if (state_ == kMonomorphic) {
    done_ = true;
    return;
  }

  CHECK_EQ(state_, kPolymorphic);
  AdvancePolymorphic();
}

void FeedbackIterator::AdvancePolymorphic() {
  CHECK(!done_);
  CHECK_EQ(state_, kPolymorphic);
  int length = polymorphic_feedback_->length();
  HeapObject heap_object;

  while (index_ < length) {
    if (polymorphic_feedback_->Get(index_)->GetHeapObjectIfWeak(&heap_object)) {
      MaybeObject handler = polymorphic_feedback_->Get(index_ + kHandlerOffset);
      map_ = Map::cast(heap_object);
      handler_ = handler;
      index_ += kEntrySize;
      return;
    }
    index_ += kEntrySize;
  }

  CHECK_EQ(index_, length);
  done_ = true;
}
1488 1489
}  // namespace internal
}  // namespace v8