feedback-vector.cc 38.7 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/object-macros.h"
11 12 13 14

namespace v8 {
namespace internal {

15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
template <typename Derived>
FeedbackSlot FeedbackVectorSpecBase<Derived>::AddSlot(FeedbackSlotKind kind) {
  int slot = This()->slots();
  int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
  This()->append(kind);
  for (int i = 1; i < entries_per_slot; i++) {
    This()->append(FeedbackSlotKind::kInvalid);
  }
  return FeedbackSlot(slot);
}

template FeedbackSlot FeedbackVectorSpecBase<FeedbackVectorSpec>::AddSlot(
    FeedbackSlotKind kind);
template FeedbackSlot FeedbackVectorSpecBase<StaticFeedbackVectorSpec>::AddSlot(
    FeedbackSlotKind kind);

template <typename Derived>
FeedbackSlot FeedbackVectorSpecBase<Derived>::AddTypeProfileSlot() {
  FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
  CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
           FeedbackVector::GetIndex(slot));
  return slot;
}

template FeedbackSlot
FeedbackVectorSpecBase<FeedbackVectorSpec>::AddTypeProfileSlot();
template FeedbackSlot
FeedbackVectorSpecBase<StaticFeedbackVectorSpec>::AddTypeProfileSlot();

44 45 46 47 48 49 50 51 52
bool FeedbackVectorSpec::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  if (slots() <= slot.ToInt()) {
    return false;
  }
  return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
}

53
static bool IsPropertyNameFeedback(Object* feedback) {
54 55 56 57 58 59 60
  if (feedback->IsString()) return true;
  if (!feedback->IsSymbol()) return false;
  Symbol* symbol = Symbol::cast(feedback);
  Heap* heap = symbol->GetHeap();
  return symbol != heap->uninitialized_symbol() &&
         symbol != heap->premonomorphic_symbol() &&
         symbol != heap->megamorphic_symbol();
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
  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
jgruber's avatar
jgruber committed
69
  int data = Smi::ToInt(get(index));
70
  return VectorICComputer::decode(data, slot.ToInt());
71 72
}

73
void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
74
  int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
jgruber's avatar
jgruber committed
75
  int data = Smi::ToInt(get(index));
76
  int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
77 78 79
  set(index, Smi::FromInt(new_data));
}

80
template Handle<FeedbackMetadata> FeedbackMetadata::New(
81
    Isolate* isolate, const StaticFeedbackVectorSpec* spec);
82
template Handle<FeedbackMetadata> FeedbackMetadata::New(
83
    Isolate* isolate, const FeedbackVectorSpec* spec);
84

85
// static
86
template <typename Spec>
87 88
Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
                                               const Spec* spec) {
89 90
  Factory* factory = isolate->factory();

91
  const int slot_count = spec->slots();
92 93
  const int slot_kinds_length = VectorICComputer::word_count(slot_count);
  const int length = slot_kinds_length + kReservedIndexCount;
94
  if (length == kReservedIndexCount) {
95
    return Handle<FeedbackMetadata>::cast(factory->empty_fixed_array());
96
  }
97 98
#ifdef DEBUG
  for (int i = 0; i < slot_count;) {
99
    FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
100
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
101
    for (int j = 1; j < entry_size; j++) {
102
      FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
103
      DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
104 105 106 107
    }
    i += entry_size;
  }
#endif
108

109
  Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
110
  array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
111 112
  // Fill the bit-vector part with zeros.
  for (int i = 0; i < slot_kinds_length; i++) {
113
    array->set(kReservedIndexCount + i, Smi::kZero);
114
  }
115

116
  Handle<FeedbackMetadata> metadata = Handle<FeedbackMetadata>::cast(array);
117

118
  for (int i = 0; i < slot_count; i++) {
119 120
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = spec->GetKind(slot);
121
    metadata->SetKind(slot, kind);
122
  }
123

124
  // It's important that the FeedbackMetadata have a COW map, since it's
125
  // pointed to by both a SharedFunctionInfo and indirectly by closures through
126
  // the FeedbackVector. The serializer uses the COW map type to decide
127 128 129 130
  // this object belongs in the startup snapshot and not the partial
  // snapshot(s).
  metadata->set_map(isolate->heap()->fixed_cow_array_map());

131 132 133
  return metadata;
}

134
bool FeedbackMetadata::SpecDiffersFrom(
135 136 137 138 139 140
    const FeedbackVectorSpec* other_spec) const {
  if (other_spec->slots() != slot_count()) {
    return true;
  }

  int slots = slot_count();
141
  for (int i = 0; i < slots;) {
142 143
    FeedbackSlot slot(i);
    FeedbackSlotKind kind = GetKind(slot);
144
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
145

146
    if (kind != other_spec->GetKind(slot)) {
147 148
      return true;
    }
149
    i += entry_size;
150 151 152 153
  }
  return false;
}

154
const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
155
  switch (kind) {
156
    case FeedbackSlotKind::kInvalid:
157
      return "Invalid";
158
    case FeedbackSlotKind::kCall:
159
      return "Call";
160
    case FeedbackSlotKind::kLoadProperty:
161
      return "LoadProperty";
162
    case FeedbackSlotKind::kLoadGlobalInsideTypeof:
163
      return "LoadGlobalInsideTypeof";
164
    case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
165
      return "LoadGlobalNotInsideTypeof";
166
    case FeedbackSlotKind::kLoadKeyed:
167
      return "LoadKeyed";
168
    case FeedbackSlotKind::kStoreNamedSloppy:
169
      return "StoreNamedSloppy";
170
    case FeedbackSlotKind::kStoreNamedStrict:
171
      return "StoreNamedStrict";
172
    case FeedbackSlotKind::kStoreOwnNamed:
173 174 175 176 177
      return "StoreOwnNamed";
    case FeedbackSlotKind::kStoreGlobalSloppy:
      return "StoreGlobalSloppy";
    case FeedbackSlotKind::kStoreGlobalStrict:
      return "StoreGlobalStrict";
178
    case FeedbackSlotKind::kStoreKeyedSloppy:
179
      return "StoreKeyedSloppy";
180
    case FeedbackSlotKind::kStoreKeyedStrict:
181
      return "StoreKeyedStrict";
182
    case FeedbackSlotKind::kBinaryOp:
183
      return "BinaryOp";
184
    case FeedbackSlotKind::kCompareOp:
185
      return "CompareOp";
186
    case FeedbackSlotKind::kStoreDataPropertyInLiteral:
187
      return "StoreDataPropertyInLiteral";
188 189 190
    case FeedbackSlotKind::kCreateClosure:
      return "kCreateClosure";
    case FeedbackSlotKind::kLiteral:
191
      return "Literal";
192
    case FeedbackSlotKind::kTypeProfile:
193
      return "TypeProfile";
194 195
    case FeedbackSlotKind::kForIn:
      return "ForIn";
196 197
    case FeedbackSlotKind::kInstanceOf:
      return "InstanceOf";
198
    case FeedbackSlotKind::kKindsNumber:
199 200 201 202 203
      break;
  }
  UNREACHABLE();
}

204 205 206
bool FeedbackMetadata::HasTypeProfileSlot() const {
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
207 208
  return slot.ToInt() < this->length() &&
         GetKind(slot) == FeedbackSlotKind::kTypeProfile;
209 210
}

211
FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
212 213 214
  DCHECK(!is_empty());
  return metadata()->GetKind(slot);
}
215

216
FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
217 218 219 220 221
  DCHECK(metadata()->HasTypeProfileSlot());
  FeedbackSlot slot =
      FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
  DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
  return slot;
222 223
}

224
// static
225
Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
226
                                           Handle<SharedFunctionInfo> shared) {
227 228
  Factory* factory = isolate->factory();

229
  const int slot_count = shared->feedback_metadata()->slot_count();
230

231 232 233 234 235 236 237 238 239
  Handle<FeedbackVector> vector = factory->NewFeedbackVector(shared, TENURED);

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

  DCHECK_EQ(vector->shared_function_info(), *shared);
  DCHECK_EQ(vector->optimized_code_cell(),
            Smi::FromEnum(OptimizationMarker::kNone));
  DCHECK_EQ(vector->invocation_count(), 0);
  DCHECK_EQ(vector->profiler_ticks(), 0);
240
  DCHECK_EQ(vector->deopt_count(), 0);
241

242 243
  // Ensure we can skip the write barrier
  Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
244
  DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
245
  Handle<Oddball> undefined_value = factory->undefined_value();
246
  for (int i = 0; i < slot_count;) {
247
    FeedbackSlot slot(i);
248
    FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
249 250
    int index = FeedbackVector::GetIndex(slot);
    int entry_size = FeedbackMetadata::GetSlotSize(kind);
251

252 253
    Object* extra_value = *uninitialized_sentinel;
    switch (kind) {
254 255
      case FeedbackSlotKind::kLoadGlobalInsideTypeof:
      case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
256 257
        vector->set(index, isolate->heap()->empty_weak_cell(),
                    SKIP_WRITE_BARRIER);
258
        break;
259
      case FeedbackSlotKind::kForIn:
260 261
      case FeedbackSlotKind::kCompareOp:
      case FeedbackSlotKind::kBinaryOp:
262
        vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
263
        break;
264
      case FeedbackSlotKind::kCreateClosure: {
265
        Handle<Cell> cell = factory->NewNoClosuresCell(undefined_value);
266
        vector->set(index, *cell);
267
        break;
268
      }
269
      case FeedbackSlotKind::kLiteral:
270
        vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
271
        break;
272
      case FeedbackSlotKind::kCall:
273
        vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
274 275
        extra_value = Smi::kZero;
        break;
276 277
      case FeedbackSlotKind::kLoadProperty:
      case FeedbackSlotKind::kLoadKeyed:
278 279 280
      case FeedbackSlotKind::kStoreNamedSloppy:
      case FeedbackSlotKind::kStoreNamedStrict:
      case FeedbackSlotKind::kStoreOwnNamed:
281 282
      case FeedbackSlotKind::kStoreGlobalSloppy:
      case FeedbackSlotKind::kStoreGlobalStrict:
283 284 285
      case FeedbackSlotKind::kStoreKeyedSloppy:
      case FeedbackSlotKind::kStoreKeyedStrict:
      case FeedbackSlotKind::kStoreDataPropertyInLiteral:
286
      case FeedbackSlotKind::kTypeProfile:
287
      case FeedbackSlotKind::kInstanceOf:
288
        vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
289 290
        break;

291 292
      case FeedbackSlotKind::kInvalid:
      case FeedbackSlotKind::kKindsNumber:
293 294
        UNREACHABLE();
        break;
295
    }
296
    for (int j = 1; j < entry_size; j++) {
297
      vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
298 299 300
    }
    i += entry_size;
  }
301

302
  Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
303 304 305
  if (!isolate->is_best_effort_code_coverage() ||
      isolate->is_collecting_type_profile()) {
    AddToVectorsForProfilingTools(isolate, result);
306
  }
307
  return result;
308 309
}

310
// static
311 312 313 314
Handle<FeedbackVector> FeedbackVector::Copy(Isolate* isolate,
                                            Handle<FeedbackVector> vector) {
  Handle<FeedbackVector> result;
  result = Handle<FeedbackVector>::cast(
315
      isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
316 317 318
  if (!isolate->is_best_effort_code_coverage() ||
      isolate->is_collecting_type_profile()) {
    AddToVectorsForProfilingTools(isolate, result);
319
  }
320 321
  return result;
}
322

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

335 336 337 338 339 340
// static
void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
                                      Handle<Code> code) {
  DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
  Factory* factory = vector->GetIsolate()->factory();
  Handle<WeakCell> cell = factory->NewWeakCell(code);
341
  vector->set_optimized_code_cell(*cell);
342 343
}

344
void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
345
  set_optimized_code_cell(Smi::FromEnum(marker));
346 347
}

348
void FeedbackVector::ClearOptimizedCode() {
349
  set_optimized_code_cell(Smi::FromEnum(OptimizationMarker::kNone));
350 351 352 353
}

void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
    SharedFunctionInfo* shared, const char* reason) {
354
  Object* slot = optimized_code_cell();
355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371
  if (slot->IsSmi()) return;

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

  Code* code = Code::cast(cell->value());
  if (code->marked_for_deoptimization()) {
    if (FLAG_trace_deopt) {
      PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
             reason);
      shared->ShortPrint();
      PrintF("]\n");
    }
    if (!code->deopt_already_counted()) {
372
      increment_deopt_count();
373
      code->set_deopt_already_counted(true);
374
    }
375
    ClearOptimizedCode();
376 377 378
  }
}

379
bool FeedbackVector::ClearSlots(Isolate* isolate) {
380
  Object* uninitialized_sentinel =
381
      FeedbackVector::RawUninitializedSentinel(isolate);
382

383
  bool feedback_updated = false;
384
  FeedbackMetadataIterator iter(metadata());
385
  while (iter.HasNext()) {
386 387
    FeedbackSlot slot = iter.Next();
    FeedbackSlotKind kind = iter.kind();
388

389 390
    Object* obj = Get(slot);
    if (obj != uninitialized_sentinel) {
391
      switch (kind) {
392
        case FeedbackSlotKind::kCall: {
393
          CallICNexus nexus(this, slot);
394 395 396 397
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
398 399
          break;
        }
400
        case FeedbackSlotKind::kLoadProperty: {
401
          LoadICNexus nexus(this, slot);
402 403 404 405
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
406 407
          break;
        }
408 409
        case FeedbackSlotKind::kLoadGlobalInsideTypeof:
        case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: {
410
          LoadGlobalICNexus nexus(this, slot);
411 412 413 414
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
415 416
          break;
        }
417
        case FeedbackSlotKind::kLoadKeyed: {
418
          KeyedLoadICNexus nexus(this, slot);
419 420 421 422
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
423 424
          break;
        }
425 426
        case FeedbackSlotKind::kStoreNamedSloppy:
        case FeedbackSlotKind::kStoreNamedStrict:
427 428 429
        case FeedbackSlotKind::kStoreOwnNamed:
        case FeedbackSlotKind::kStoreGlobalSloppy:
        case FeedbackSlotKind::kStoreGlobalStrict: {
430
          StoreICNexus nexus(this, slot);
431 432 433 434
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
435 436
          break;
        }
437 438
        case FeedbackSlotKind::kStoreKeyedSloppy:
        case FeedbackSlotKind::kStoreKeyedStrict: {
439
          KeyedStoreICNexus nexus(this, slot);
440 441 442 443
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
444 445
          break;
        }
446
        case FeedbackSlotKind::kForIn:
447 448
        case FeedbackSlotKind::kBinaryOp:
        case FeedbackSlotKind::kCompareOp: {
449 450
          DCHECK(Get(slot)->IsSmi());
          // don't clear these smi slots.
451
          // Set(slot, Smi::kZero);
452 453
          break;
        }
454 455 456 457 458 459 460 461 462 463 464
        case FeedbackSlotKind::kInstanceOf: {
          InstanceOfICNexus nexus(this, slot);
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
          break;
        }
        case FeedbackSlotKind::kCreateClosure:
        case FeedbackSlotKind::kTypeProfile: {
          break;
465
        }
466
        case FeedbackSlotKind::kLiteral: {
467
          Set(slot, Smi::kZero, SKIP_WRITE_BARRIER);
468
          feedback_updated = true;
469 470
          break;
        }
471
        case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
472
          StoreDataPropertyInLiteralICNexus nexus(this, slot);
473 474 475 476
          if (!nexus.IsCleared()) {
            nexus.Clear();
            feedback_updated = true;
          }
477 478
          break;
        }
479 480
        case FeedbackSlotKind::kInvalid:
        case FeedbackSlotKind::kKindsNumber:
481 482
          UNREACHABLE();
          break;
483
      }
484 485
    }
  }
486
  return feedback_updated;
487
}
488 489 490 491 492 493 494 495 496 497 498 499 500

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

501
Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
502
  Isolate* isolate = GetIsolate();
503 504 505 506 507 508 509 510 511 512
  Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
  if (!feedback_extra->IsFixedArray() ||
      FixedArray::cast(*feedback_extra)->length() != length) {
    Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
    SetFeedbackExtra(*array);
    return array;
  }
  return Handle<FixedArray>::cast(feedback_extra);
}

513
void FeedbackNexus::ConfigureUninitialized() {
514
  SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()),
515
              SKIP_WRITE_BARRIER);
516
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
517 518 519 520
                   SKIP_WRITE_BARRIER);
}

void FeedbackNexus::ConfigurePremonomorphic() {
521
  SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
522
              SKIP_WRITE_BARRIER);
523
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
524 525 526
                   SKIP_WRITE_BARRIER);
}

527 528
bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
  DisallowHeapAllocation no_gc;
529
  Isolate* isolate = GetIsolate();
530 531 532 533 534 535 536 537 538 539 540 541 542
  bool changed = false;
  Symbol* sentinel = *FeedbackVector::MegamorphicSentinel(isolate);
  if (GetFeedback() != sentinel) {
    SetFeedback(sentinel, SKIP_WRITE_BARRIER);
    changed = true;
  }

  Smi* extra = Smi::FromInt(static_cast<int>(property_type));
  if (changed || GetFeedbackExtra() != extra) {
    SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
    changed = true;
  }
  return changed;
543
}
544

545 546 547
InlineCacheState LoadICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
548

549
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
550
    return UNINITIALIZED;
551
  } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
552
    return MEGAMORPHIC;
553
  } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
554 555
    return PREMONOMORPHIC;
  } else if (feedback->IsFixedArray()) {
556 557
    // Determine state purely by our structure, don't check if the maps are
    // cleared.
558 559 560 561
    return POLYMORPHIC;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
562 563 564 565 566
  }

  return UNINITIALIZED;
}

567 568 569 570
InlineCacheState LoadGlobalICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();

571 572
  Object* extra = GetFeedbackExtra();
  if (!WeakCell::cast(feedback)->cleared() ||
573
      extra != *FeedbackVector::UninitializedSentinel(isolate)) {
574
    return MONOMORPHIC;
575
  }
576 577
  return UNINITIALIZED;
}
578 579 580 581

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

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

  return UNINITIALIZED;
}

605 606 607 608
InlineCacheState StoreICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();

609
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
610
    return UNINITIALIZED;
611
  } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
612
    return MEGAMORPHIC;
613
  } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630
    return PREMONOMORPHIC;
  } else if (feedback->IsFixedArray()) {
    // Determine state purely by our structure, don't check if the maps are
    // cleared.
    return POLYMORPHIC;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
  }

  return UNINITIALIZED;
}

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

631
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
632
    return UNINITIALIZED;
633
  } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
634
    return PREMONOMORPHIC;
635
  } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652
    return MEGAMORPHIC;
  } else if (feedback->IsFixedArray()) {
    // Determine state purely by our structure, don't check if the maps are
    // cleared.
    return POLYMORPHIC;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
  } else if (feedback->IsName()) {
    Object* extra = GetFeedbackExtra();
    FixedArray* extra_array = FixedArray::cast(extra);
    return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
  }

  return UNINITIALIZED;
}

653 654 655
InlineCacheState CallICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
656
  DCHECK(GetFeedbackExtra() ==
657
             *FeedbackVector::UninitializedSentinel(isolate) ||
658
         GetFeedbackExtra()->IsSmi());
659

660
  if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
661
    return GENERIC;
662
  } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
663
    return MONOMORPHIC;
664 665
  }

666
  CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate));
667
  return UNINITIALIZED;
668 669
}

670 671
int CallICNexus::ExtractCallCount() {
  Object* call_count = GetFeedbackExtra();
672
  CHECK(call_count->IsSmi());
jgruber's avatar
jgruber committed
673
  int value = Smi::ToInt(call_count);
674
  return value;
675 676
}

677 678 679
float CallICNexus::ComputeCallFrequency() {
  double const invocation_count = vector()->invocation_count();
  double const call_count = ExtractCallCount();
680 681 682 683
  if (invocation_count == 0) {
    // Prevent division by 0.
    return 0.0f;
  }
684 685 686
  return static_cast<float>(call_count / invocation_count);
}

687 688
void CallICNexus::ConfigureUninitialized() {
  Isolate* isolate = GetIsolate();
689
  SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
690
              SKIP_WRITE_BARRIER);
691
  SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
692
}
693

694 695 696
void LoadGlobalICNexus::ConfigureUninitialized() {
  Isolate* isolate = GetIsolate();
  SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
697
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
698 699 700 701 702 703
                   SKIP_WRITE_BARRIER);
}

void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
  Isolate* isolate = GetIsolate();
  SetFeedback(*isolate->factory()->NewWeakCell(cell));
704
  SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
705 706 707
                   SKIP_WRITE_BARRIER);
}

708
void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) {
709 710 711 712
  SetFeedback(GetIsolate()->heap()->empty_weak_cell());
  SetFeedbackExtra(*handler);
}

713 714 715
void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
                                         Handle<Map> receiver_map,
                                         Handle<Object> handler) {
716 717 718 719 720 721
  Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
  if (name.is_null()) {
    SetFeedback(*cell);
    SetFeedbackExtra(*handler);
  } else {
    Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
722
    SetFeedback(*name);
723 724 725
    array->set(0, *cell);
    array->set(1, *handler);
  }
726 727
}

728 729
void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
                                         MapHandles const& maps,
730
                                         ObjectHandles* handlers) {
731
  int receiver_count = static_cast<int>(maps.size());
732
  DCHECK_GT(receiver_count, 1);
733
  Handle<FixedArray> array;
734
  if (name.is_null()) {
735
    array = EnsureArrayOfSize(receiver_count * 2);
736
    SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
737
                     SKIP_WRITE_BARRIER);
738
  } else {
739
    array = EnsureExtraArrayOfSize(receiver_count * 2);
740
    SetFeedback(*name);
741
  }
742

743
  for (int current = 0; current < receiver_count; ++current) {
744
    Handle<Map> map = maps[current];
745 746 747
    Handle<WeakCell> cell = Map::WeakCellForMap(map);
    array->set(current * 2, *cell);
    array->set(current * 2 + 1, *handlers->at(current));
748
  }
749 750
}

751
int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
752 753
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
754 755
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
  if (feedback->IsFixedArray() || is_named_feedback) {
756
    int found = 0;
757
    if (is_named_feedback) {
758 759
      feedback = GetFeedbackExtra();
    }
760
    FixedArray* array = FixedArray::cast(feedback);
761
    const int increment = 2;
762
    for (int i = 0; i < array->length(); i += increment) {
763
      DCHECK(array->get(i)->IsWeakCell());
764 765 766
      WeakCell* cell = WeakCell::cast(array->get(i));
      if (!cell->cleared()) {
        Map* map = Map::cast(cell->value());
767
        maps->push_back(handle(map, isolate));
768 769
        found++;
      }
770
    }
771
    return found;
772 773 774 775
  } else if (feedback->IsWeakCell()) {
    WeakCell* cell = WeakCell::cast(feedback);
    if (!cell->cleared()) {
      Map* map = Map::cast(cell->value());
776
      maps->push_back(handle(map, isolate));
777 778
      return 1;
    }
779 780 781 782 783
  }

  return 0;
}

784
MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
785
  Object* feedback = GetFeedback();
786
  Isolate* isolate = GetIsolate();
787 788 789
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
  if (feedback->IsFixedArray() || is_named_feedback) {
    if (is_named_feedback) {
790 791
      feedback = GetFeedbackExtra();
    }
792
    FixedArray* array = FixedArray::cast(feedback);
793
    const int increment = 2;
794
    for (int i = 0; i < array->length(); i += increment) {
795
      DCHECK(array->get(i)->IsWeakCell());
796 797 798 799
      WeakCell* cell = WeakCell::cast(array->get(i));
      if (!cell->cleared()) {
        Map* array_map = Map::cast(cell->value());
        if (array_map == *map) {
800
          Object* code = array->get(i + increment - 1);
801
          DCHECK(IC::IsHandler(code));
802
          return handle(code, isolate);
803
        }
804 805
      }
    }
806 807 808 809 810
  } else if (feedback->IsWeakCell()) {
    WeakCell* cell = WeakCell::cast(feedback);
    if (!cell->cleared()) {
      Map* cell_map = Map::cast(cell->value());
      if (cell_map == *map) {
811
        Object* code = GetFeedbackExtra();
812
        DCHECK(IC::IsHandler(code));
813
        return handle(code, isolate);
814 815
      }
    }
816 817 818 819 820
  }

  return MaybeHandle<Code>();
}

821
bool FeedbackNexus::FindHandlers(ObjectHandles* code_list, int length) const {
822
  Object* feedback = GetFeedback();
823
  Isolate* isolate = GetIsolate();
824
  int count = 0;
825 826 827
  bool is_named_feedback = IsPropertyNameFeedback(feedback);
  if (feedback->IsFixedArray() || is_named_feedback) {
    if (is_named_feedback) {
828 829
      feedback = GetFeedbackExtra();
    }
830
    FixedArray* array = FixedArray::cast(feedback);
831
    const int increment = 2;
832
    for (int i = 0; i < array->length(); i += increment) {
833
      DCHECK(array->get(i)->IsWeakCell());
834
      WeakCell* cell = WeakCell::cast(array->get(i));
835
      // Be sure to skip handlers whose maps have been cleared.
836
      if (!cell->cleared()) {
837
        Object* code = array->get(i + increment - 1);
838
        DCHECK(IC::IsHandler(code));
839
        code_list->push_back(handle(code, isolate));
840 841
        count++;
      }
842
    }
843 844 845
  } else if (feedback->IsWeakCell()) {
    WeakCell* cell = WeakCell::cast(feedback);
    if (!cell->cleared()) {
846
      Object* code = GetFeedbackExtra();
847
      DCHECK(IC::IsHandler(code));
848
      code_list->push_back(handle(code, isolate));
849 850
      count++;
    }
851 852 853
  }
  return count == length;
}
854 855 856

Name* KeyedLoadICNexus::FindFirstName() const {
  Object* feedback = GetFeedback();
857
  if (IsPropertyNameFeedback(feedback)) {
858
    return Name::cast(feedback);
859
  }
860
  return nullptr;
861
}
862 863 864

Name* KeyedStoreICNexus::FindFirstName() const {
  Object* feedback = GetFeedback();
865
  if (IsPropertyNameFeedback(feedback)) {
866 867
    return Name::cast(feedback);
  }
868
  return nullptr;
869 870
}

871 872 873 874
KeyedAccessLoadMode KeyedLoadICNexus::GetKeyedAccessLoadMode() const {
  MapHandles maps;
  ObjectHandles handlers;

875
  if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
876 877 878 879

  ExtractMaps(&maps);
  FindHandlers(&handlers, static_cast<int>(maps.size()));
  for (Handle<Object> const& handler : handlers) {
880 881
    KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
    if (mode != STANDARD_LOAD) return mode;
882 883
  }

884
  return STANDARD_LOAD;
885 886
}

887 888
KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
  KeyedAccessStoreMode mode = STANDARD_STORE;
889
  MapHandles maps;
890
  ObjectHandles handlers;
891 892 893 894

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

  ExtractMaps(&maps);
895
  FindHandlers(&handlers, static_cast<int>(maps.size()));
896
  for (const Handle<Object>& maybe_code_handler : handlers) {
897
    // The first handler that isn't the slow handler will have the bits we need.
898
    Handle<Code> handler;
899 900 901 902 903 904
    if (maybe_code_handler->IsTuple3()) {
      // Elements transition.
      Handle<Tuple3> data_handler = Handle<Tuple3>::cast(maybe_code_handler);
      handler = handle(Code::cast(data_handler->value2()));
    } else if (maybe_code_handler->IsTuple2()) {
      // Element store with prototype chain check.
905 906
      Handle<Tuple2> data_handler = Handle<Tuple2>::cast(maybe_code_handler);
      handler = handle(Code::cast(data_handler->value2()));
907 908 909 910
    } else if (maybe_code_handler->IsSmi()) {
      // Skip proxy handlers.
      DCHECK_EQ(*maybe_code_handler, *StoreHandler::StoreProxy(GetIsolate()));
      continue;
911
    } else {
912
      // Element store without prototype chain check.
913
      handler = Handle<Code>::cast(maybe_code_handler);
914
      if (handler->is_builtin()) continue;
915
    }
916 917 918 919
    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 ||
920
          major_key == CodeStub::StoreSlowElement ||
921 922 923 924 925 926 927 928 929 930 931
          major_key == CodeStub::ElementsTransitionAndStore ||
          major_key == CodeStub::NoCache);
    if (major_key != CodeStub::NoCache) {
      mode = CommonStoreModeBits::decode(minor_key);
      break;
    }
  }

  return mode;
}

932 933
IcCheckType KeyedLoadICNexus::GetKeyType() const {
  Object* feedback = GetFeedback();
934
  if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
jgruber's avatar
jgruber committed
935
    return static_cast<IcCheckType>(Smi::ToInt(GetFeedbackExtra()));
936 937 938
  }
  return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
}
939 940

IcCheckType KeyedStoreICNexus::GetKeyType() const {
941
  Object* feedback = GetFeedback();
942
  if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
jgruber's avatar
jgruber committed
943
    return static_cast<IcCheckType>(Smi::ToInt(GetFeedbackExtra()));
944 945
  }
  return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
946
}
947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970

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

  return MONOMORPHIC;
}

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

  return MONOMORPHIC;
}

BinaryOperationHint BinaryOpICNexus::GetBinaryOperationFeedback() const {
jgruber's avatar
jgruber committed
971
  int feedback = Smi::ToInt(GetFeedback());
972 973 974 975
  return BinaryOperationHintFromFeedback(feedback);
}

CompareOperationHint CompareICNexus::GetCompareOperationFeedback() const {
jgruber's avatar
jgruber committed
976
  int feedback = Smi::ToInt(GetFeedback());
977 978 979
  return CompareOperationHintFromFeedback(feedback);
}

980
InlineCacheState ForInICNexus::StateFromFeedback() const {
981 982
  ForInHint hint = GetForInFeedback();
  if (hint == ForInHint::kNone) {
983
    return UNINITIALIZED;
984 985
  } else if (hint == ForInHint::kAny) {
    return GENERIC;
986
  }
987 988 989 990 991 992
  return MONOMORPHIC;
}

ForInHint ForInICNexus::GetForInFeedback() const {
  int feedback = Smi::ToInt(GetFeedback());
  return ForInHintFromFeedback(feedback);
993 994
}

995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020
void InstanceOfICNexus::ConfigureUninitialized() {
  SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()),
              SKIP_WRITE_BARRIER);
}

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

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

MaybeHandle<JSObject> InstanceOfICNexus::GetConstructorFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();
  if (feedback->IsWeakCell() && !WeakCell::cast(feedback)->cleared()) {
    return handle(JSObject::cast(WeakCell::cast(feedback)->value()), isolate);
  }
  return MaybeHandle<JSObject>();
}

1021 1022 1023 1024
InlineCacheState StoreDataPropertyInLiteralICNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* feedback = GetFeedback();

1025
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042
    return UNINITIALIZED;
  } else if (feedback->IsWeakCell()) {
    // Don't check if the map is cleared.
    return MONOMORPHIC;
  }

  return MEGAMORPHIC;
}

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

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

1043 1044 1045 1046 1047 1048 1049 1050 1051 1052
InlineCacheState CollectTypeProfileNexus::StateFromFeedback() const {
  Isolate* isolate = GetIsolate();
  Object* const feedback = GetFeedback();

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

1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065
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

1066
void CollectTypeProfileNexus::Collect(Handle<String> type, int position) {
1067
  DCHECK_GE(position, 0);
1068 1069 1070
  Isolate* isolate = GetIsolate();

  Object* const feedback = GetFeedback();
1071 1072

  // Map source position to collection of types
1073
  Handle<NumberDictionary> types;
1074 1075

  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
1076
    types = NumberDictionary::New(isolate, 1);
1077
  } else {
1078
    types = handle(NumberDictionary::cast(feedback));
1079
  }
1080

1081
  Handle<ArrayList> position_specific_types;
1082

1083
  int entry = types->FindEntry(position);
1084
  if (entry == NumberDictionary::kNotFound) {
1085
    position_specific_types = ArrayList::New(isolate, 1);
1086
    types = NumberDictionary::Set(
1087
        types, position, ArrayList::Add(position_specific_types, type));
1088
  } else {
1089
    DCHECK(types->ValueAt(entry)->IsArrayList());
1090
    position_specific_types = handle(ArrayList::cast(types->ValueAt(entry)));
1091
    if (!InList(position_specific_types, type)) {  // Add type
1092
      types = NumberDictionary::Set(
1093 1094
          types, position, ArrayList::Add(position_specific_types, type));
    }
1095 1096
  }
  SetFeedback(*types);
1097 1098
}

1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112
void CollectTypeProfileNexus::Clear() {
  SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
}

std::vector<int> CollectTypeProfileNexus::GetSourcePositions() const {
  std::vector<int> source_positions;
  Isolate* isolate = GetIsolate();

  Object* const feedback = GetFeedback();

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

1113 1114
  Handle<NumberDictionary> types =
      Handle<NumberDictionary>(NumberDictionary::cast(feedback), isolate);
1115

1116 1117 1118
  for (int index = NumberDictionary::kElementsStartIndex;
       index < types->length(); index += NumberDictionary::kEntrySize) {
    int key_index = index + NumberDictionary::kEntryKeyIndex;
1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137
    Object* key = types->get(key_index);
    if (key->IsSmi()) {
      int position = Smi::cast(key)->value();
      source_positions.push_back(position);
    }
  }
  return source_positions;
}

std::vector<Handle<String>> CollectTypeProfileNexus::GetTypesForSourcePositions(
    uint32_t position) const {
  Isolate* isolate = GetIsolate();

  Object* const feedback = GetFeedback();
  std::vector<Handle<String>> types_for_position;
  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
    return types_for_position;
  }

1138 1139
  Handle<NumberDictionary> types =
      Handle<NumberDictionary>(NumberDictionary::cast(feedback), isolate);
1140 1141

  int entry = types->FindEntry(position);
1142
  if (entry == NumberDictionary::kNotFound) {
1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155
    return types_for_position;
  }
  DCHECK(types->ValueAt(entry)->IsArrayList());
  Handle<ArrayList> position_specific_types =
      Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)));
  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;
}

1156 1157
namespace {

1158
Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1159
                                   Handle<NumberDictionary> feedback) {
1160 1161
  Handle<JSObject> type_profile =
      isolate->factory()->NewJSObject(isolate->object_function());
1162

1163 1164 1165
  for (int index = NumberDictionary::kElementsStartIndex;
       index < feedback->length(); index += NumberDictionary::kEntrySize) {
    int key_index = index + NumberDictionary::kEntryKeyIndex;
1166
    Object* key = feedback->get(key_index);
1167
    if (key->IsSmi()) {
1168
      int value_index = index + NumberDictionary::kEntryValueIndex;
1169

1170 1171
      Handle<ArrayList> position_specific_types(
          ArrayList::cast(feedback->get(value_index)));
1172

jgruber's avatar
jgruber committed
1173
      int position = Smi::ToInt(key);
1174 1175 1176 1177 1178
      JSObject::AddDataElement(
          type_profile, position,
          isolate->factory()->NewJSArrayWithElements(
              ArrayList::Elements(position_specific_types)),
          PropertyAttributes::NONE)
1179
          .ToHandleChecked();
1180 1181
    }
  }
1182
  return type_profile;
1183 1184 1185
}
}  // namespace

1186
JSObject* CollectTypeProfileNexus::GetTypeProfile() const {
1187 1188 1189 1190 1191
  Isolate* isolate = GetIsolate();

  Object* const feedback = GetFeedback();

  if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
1192
    return *isolate->factory()->NewJSObject(isolate->object_function());
1193 1194
  }

1195
  return *ConvertToJSObject(isolate, handle(NumberDictionary::cast(feedback)));
1196 1197
}

1198 1199
}  // namespace internal
}  // namespace v8