feedback-vector.cc 44.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/feedback-vector.h"
6
#include "src/code-stubs.h"
7
#include "src/feedback-vector-inl.h"
8
#include "src/ic/ic-inl.h"
9
#include "src/objects.h"
10
#include "src/objects/data-handler-inl.h"
11
#include "src/objects/hash-table-inl.h"
12
#include "src/objects/object-macros.h"
13 14 15 16

namespace v8 {
namespace internal {

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

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

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

43 44 45 46 47 48
static bool IsPropertyNameFeedback(MaybeObject* feedback) {
  HeapObject* heap_object;
  if (!feedback->ToStrongHeapObject(&heap_object)) return false;
  if (heap_object->IsString()) return true;
  if (!heap_object->IsSymbol()) return false;
  Symbol* symbol = Symbol::cast(heap_object);
49 50 51 52
  ReadOnlyRoots roots = symbol->GetReadOnlyRoots();
  return symbol != roots.uninitialized_symbol() &&
         symbol != roots.premonomorphic_symbol() &&
         symbol != roots.megamorphic_symbol();
53 54
}

55
std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
56
  return os << FeedbackMetadata::Kind2String(kind);
57 58
}

59
FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
60 61
  int index = VectorICComputer::index(0, slot.ToInt());
  int data = get(index);
62
  return VectorICComputer::decode(data, slot.ToInt());
63 64
}

65
void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
66 67
  int index = VectorICComputer::index(0, slot.ToInt());
  int data = get(index);
68
  int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
69
  set(index, new_data);
70 71
}

72
// static
73
Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
74
                                               const FeedbackVectorSpec* spec) {
75 76
  Factory* factory = isolate->factory();

77
  const int slot_count = spec == nullptr ? 0 : spec->slots();
78 79
  if (slot_count == 0) {
    return factory->empty_feedback_metadata();
80
  }
81 82
#ifdef DEBUG
  for (int i = 0; i < slot_count;) {
83
    DCHECK(spec);
84
    FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
85
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
86
    for (int j = 1; j < entry_size; j++) {
87
      FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
88
      DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
89 90 91 92
    }
    i += entry_size;
  }
#endif
93

94
  Handle<FeedbackMetadata> metadata = factory->NewFeedbackMetadata(slot_count);
95

96 97
  // Initialize the slots. The raw data section has already been pre-zeroed in
  // NewFeedbackMetadata.
98
  for (int i = 0; i < slot_count; i++) {
99
    DCHECK(spec);
100 101
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = spec->GetKind(slot);
102
    metadata->SetKind(slot, kind);
103
  }
104

105 106 107
  return metadata;
}

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

  int slots = slot_count();
115
  for (int i = 0; i < slots;) {
116 117
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = GetKind(slot);
118
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
119

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

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

182 183 184
bool FeedbackMetadata::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
185
  return slot.ToInt() < slot_count() &&
186
         GetKind(slot) == FeedbackSlotKind::kTypeProfile;
187 188
}

189
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
190 191 192
  DCHECK(!is_empty());
  return metadata()->GetKind(slot);
}
193

194
FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
195 196 197 198 199
  DCHECK(metadata()->HasTypeProfileSlot());
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
  return slot;
200 201
}

202
// static
203
Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
204
                                           Handle<SharedFunctionInfo> shared) {
205 206
  Factory* factory = isolate->factory();

207
  const int slot_count = shared->feedback_metadata()->slot_count();
208

209 210 211 212 213
  Handle<FeedbackVector> vector = factory->NewFeedbackVector(shared, TENURED);

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

  DCHECK_EQ(vector->shared_function_info(), *shared);
214 215 216 217 218
  DCHECK_EQ(
      vector->optimized_code_weak_or_smi(),
      MaybeObject::FromSmi(Smi::FromEnum(
          FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
                                   : OptimizationMarker::kNone)));
219 220
  DCHECK_EQ(vector->invocation_count(), 0);
  DCHECK_EQ(vector->profiler_ticks(), 0);
221
  DCHECK_EQ(vector->deopt_count(), 0);
222

223 224
  // Ensure we can skip the write barrier
  Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
225 226
  DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
            *uninitialized_sentinel);
227
  Handle<Oddball> undefined_value = factory->undefined_value();
228
  for (int i = 0; i < slot_count;) {
229
    FeedbackSlot slot(i);
230
    FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
231 232
    int index = FeedbackVector::GetIndex(slot);
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
233

234 235
    Object* extra_value = *uninitialized_sentinel;
    switch (kind) {
236 237
      case FeedbackSlotKind::kLoadGlobalInsideTypeof:
      case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
238 239
      case FeedbackSlotKind::kStoreGlobalSloppy:
      case FeedbackSlotKind::kStoreGlobalStrict:
240
        vector->set(index, HeapObjectReference::ClearedValue(),
241
                    SKIP_WRITE_BARRIER);
242
        break;
243
      case FeedbackSlotKind::kForIn:
244 245
      case FeedbackSlotKind::kCompareOp:
      case FeedbackSlotKind::kBinaryOp:
246
        vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
247
        break;
248
      case FeedbackSlotKind::kCreateClosure: {
249
        Handle<FeedbackCell> cell = factory->NewNoClosuresCell(undefined_value);
250
        vector->set(index, *cell);
251
        break;
252
      }
253
      case FeedbackSlotKind::kLiteral:
254
        vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
255
        break;
256
      case FeedbackSlotKind::kCall:
257
        vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
258 259
        extra_value = Smi::kZero;
        break;
260
      case FeedbackSlotKind::kCloneObject:
261 262
      case FeedbackSlotKind::kLoadProperty:
      case FeedbackSlotKind::kLoadKeyed:
263 264 265
      case FeedbackSlotKind::kStoreNamedSloppy:
      case FeedbackSlotKind::kStoreNamedStrict:
      case FeedbackSlotKind::kStoreOwnNamed:
266 267
      case FeedbackSlotKind::kStoreKeyedSloppy:
      case FeedbackSlotKind::kStoreKeyedStrict:
268
      case FeedbackSlotKind::kStoreInArrayLiteral:
269
      case FeedbackSlotKind::kStoreDataPropertyInLiteral:
270
      case FeedbackSlotKind::kTypeProfile:
271
      case FeedbackSlotKind::kInstanceOf:
272
        vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
273 274
        break;

275 276
      case FeedbackSlotKind::kInvalid:
      case FeedbackSlotKind::kKindsNumber:
277 278
        UNREACHABLE();
        break;
279
    }
280
    for (int j = 1; j < entry_size; j++) {
281
      vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
282 283 284
    }
    i += entry_size;
  }
285

286
  Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
287 288 289
  if (!isolate->is_best_effort_code_coverage() ||
      isolate->is_collecting_type_profile()) {
    AddToVectorsForProfilingTools(isolate, result);
290
  }
291 292
  return result;
}
293

294
// static
295 296 297 298
void FeedbackVector::AddToVectorsForProfilingTools(
    Isolate* isolate, Handle<FeedbackVector> vector) {
  DCHECK(!isolate->is_best_effort_code_coverage() ||
         isolate->is_collecting_type_profile());
299
  if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
300 301
  Handle<ArrayList> list = Handle<ArrayList>::cast(
      isolate->factory()->feedback_vectors_for_profiling_tools());
302
  list = ArrayList::Add(isolate, list, vector);
303
  isolate->SetFeedbackVectorsForProfilingTools(*list);
304 305
}

306 307 308 309
// static
void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
                                      Handle<Code> code) {
  DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
310
  vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
311 312
}

313 314 315
void FeedbackVector::ClearOptimizedCode() {
  DCHECK(has_optimized_code());
  SetOptimizationMarker(OptimizationMarker::kNone);
316 317
}

318 319 320 321 322 323
void FeedbackVector::ClearOptimizationMarker() {
  DCHECK(!has_optimized_code());
  SetOptimizationMarker(OptimizationMarker::kNone);
}

void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
324
  set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
325 326 327 328
}

void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
    SharedFunctionInfo* shared, const char* reason) {
329 330 331 332
  MaybeObject* slot = optimized_code_weak_or_smi();
  if (slot->IsSmi()) {
    return;
  }
333

334
  if (slot->IsClearedWeakHeapObject()) {
335
    ClearOptimizationMarker();
336 337 338
    return;
  }

339
  Code* code = Code::cast(slot->GetHeapObject());
340 341 342 343 344 345 346 347
  if (code->marked_for_deoptimization()) {
    if (FLAG_trace_deopt) {
      PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
             reason);
      shared->ShortPrint();
      PrintF("]\n");
    }
    if (!code->deopt_already_counted()) {
348
      increment_deopt_count();
349
      code->set_deopt_already_counted(true);
350
    }
351
    ClearOptimizedCode();
352 353 354
  }
}

355
bool FeedbackVector::ClearSlots(Isolate* isolate) {
356 357
  MaybeObject* uninitialized_sentinel = MaybeObject::FromObject(
      FeedbackVector::RawUninitializedSentinel(isolate));
358

359
  bool feedback_updated = false;
360
  FeedbackMetadataIterator iter(metadata());
361
  while (iter.HasNext()) {
362
    FeedbackSlot slot = iter.Next();
363

364
    MaybeObject* obj = Get(slot);
365
    if (obj != uninitialized_sentinel) {
366 367
      FeedbackNexus nexus(this, slot);
      feedback_updated |= nexus.Clear();
368 369
    }
  }
370
  return feedback_updated;
371
}
372

373 374 375 376 377 378 379 380 381
void FeedbackVector::AssertNoLegacyTypes(MaybeObject* object) {
#ifdef DEBUG
  HeapObject* heap_object;
  if (object->ToStrongOrWeakHeapObject(&heap_object)) {
    // Instead of FixedArray, the Feedback and the Extra should contain
    // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
    DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable());
  }
#endif
382 383 384
}

Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
385
  Isolate* isolate = GetIsolate();
386 387 388 389
  HeapObject* heap_object;
  if (GetFeedback()->ToStrongHeapObject(&heap_object) &&
      heap_object->IsWeakFixedArray() &&
      WeakFixedArray::cast(heap_object)->length() == length) {
390
    return handle(WeakFixedArray::cast(heap_object), isolate);
391
  }
392 393 394
  Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
  SetFeedback(*array);
  return array;
395 396
}

397
Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
398
  Isolate* isolate = GetIsolate();
399 400 401 402
  HeapObject* heap_object;
  if (GetFeedbackExtra()->ToStrongHeapObject(&heap_object) &&
      heap_object->IsWeakFixedArray() &&
      WeakFixedArray::cast(heap_object)->length() == length) {
403
    return handle(WeakFixedArray::cast(heap_object), isolate);
404
  }
405 406 407
  Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
  SetFeedbackExtra(*array);
  return array;
408 409
}

410
void FeedbackNexus::ConfigureUninitialized() {
411 412 413 414 415 416
  Isolate* isolate = GetIsolate();
  switch (kind()) {
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
417
      SetFeedback(HeapObjectReference::ClearedValue(), SKIP_WRITE_BARRIER);
418 419 420 421
      SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                       SKIP_WRITE_BARRIER);
      break;
    }
422
    case FeedbackSlotKind::kCloneObject:
423 424 425 426 427 428 429 430 431 432 433
    case FeedbackSlotKind::kCall: {
      SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
                  SKIP_WRITE_BARRIER);
      SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
      break;
    }
    case FeedbackSlotKind::kInstanceOf: {
      SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
                  SKIP_WRITE_BARRIER);
      break;
    }
434 435 436 437 438 439 440 441
    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict:
    case FeedbackSlotKind::kStoreInArrayLiteral:
    case FeedbackSlotKind::kStoreOwnNamed:
    case FeedbackSlotKind::kLoadProperty:
    case FeedbackSlotKind::kLoadKeyed:
442 443 444 445 446 447 448
    case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
      SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
                  SKIP_WRITE_BARRIER);
      SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                       SKIP_WRITE_BARRIER);
      break;
    }
449
    default:
450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477
      UNREACHABLE();
  }
}

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

  switch (kind()) {
    case FeedbackSlotKind::kCreateClosure:
    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:
      SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER);
      feedback_updated = true;
      break;

    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict:
478
    case FeedbackSlotKind::kStoreInArrayLiteral:
479 480 481 482 483 484 485 486 487 488
    case FeedbackSlotKind::kStoreOwnNamed:
    case FeedbackSlotKind::kLoadProperty:
    case FeedbackSlotKind::kLoadKeyed:
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
    case FeedbackSlotKind::kCall:
    case FeedbackSlotKind::kInstanceOf:
    case FeedbackSlotKind::kStoreDataPropertyInLiteral:
489
    case FeedbackSlotKind::kCloneObject:
490 491 492 493 494 495 496 497 498 499 500 501
      if (!IsCleared()) {
        ConfigureUninitialized();
        feedback_updated = true;
      }
      break;

    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
      break;
  }
  return feedback_updated;
502 503
}

504
void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) {
505
  SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
506
              SKIP_WRITE_BARRIER);
507
  SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map));
508 509
}

510 511 512 513 514 515 516 517 518 519 520 521 522 523
bool FeedbackNexus::ConfigureMegamorphic() {
  DisallowHeapAllocation no_gc;
  Isolate* isolate = GetIsolate();
  MaybeObject* sentinel =
      MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
  if (GetFeedback() != sentinel) {
    SetFeedback(sentinel, SKIP_WRITE_BARRIER);
    SetFeedbackExtra(HeapObjectReference::ClearedValue());
    return true;
  }

  return false;
}

524 525
bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
  DisallowHeapAllocation no_gc;
526
  Isolate* isolate = GetIsolate();
527
  bool changed = false;
528 529
  MaybeObject* sentinel =
      MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
530 531 532 533 534 535
  if (GetFeedback() != sentinel) {
    SetFeedback(sentinel, SKIP_WRITE_BARRIER);
    changed = true;
  }

  Smi* extra = Smi::FromInt(static_cast<int>(property_type));
536
  if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
537 538 539 540
    SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
    changed = true;
  }
  return changed;
541
}
542

543
InlineCacheState FeedbackNexus::StateFromFeedback() const {
544
  Isolate* isolate = GetIsolate();
545
  MaybeObject* feedback = GetFeedback();
546

547 548 549 550 551 552
  switch (kind()) {
    case FeedbackSlotKind::kCreateClosure:
    case FeedbackSlotKind::kLiteral:
      // CreateClosure and literal slots don't have a notion of state.
      UNREACHABLE();
      break;
553

554 555 556 557 558
    case FeedbackSlotKind::kStoreGlobalSloppy:
    case FeedbackSlotKind::kStoreGlobalStrict:
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
    case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
      if (feedback->IsSmi()) return MONOMORPHIC;
559

560
      DCHECK(feedback->IsWeakOrClearedHeapObject());
561
      MaybeObject* extra = GetFeedbackExtra();
562
      if (!feedback->IsClearedWeakHeapObject() ||
563 564
          extra != MaybeObject::FromObject(
                       *FeedbackVector::UninitializedSentinel(isolate))) {
565 566 567 568
        return MONOMORPHIC;
      }
      return UNINITIALIZED;
    }
569

570 571 572 573
    case FeedbackSlotKind::kStoreNamedSloppy:
    case FeedbackSlotKind::kStoreNamedStrict:
    case FeedbackSlotKind::kStoreKeyedSloppy:
    case FeedbackSlotKind::kStoreKeyedStrict:
574
    case FeedbackSlotKind::kStoreInArrayLiteral:
575 576 577
    case FeedbackSlotKind::kStoreOwnNamed:
    case FeedbackSlotKind::kLoadProperty:
    case FeedbackSlotKind::kLoadKeyed: {
578 579
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
580
        return UNINITIALIZED;
581
      }
582 583
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::MegamorphicSentinel(isolate))) {
584
        return MEGAMORPHIC;
585
      }
586 587
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::PremonomorphicSentinel(isolate))) {
588
        return PREMONOMORPHIC;
589
      }
590
      if (feedback->IsWeakOrClearedHeapObject()) {
591 592
        // Don't check if the map is cleared.
        return MONOMORPHIC;
593
      }
594 595 596 597 598 599 600 601 602 603 604 605 606
      HeapObject* heap_object;
      if (feedback->ToStrongHeapObject(&heap_object)) {
        if (heap_object->IsWeakFixedArray()) {
          // Determine state purely by our structure, don't check if the maps
          // are cleared.
          return POLYMORPHIC;
        }
        if (heap_object->IsName()) {
          DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()));
          Object* extra = GetFeedbackExtra()->ToStrongHeapObject();
          WeakFixedArray* extra_array = WeakFixedArray::cast(extra);
          return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
        }
607
      }
608
      UNREACHABLE();
609 610
    }
    case FeedbackSlotKind::kCall: {
611 612 613
      HeapObject* heap_object;
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::MegamorphicSentinel(isolate))) {
614
        return GENERIC;
615 616 617
      } else if (feedback->IsWeakOrClearedHeapObject() ||
                 (feedback->ToStrongHeapObject(&heap_object) &&
                  heap_object->IsAllocationSite())) {
618 619
        return MONOMORPHIC;
      }
620

621 622
      CHECK_EQ(feedback, MaybeObject::FromObject(
                             *FeedbackVector::UninitializedSentinel(isolate)));
623 624 625 626 627 628 629 630 631
      return UNINITIALIZED;
    }
    case FeedbackSlotKind::kBinaryOp: {
      BinaryOperationHint hint = GetBinaryOperationFeedback();
      if (hint == BinaryOperationHint::kNone) {
        return UNINITIALIZED;
      } else if (hint == BinaryOperationHint::kAny) {
        return GENERIC;
      }
632

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
      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: {
655 656
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
657
        return UNINITIALIZED;
658 659 660
      } else if (feedback ==
                 MaybeObject::FromObject(
                     *FeedbackVector::MegamorphicSentinel(isolate))) {
661 662 663 664 665
        return MEGAMORPHIC;
      }
      return MONOMORPHIC;
    }
    case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
666 667
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
668
        return UNINITIALIZED;
669
      } else if (feedback->IsWeakOrClearedHeapObject()) {
670 671 672 673 674 675 676
        // Don't check if the map is cleared.
        return MONOMORPHIC;
      }

      return MEGAMORPHIC;
    }
    case FeedbackSlotKind::kTypeProfile: {
677 678
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
679 680 681 682 683
        return UNINITIALIZED;
      }
      return MONOMORPHIC;
    }

684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700
    case FeedbackSlotKind::kCloneObject: {
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::UninitializedSentinel(isolate))) {
        return UNINITIALIZED;
      }
      if (feedback == MaybeObject::FromObject(
                          *FeedbackVector::MegamorphicSentinel(isolate))) {
        return MEGAMORPHIC;
      }
      if (feedback->IsWeakOrClearedHeapObject()) {
        return MONOMORPHIC;
      }

      DCHECK(feedback->ToStrongHeapObject()->IsWeakFixedArray());
      return POLYMORPHIC;
    }

701 702 703 704 705 706
    case FeedbackSlotKind::kInvalid:
    case FeedbackSlotKind::kKindsNumber:
      UNREACHABLE();
      break;
  }
  return UNINITIALIZED;
707 708
}

709 710
void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
  DCHECK(IsGlobalICKind(kind()));
711
  Isolate* isolate = GetIsolate();
712
  SetFeedback(HeapObjectReference::Weak(*cell));
713 714 715 716
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                   SKIP_WRITE_BARRIER);
}

717
bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
718
                                            int context_slot_index) {
719
  DCHECK(IsGlobalICKind(kind()));
720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
  DCHECK_LE(0, script_context_index);
  DCHECK_LE(0, context_slot_index);
  if (!ContextIndexBits::is_valid(script_context_index) ||
      !SlotIndexBits::is_valid(context_slot_index)) {
    return false;
  }
  int config = ContextIndexBits::encode(script_context_index) |
               SlotIndexBits::encode(context_slot_index);

  SetFeedback(Smi::FromInt(config));
  Isolate* isolate = GetIsolate();
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
                   SKIP_WRITE_BARRIER);
  return true;
}

736
void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
737
  DCHECK(IsGlobalICKind(kind()));
738
  DCHECK(IC::IsHandler(*handler));
739
  SetFeedback(HeapObjectReference::ClearedValue());
740
  SetFeedbackExtra(*handler);
741 742
}

743 744 745 746 747 748 749 750 751 752 753 754 755 756 757
void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
                                         Handle<Map> result_map) {
  Isolate* isolate = GetIsolate();
  MaybeObject* maybe_feedback = GetFeedback();
  Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeakHeapObject()
                                  ? maybe_feedback->GetHeapObject()
                                  : nullptr,
                              isolate);
  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:
758 759 760
      if (maybe_feedback->IsClearedWeakHeapObject() ||
          feedback.is_identical_to(source_map) ||
          Map::cast(*feedback)->is_deprecated()) {
761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780
        // Remain in MONOMORPHIC state if previous feedback has been collected.
        SetFeedback(HeapObjectReference::Weak(*source_map));
        SetFeedbackExtra(*result_map);
      } else {
        // Transition to POLYMORPHIC.
        Handle<WeakFixedArray> array =
            EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
        array->Set(0, maybe_feedback);
        array->Set(1, GetFeedbackExtra());
        array->Set(2, HeapObjectReference::Weak(*source_map));
        array->Set(3, MaybeObject::FromObject(*result_map));
        SetFeedbackExtra(HeapObjectReference::ClearedValue());
      }
      break;
    case POLYMORPHIC: {
      static constexpr int kMaxElements =
          IC::kMaxPolymorphicMapCount * kCloneObjectPolymorphicEntrySize;
      Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
      int i = 0;
      for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
781 782 783 784 785
        MaybeObject* feedback = array->Get(i);
        if (feedback->IsClearedWeakHeapObject()) break;
        Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate);
        if (cached_map.is_identical_to(source_map) ||
            cached_map->is_deprecated())
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817
          break;
      }

      if (i >= array->length()) {
        if (i == kMaxElements) {
          // Transition to MEGAMORPHIC.
          MaybeObject* sentinel = MaybeObject::FromObject(
              *FeedbackVector::MegamorphicSentinel(isolate));
          SetFeedback(sentinel, SKIP_WRITE_BARRIER);
          SetFeedbackExtra(HeapObjectReference::ClearedValue());
          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();
  }
}

818 819
int FeedbackNexus::GetCallCount() {
  DCHECK(IsCallICKind(kind()));
820

821
  Object* call_count = GetFeedbackExtra()->ToObject();
822
  CHECK(call_count->IsSmi());
823 824
  uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
  return CallCountField::decode(value);
825 826
}

827 828 829
void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
  DCHECK(IsCallICKind(kind()));

830
  Object* call_count = GetFeedbackExtra()->ToObject();
831
  CHECK(call_count->IsSmi());
832 833 834
  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));
835 836 837
  SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
}

838 839 840
SpeculationMode FeedbackNexus::GetSpeculationMode() {
  DCHECK(IsCallICKind(kind()));

841
  Object* call_count = GetFeedbackExtra()->ToObject();
842 843 844 845
  CHECK(call_count->IsSmi());
  uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
  return SpeculationModeField::decode(value);
}
846 847 848 849

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

850
  double const invocation_count = vector()->invocation_count();
851
  double const call_count = GetCallCount();
852 853 854 855
  if (invocation_count == 0) {
    // Prevent division by 0.
    return 0.0f;
  }
856 857 858
  return static_cast<float>(call_count / invocation_count);
}

859 860
void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
                                         Handle<Map> receiver_map,
861
                                         const MaybeObjectHandle& handler) {
862
  DCHECK(handler.is_null() || IC::IsHandler(*handler));
863
  if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
864
    SetFeedback(HeapObjectReference::Weak(*receiver_map));
865
    SetFeedbackExtra(*name);
866
  } else {
867
    if (name.is_null()) {
868
      SetFeedback(HeapObjectReference::Weak(*receiver_map));
869
      SetFeedbackExtra(*handler);
870
    } else {
871
      Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
872
      SetFeedback(*name);
873
      array->Set(0, HeapObjectReference::Weak(*receiver_map));
874
      array->Set(1, *handler);
875
    }
876
  }
877 878
}

879 880
void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
                                         MapHandles const& maps,
881
                                         MaybeObjectHandles* handlers) {
882
  DCHECK_EQ(handlers->size(), maps.size());
883
  int receiver_count = static_cast<int>(maps.size());
884
  DCHECK_GT(receiver_count, 1);
885
  Handle<WeakFixedArray> array;
886
  if (name.is_null()) {
887
    array = EnsureArrayOfSize(receiver_count * 2);
888
    SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
889
                     SKIP_WRITE_BARRIER);
890
  } else {
891
    array = EnsureExtraArrayOfSize(receiver_count * 2);
892
    SetFeedback(*name);
893
  }
894

895
  for (int current = 0; current < receiver_count; ++current) {
896
    Handle<Map> map = maps[current];
897
    array->Set(current * 2, HeapObjectReference::Weak(*map));
898
    DCHECK(IC::IsHandler(*handlers->at(current)));
899
    array->Set(current * 2 + 1, *handlers->at(current));
900
  }
901 902
}

903
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
904 905
  DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
         IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
906 907
         IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
         IsStoreInArrayLiteralICKind(kind()));
908

909
  Isolate* isolate = GetIsolate();
910
  MaybeObject* feedback = GetFeedback();
911
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
912 913 914 915
  HeapObject* heap_object;
  if ((feedback->ToStrongHeapObject(&heap_object) &&
       heap_object->IsWeakFixedArray()) ||
      is_named_feedback) {
916
    int found = 0;
917
    WeakFixedArray* array;
918
    if (is_named_feedback) {
919 920
      array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject());
    } else {
921
      array = WeakFixedArray::cast(heap_object);
922
    }
923
    const int increment = 2;
924
    HeapObject* heap_object;
925
    for (int i = 0; i < array->length(); i += increment) {
926 927 928
      DCHECK(array->Get(i)->IsWeakOrClearedHeapObject());
      if (array->Get(i)->ToWeakHeapObject(&heap_object)) {
        Map* map = Map::cast(heap_object);
929
        maps->push_back(handle(map, isolate));
930 931
        found++;
      }
932
    }
933
    return found;
934 935 936 937
  } else if (feedback->ToWeakHeapObject(&heap_object)) {
    Map* map = Map::cast(heap_object);
    maps->push_back(handle(map, isolate));
    return 1;
938 939 940 941 942 943 944 945
  } else if (feedback->ToStrongHeapObject(&heap_object) &&
             heap_object ==
                 heap_object->GetReadOnlyRoots().premonomorphic_symbol()) {
    if (GetFeedbackExtra()->ToWeakHeapObject(&heap_object)) {
      Map* map = Map::cast(heap_object);
      maps->push_back(handle(map, isolate));
      return 1;
    }
946 947 948 949 950
  }

  return 0;
}

951
MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
952 953 954 955
  DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
         IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
         IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()));

956
  MaybeObject* feedback = GetFeedback();
957
  Isolate* isolate = GetIsolate();
958
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
959 960 961 962
  HeapObject* heap_object;
  if ((feedback->ToStrongHeapObject(&heap_object) &&
       heap_object->IsWeakFixedArray()) ||
      is_named_feedback) {
963
    WeakFixedArray* array;
964
    if (is_named_feedback) {
965 966
      array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject());
    } else {
967
      array = WeakFixedArray::cast(heap_object);
968
    }
969
    const int increment = 2;
970
    HeapObject* heap_object;
971
    for (int i = 0; i < array->length(); i += increment) {
972 973 974
      DCHECK(array->Get(i)->IsWeakOrClearedHeapObject());
      if (array->Get(i)->ToWeakHeapObject(&heap_object)) {
        Map* array_map = Map::cast(heap_object);
975 976
        if (array_map == *map &&
            !array->Get(i + increment - 1)->IsClearedWeakHeapObject()) {
977
          MaybeObject* handler = array->Get(i + increment - 1);
978 979
          DCHECK(IC::IsHandler(handler));
          return handle(handler, isolate);
980
        }
981 982
      }
    }
983 984 985 986 987 988
  } else if (feedback->ToWeakHeapObject(&heap_object)) {
    Map* cell_map = Map::cast(heap_object);
    if (cell_map == *map && !GetFeedbackExtra()->IsClearedWeakHeapObject()) {
      MaybeObject* handler = GetFeedbackExtra();
      DCHECK(IC::IsHandler(handler));
      return handle(handler, isolate);
989
    }
990 991
  }

992
  return MaybeObjectHandle();
993 994
}

995 996
bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list,
                                 int length) const {
997 998
  DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
         IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
999 1000
         IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
         IsStoreInArrayLiteralICKind(kind()));
1001

1002
  MaybeObject* feedback = GetFeedback();
1003
  Isolate* isolate = GetIsolate();
1004
  int count = 0;
1005
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
1006 1007 1008 1009
  HeapObject* heap_object;
  if ((feedback->ToStrongHeapObject(&heap_object) &&
       heap_object->IsWeakFixedArray()) ||
      is_named_feedback) {
1010
    WeakFixedArray* array;
1011
    if (is_named_feedback) {
1012 1013
      array = WeakFixedArray::cast(GetFeedbackExtra()->ToStrongHeapObject());
    } else {
1014
      array = WeakFixedArray::cast(heap_object);
1015
    }
1016
    const int increment = 2;
1017
    HeapObject* heap_object;
1018
    for (int i = 0; i < array->length(); i += increment) {
1019
      // Be sure to skip handlers whose maps have been cleared.
1020 1021
      DCHECK(array->Get(i)->IsWeakOrClearedHeapObject());
      if (array->Get(i)->ToWeakHeapObject(&heap_object) &&
1022
          !array->Get(i + increment - 1)->IsClearedWeakHeapObject()) {
1023
        MaybeObject* handler = array->Get(i + increment - 1);
1024 1025
        DCHECK(IC::IsHandler(handler));
        code_list->push_back(handle(handler, isolate));
1026 1027
        count++;
      }
1028
    }
1029
  } else if (feedback->ToWeakHeapObject(&heap_object)) {
1030
    MaybeObject* extra = GetFeedbackExtra();
1031
    if (!extra->IsClearedWeakHeapObject()) {
1032 1033
      DCHECK(IC::IsHandler(extra));
      code_list->push_back(handle(extra, isolate));
1034 1035
      count++;
    }
1036 1037 1038
  }
  return count == length;
}
1039

1040 1041
Name* FeedbackNexus::FindFirstName() const {
  if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind())) {
1042
    MaybeObject* feedback = GetFeedback();
1043
    if (IsPropertyNameFeedback(feedback)) {
1044
      return Name::cast(feedback->ToStrongHeapObject());
1045
    }
1046
  }
1047
  return nullptr;
1048 1049
}

1050 1051
KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
  DCHECK(IsKeyedLoadICKind(kind()));
1052
  MapHandles maps;
1053
  MaybeObjectHandles handlers;
1054

1055
  if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1056 1057 1058

  ExtractMaps(&maps);
  FindHandlers(&handlers, static_cast<int>(maps.size()));
1059
  for (MaybeObjectHandle const& handler : handlers) {
1060 1061
    KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
    if (mode != STANDARD_LOAD) return mode;
1062 1063
  }

1064
  return STANDARD_LOAD;
1065 1066
}

1067
KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1068
  DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
1069
  KeyedAccessStoreMode mode = STANDARD_STORE;
1070
  MapHandles maps;
1071
  MaybeObjectHandles handlers;
1072 1073 1074 1075

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

  ExtractMaps(&maps);
1076
  FindHandlers(&handlers, static_cast<int>(maps.size()));
1077
  for (const MaybeObjectHandle& maybe_code_handler : handlers) {
1078
    // The first handler that isn't the slow handler will have the bits we need.
1079
    Handle<Code> handler;
1080
    if (maybe_code_handler.object()->IsStoreHandler()) {
1081
      Handle<StoreHandler> data_handler =
1082
          Handle<StoreHandler>::cast(maybe_code_handler.object());
1083 1084
      handler = handle(Code::cast(data_handler->smi_handler()),
                       vector()->GetIsolate());
1085
    } else if (maybe_code_handler.object()->IsSmi()) {
1086
      // Skip proxy handlers.
1087 1088
      DCHECK_EQ(*(maybe_code_handler.object()),
                *StoreHandler::StoreProxy(GetIsolate()));
1089
      continue;
1090
    } else {
1091
      // Element store without prototype chain check.
1092
      handler = Handle<Code>::cast(maybe_code_handler.object());
1093
      if (handler->is_builtin()) continue;
1094
    }
1095 1096 1097 1098
    CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
    uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
    CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
          major_key == CodeStub::StoreFastElement ||
1099
          major_key == CodeStub::StoreSlowElement ||
Georg Neis's avatar
Georg Neis committed
1100
          major_key == CodeStub::StoreInArrayLiteralSlow ||
1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
          major_key == CodeStub::ElementsTransitionAndStore ||
          major_key == CodeStub::NoCache);
    if (major_key != CodeStub::NoCache) {
      mode = CommonStoreModeBits::decode(minor_key);
      break;
    }
  }

  return mode;
}

1112
IcCheckType FeedbackNexus::GetKeyType() const {
1113 1114
  DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
         IsStoreInArrayLiteralICKind(kind()));
1115 1116 1117
  MaybeObject* feedback = GetFeedback();
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
1118
    return static_cast<IcCheckType>(Smi::ToInt(GetFeedbackExtra()->ToObject()));
1119 1120 1121
  }
  return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
}
1122

1123 1124
BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1125
  int feedback = Smi::ToInt(GetFeedback()->ToSmi());
1126 1127 1128
  return BinaryOperationHintFromFeedback(feedback);
}

1129 1130
CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1131
  int feedback = Smi::ToInt(GetFeedback()->ToSmi());
1132 1133 1134
  return CompareOperationHintFromFeedback(feedback);
}

1135 1136
ForInHint FeedbackNexus::GetForInFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1137
  int feedback = Smi::ToInt(GetFeedback()->ToSmi());
1138
  return ForInHintFromFeedback(feedback);
1139 1140
}

1141 1142
Handle<FeedbackCell> FeedbackNexus::GetFeedbackCell() const {
  DCHECK_EQ(FeedbackSlotKind::kCreateClosure, kind());
1143 1144
  return handle(FeedbackCell::cast(GetFeedback()->ToObject()),
                vector()->GetIsolate());
1145 1146
}

1147 1148
MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
  DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1149
  Isolate* isolate = GetIsolate();
1150 1151 1152 1153
  MaybeObject* feedback = GetFeedback();
  HeapObject* heap_object;
  if (feedback->ToWeakHeapObject(&heap_object)) {
    return handle(JSObject::cast(heap_object), isolate);
1154 1155 1156 1157
  }
  return MaybeHandle<JSObject>();
}

1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
namespace {

bool InList(Handle<ArrayList> types, Handle<String> type) {
  for (int i = 0; i < types->Length(); i++) {
    Object* obj = types->Get(i);
    if (String::cast(obj)->Equals(*type)) {
      return true;
    }
  }
  return false;
}
}  // anonymous namespace

1171 1172
void FeedbackNexus::Collect(Handle<String> type, int position) {
  DCHECK(IsTypeProfileKind(kind()));
1173
  DCHECK_GE(position, 0);
1174 1175
  Isolate* isolate = GetIsolate();

1176
  MaybeObject* const feedback = GetFeedback();
1177 1178

  // Map source position to collection of types
1179
  Handle<SimpleNumberDictionary> types;
1180

1181 1182
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1183
    types = SimpleNumberDictionary::New(isolate, 1);
1184
  } else {
1185 1186
    types = handle(SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()),
                   isolate);
1187
  }
1188

1189
  Handle<ArrayList> position_specific_types;
1190

1191
  int entry = types->FindEntry(isolate, position);
1192
  if (entry == SimpleNumberDictionary::kNotFound) {
1193
    position_specific_types = ArrayList::New(isolate, 1);
1194
    types = SimpleNumberDictionary::Set(
1195 1196
        isolate, types, position,
        ArrayList::Add(isolate, position_specific_types, type));
1197
  } else {
1198
    DCHECK(types->ValueAt(entry)->IsArrayList());
1199 1200
    position_specific_types =
        handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1201
    if (!InList(position_specific_types, type)) {  // Add type
1202
      types = SimpleNumberDictionary::Set(
1203 1204
          isolate, types, position,
          ArrayList::Add(isolate, position_specific_types, type));
1205
    }
1206 1207
  }
  SetFeedback(*types);
1208 1209
}

1210 1211
std::vector<int> FeedbackNexus::GetSourcePositions() const {
  DCHECK(IsTypeProfileKind(kind()));
1212 1213 1214
  std::vector<int> source_positions;
  Isolate* isolate = GetIsolate();

1215
  MaybeObject* const feedback = GetFeedback();
1216

1217 1218
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1219 1220 1221
    return source_positions;
  }

1222 1223
  Handle<SimpleNumberDictionary> types(
      SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), isolate);
1224

1225 1226 1227
  for (int index = SimpleNumberDictionary::kElementsStartIndex;
       index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
    int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1228 1229 1230 1231 1232 1233 1234 1235 1236
    Object* key = types->get(key_index);
    if (key->IsSmi()) {
      int position = Smi::cast(key)->value();
      source_positions.push_back(position);
    }
  }
  return source_positions;
}

1237
std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1238
    uint32_t position) const {
1239
  DCHECK(IsTypeProfileKind(kind()));
1240 1241
  Isolate* isolate = GetIsolate();

1242
  MaybeObject* const feedback = GetFeedback();
1243
  std::vector<Handle<String>> types_for_position;
1244 1245
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1246 1247 1248
    return types_for_position;
  }

1249 1250
  Handle<SimpleNumberDictionary> types(
      SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()), isolate);
1251

1252
  int entry = types->FindEntry(isolate, position);
1253
  if (entry == SimpleNumberDictionary::kNotFound) {
1254 1255 1256 1257
    return types_for_position;
  }
  DCHECK(types->ValueAt(entry)->IsArrayList());
  Handle<ArrayList> position_specific_types =
1258
      Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1259 1260 1261 1262 1263 1264 1265 1266
  for (int i = 0; i < position_specific_types->Length(); i++) {
    Object* t = position_specific_types->Get(i);
    types_for_position.push_back(Handle<String>(String::cast(t), isolate));
  }

  return types_for_position;
}

1267 1268
namespace {

1269
Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1270
                                   Handle<SimpleNumberDictionary> feedback) {
1271 1272
  Handle<JSObject> type_profile =
      isolate->factory()->NewJSObject(isolate->object_function());
1273

1274 1275 1276 1277
  for (int index = SimpleNumberDictionary::kElementsStartIndex;
       index < feedback->length();
       index += SimpleNumberDictionary::kEntrySize) {
    int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1278
    Object* key = feedback->get(key_index);
1279
    if (key->IsSmi()) {
1280
      int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1281

1282
      Handle<ArrayList> position_specific_types(
1283
          ArrayList::cast(feedback->get(value_index)), isolate);
1284

jgruber's avatar
jgruber committed
1285
      int position = Smi::ToInt(key);
1286 1287 1288
      JSObject::AddDataElement(
          type_profile, position,
          isolate->factory()->NewJSArrayWithElements(
1289
              ArrayList::Elements(isolate, position_specific_types)),
1290
          PropertyAttributes::NONE);
1291 1292
    }
  }
1293
  return type_profile;
1294 1295 1296
}
}  // namespace

1297 1298
JSObject* FeedbackNexus::GetTypeProfile() const {
  DCHECK(IsTypeProfileKind(kind()));
1299 1300
  Isolate* isolate = GetIsolate();

1301
  MaybeObject* const feedback = GetFeedback();
1302

1303 1304
  if (feedback == MaybeObject::FromObject(
                      *FeedbackVector::UninitializedSentinel(isolate))) {
1305
    return *isolate->factory()->NewJSObject(isolate->object_function());
1306 1307
  }

1308 1309
  return *ConvertToJSObject(
      isolate,
1310 1311
      handle(SimpleNumberDictionary::cast(feedback->ToStrongHeapObject()),
             isolate));
1312 1313
}

1314 1315 1316 1317 1318
void FeedbackNexus::ResetTypeProfile() {
  DCHECK(IsTypeProfileKind(kind()));
  SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
}

1319 1320
}  // namespace internal
}  // namespace v8