test-feedback-vector.cc 20.3 KB
Newer Older
1 2 3 4 5 6 7 8
// 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.

#include "src/v8.h"
#include "test/cctest/cctest.h"

#include "src/api.h"
9
#include "src/debug/debug.h"
10 11 12 13
#include "src/execution.h"
#include "src/factory.h"
#include "src/global-handles.h"
#include "src/macro-assembler.h"
14
#include "src/objects-inl.h"
15
#include "test/cctest/test-feedback-vector.h"
16 17 18 19 20

using namespace v8::internal;

namespace {

21 22
#define CHECK_SLOT_KIND(helper, index, expected_kind) \
  CHECK_EQ(expected_kind, helper.vector()->GetKind(helper.slot(index)));
23 24


25 26 27 28 29 30 31 32 33
static Handle<JSFunction> GetFunction(const char* name) {
  v8::MaybeLocal<v8::Value> v8_f = CcTest::global()->Get(
      v8::Isolate::GetCurrent()->GetCurrentContext(), v8_str(name));
  Handle<JSFunction> f =
      Handle<JSFunction>::cast(v8::Utils::OpenHandle(*v8_f.ToLocalChecked()));
  return f;
}


34 35 36 37 38
TEST(VectorStructure) {
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();
  Factory* factory = isolate->factory();
39
  Zone zone(isolate->allocator(), ZONE_NAME);
40

41
  Handle<FeedbackVector> vector;
42 43

  {
44
    FeedbackVectorSpec one_slot(&zone);
45
    one_slot.AddGeneralSlot();
46
    vector = NewFeedbackVector(isolate, &one_slot);
47 48 49
    FeedbackVectorHelper helper(vector);
    CHECK_EQ(1, helper.slot_count());
  }
50

51
  {
52
    FeedbackVectorSpec one_icslot(&zone);
53
    one_icslot.AddCallICSlot();
54
    vector = NewFeedbackVector(isolate, &one_icslot);
55 56 57
    FeedbackVectorHelper helper(vector);
    CHECK_EQ(1, helper.slot_count());
  }
58

59
  {
60
    FeedbackVectorSpec spec(&zone);
61 62 63 64 65 66
    for (int i = 0; i < 3; i++) {
      spec.AddGeneralSlot();
    }
    for (int i = 0; i < 5; i++) {
      spec.AddCallICSlot();
    }
67
    vector = NewFeedbackVector(isolate, &spec);
68 69 70 71 72
    FeedbackVectorHelper helper(vector);
    CHECK_EQ(8, helper.slot_count());

    int index = vector->GetIndex(helper.slot(0));

73
    CHECK_EQ(helper.slot(0), vector->ToSlot(index));
74 75

    index = vector->GetIndex(helper.slot(3));
76
    CHECK_EQ(helper.slot(3), vector->ToSlot(index));
77 78

    index = vector->GetIndex(helper.slot(7));
79
    CHECK_EQ(3 + 4 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
80
             index);
81
    CHECK_EQ(helper.slot(7), vector->ToSlot(index));
82

83
    CHECK_EQ(3 + 5 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
84
             vector->length());
85
  }
86 87 88 89

  {
    FeedbackVectorSpec spec(&zone);
    spec.AddGeneralSlot();
90
    spec.AddCreateClosureSlot();
91
    spec.AddGeneralSlot();
92
    vector = NewFeedbackVector(isolate, &spec);
93
    FeedbackVectorHelper helper(vector);
94
    CHECK_EQ(1,
95
             FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCreateClosure));
96
    FeedbackSlot slot = helper.slot(1);
97 98
    Cell* cell = Cell::cast(vector->Get(slot));
    CHECK_EQ(cell->value(), *factory->undefined_value());
99
  }
100 101 102 103 104 105 106 107
}


// IC slots need an encoding to recognize what is in there.
TEST(VectorICMetadata) {
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();
108
  Zone zone(isolate->allocator(), ZONE_NAME);
109

110
  FeedbackVectorSpec spec(&zone);
111
  // Set metadata.
112 113
  for (int i = 0; i < 40; i++) {
    switch (i % 4) {
114
      case 0:
115
        spec.AddGeneralSlot();
116 117
        break;
      case 1:
118
        spec.AddCallICSlot();
119 120
        break;
      case 2:
121 122 123 124
        spec.AddLoadICSlot();
        break;
      case 3:
        spec.AddKeyedLoadICSlot();
125
        break;
126
    }
127 128
  }

129
  Handle<FeedbackVector> vector = NewFeedbackVector(isolate, &spec);
130 131
  FeedbackVectorHelper helper(vector);
  CHECK_EQ(40, helper.slot_count());
132

133 134
  // Meanwhile set some feedback values and type feedback values to
  // verify the data structure remains intact.
135
  vector->Set(FeedbackSlot(0), *vector);
136

137
  // Verify the metadata is correctly set up from the spec.
138
  for (int i = 0; i < 40; i++) {
139
    FeedbackSlotKind kind = vector->GetKind(helper.slot(i));
140 141
    switch (i % 4) {
      case 0:
142
        CHECK_EQ(FeedbackSlotKind::kGeneral, kind);
143 144
        break;
      case 1:
145
        CHECK_EQ(FeedbackSlotKind::kCall, kind);
146 147
        break;
      case 2:
148
        CHECK_EQ(FeedbackSlotKind::kLoadProperty, kind);
149 150
        break;
      case 3:
151
        CHECK_EQ(FeedbackSlotKind::kLoadKeyed, kind);
152
        break;
153 154
    }
  }
155 156 157 158 159 160 161 162
}


TEST(VectorSlotClearing) {
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();
  Factory* factory = isolate->factory();
163
  Zone zone(isolate->allocator(), ZONE_NAME);
164

165 166 167 168 169
  CompileRun("function f() {};");
  Handle<JSFunction> f = GetFunction("f");

  // We only test clearing of a FeedbackSlotKind::kGeneral slots because all
  // the other slot kinds require a host function for clearing.
170
  FeedbackVectorSpec spec(&zone);
171 172 173
  for (int i = 0; i < 5; i++) {
    spec.AddGeneralSlot();
  }
174
  Handle<FeedbackVector> vector = NewFeedbackVector(isolate, &spec);
175
  FeedbackVectorHelper helper(vector);
176 177

  // Fill with information
178
  vector->Set(helper.slot(0), Smi::FromInt(1));
179
  Handle<WeakCell> cell = factory->NewWeakCell(factory->fixed_array_map());
180
  vector->Set(helper.slot(1), *cell);
181
  Handle<AllocationSite> site = factory->NewAllocationSite();
182
  vector->Set(helper.slot(2), *site);
183

184
  vector->ClearSlots(*f);
185

186
  // The feedback vector slots are cleared. AllocationSites are still granted
187
  // an exemption from clearing, as are smis.
188
  CHECK_EQ(Smi::FromInt(1), vector->Get(helper.slot(0)));
189
  CHECK_EQ(*FeedbackVector::UninitializedSentinel(isolate),
190 191
           vector->Get(helper.slot(1)));
  CHECK(vector->Get(helper.slot(2))->IsAllocationSite());
192 193 194
}


195 196 197 198 199 200 201 202 203 204
TEST(VectorCallICStates) {
  if (i::FLAG_always_opt) return;
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();
  // Make sure function f has a call that uses a type feedback slot.
  CompileRun(
      "function foo() { return 17; }"
      "function f(a) { a(); } f(foo);");
205
  Handle<JSFunction> f = GetFunction("f");
206
  // There should be one IC.
207 208
  Handle<FeedbackVector> feedback_vector =
      Handle<FeedbackVector>(f->feedback_vector(), isolate);
209
  FeedbackSlot slot(0);
210 211 212
  CallICNexus nexus(feedback_vector, slot);
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
  // CallIC doesn't return map feedback.
213
  CHECK(!nexus.FindFirstMap());
214 215 216 217

  CompileRun("f(function() { return 16; })");
  CHECK_EQ(GENERIC, nexus.StateFromFeedback());

218
  // After a collection, state should remain GENERIC.
219
  CcTest::CollectAllGarbage();
220
  CHECK_EQ(GENERIC, nexus.StateFromFeedback());
221 222 223 224 225 226 227 228 229 230 231 232 233 234
}

TEST(VectorCallFeedbackForArray) {
  if (i::FLAG_always_opt) return;
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();
  // Make sure function f has a call that uses a type feedback slot.
  CompileRun(
      "function foo() { return 17; }"
      "function f(a) { a(); } f(Array);");
  Handle<JSFunction> f = GetFunction("f");
  // There should be one IC.
235 236
  Handle<FeedbackVector> feedback_vector =
      Handle<FeedbackVector>(f->feedback_vector(), isolate);
237
  FeedbackSlot slot(0);
238
  CallICNexus nexus(feedback_vector, slot);
239

240
  // A call to Array is special, it contains an AllocationSite as feedback.
241
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
242
  CHECK(nexus.GetFeedback()->IsAllocationSite());
243

244
  CcTest::CollectAllGarbage();
245
  // It should stay monomorphic even after a GC.
246 247
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
}
248

249 250 251 252 253 254 255 256 257 258 259 260 261
TEST(VectorCallCounts) {
  if (i::FLAG_always_opt) return;
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();

  // Make sure function f has a call that uses a type feedback slot.
  CompileRun(
      "function foo() { return 17; }"
      "function f(a) { a(); } f(foo);");
  Handle<JSFunction> f = GetFunction("f");
  // There should be one IC.
262 263
  Handle<FeedbackVector> feedback_vector =
      Handle<FeedbackVector>(f->feedback_vector(), isolate);
264
  FeedbackSlot slot(0);
265 266 267 268 269 270
  CallICNexus nexus(feedback_vector, slot);
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());

  CompileRun("f(foo); f(foo);");
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
  CHECK_EQ(3, nexus.ExtractCallCount());
271 272 273 274 275

  // Send the IC megamorphic, but we should still have incrementing counts.
  CompileRun("f(function() { return 12; });");
  CHECK_EQ(GENERIC, nexus.StateFromFeedback());
  CHECK_EQ(4, nexus.ExtractCallCount());
276 277 278 279 280 281 282 283
}

TEST(VectorConstructCounts) {
  if (i::FLAG_always_opt) return;
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();
284

285
  // Make sure function f has a call that uses a type feedback slot.
286 287 288
  CompileRun(
      "function Foo() {}"
      "function f(a) { new a(); } f(Foo);");
289
  Handle<JSFunction> f = GetFunction("f");
290 291
  Handle<FeedbackVector> feedback_vector =
      Handle<FeedbackVector>(f->feedback_vector(), isolate);
292

293
  FeedbackSlot slot(0);
294 295 296
  CallICNexus nexus(feedback_vector, slot);
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());

297
  CHECK(feedback_vector->Get(slot)->IsWeakCell());
298 299

  CompileRun("f(Foo); f(Foo);");
300 301 302 303 304 305 306
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
  CHECK_EQ(3, nexus.ExtractCallCount());

  // Send the IC megamorphic, but we should still have incrementing counts.
  CompileRun("f(function() {});");
  CHECK_EQ(GENERIC, nexus.StateFromFeedback());
  CHECK_EQ(4, nexus.ExtractCallCount());
307
}
308 309

TEST(VectorLoadICStates) {
310
  if (i::FLAG_always_opt) return;
311 312 313 314 315 316 317 318 319
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();

  // Make sure function f has a call that uses a type feedback slot.
  CompileRun(
      "var o = { foo: 3 };"
      "function f(a) { return a.foo; } f(o);");
320
  Handle<JSFunction> f = GetFunction("f");
321
  // There should be one IC.
322 323
  Handle<FeedbackVector> feedback_vector =
      Handle<FeedbackVector>(f->feedback_vector(), isolate);
324
  FeedbackSlot slot(0);
325 326 327 328 329 330
  LoadICNexus nexus(feedback_vector, slot);
  CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());

  CompileRun("f(o)");
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
  // Verify that the monomorphic map is the one we expect.
331 332 333 334
  v8::MaybeLocal<v8::Value> v8_o =
      CcTest::global()->Get(context.local(), v8_str("o"));
  Handle<JSObject> o =
      Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
335 336 337 338 339 340 341 342 343 344 345 346 347
  CHECK_EQ(o->map(), nexus.FindFirstMap());

  // Now go polymorphic.
  CompileRun("f({ blarg: 3, foo: 2 })");
  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());

  CompileRun(
      "delete o.foo;"
      "f(o)");
  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());

  CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
348
  MapHandles maps;
349
  nexus.ExtractMaps(&maps);
350
  CHECK_EQ(4, maps.size());
351 352 353 354

  // Finally driven megamorphic.
  CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
355
  CHECK(!nexus.FindFirstMap());
356

357
  // After a collection, state should not be reset to PREMONOMORPHIC.
358
  CcTest::CollectAllGarbage();
359
  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
360
}
361

362
TEST(VectorLoadGlobalICSlotSharing) {
363
  if (i::FLAG_always_opt) return;
364 365 366 367 368
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();

369 370
  // Function f has 5 LoadGlobalICs: 3 for {o} references outside of "typeof"
  // operator and 2 for {o} references inside "typeof" operator.
371
  CompileRun(
372
      "o = 10;"
373
      "function f() {"
374
      "  var x = o || 10;"
375 376
      "  var y = typeof o;"
      "  return o , typeof o, x , y, o;"
377 378
      "}"
      "f();");
379
  Handle<JSFunction> f = GetFunction("f");
380 381
  // There should be two IC slots for {o} references outside and inside
  // typeof operator respectively.
382 383
  Handle<FeedbackVector> feedback_vector =
      Handle<FeedbackVector>(f->feedback_vector(), isolate);
384
  FeedbackVectorHelper helper(feedback_vector);
385
  CHECK_EQ(2, helper.slot_count());
386 387
  CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
  CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalInsideTypeof);
388 389
  FeedbackSlot slot1 = helper.slot(0);
  FeedbackSlot slot2 = helper.slot(1);
390 391 392 393
  CHECK_EQ(MONOMORPHIC,
           LoadGlobalICNexus(feedback_vector, slot1).StateFromFeedback());
  CHECK_EQ(MONOMORPHIC,
           LoadGlobalICNexus(feedback_vector, slot2).StateFromFeedback());
394 395 396
}


397
TEST(VectorLoadICOnSmi) {
398
  if (i::FLAG_always_opt) return;
399 400 401 402 403 404 405 406 407 408
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();
  Heap* heap = isolate->heap();

  // Make sure function f has a call that uses a type feedback slot.
  CompileRun(
      "var o = { foo: 3 };"
      "function f(a) { return a.foo; } f(o);");
409
  Handle<JSFunction> f = GetFunction("f");
410
  // There should be one IC.
411 412
  Handle<FeedbackVector> feedback_vector =
      Handle<FeedbackVector>(f->feedback_vector(), isolate);
413
  FeedbackSlot slot(0);
414 415 416 417 418 419 420 421 422 423 424 425 426
  LoadICNexus nexus(feedback_vector, slot);
  CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());

  CompileRun("f(34)");
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
  // Verify that the monomorphic map is the one we expect.
  Map* number_map = heap->heap_number_map();
  CHECK_EQ(number_map, nexus.FindFirstMap());

  // Now go polymorphic on o.
  CompileRun("f(o)");
  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());

427
  MapHandles maps;
428
  nexus.ExtractMaps(&maps);
429
  CHECK_EQ(2, maps.size());
430 431

  // One of the maps should be the o map.
432 433 434 435
  v8::MaybeLocal<v8::Value> v8_o =
      CcTest::global()->Get(context.local(), v8_str("o"));
  Handle<JSObject> o =
      Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
436 437
  bool number_map_found = false;
  bool o_map_found = false;
438
  for (Handle<Map> current : maps) {
439 440 441 442 443 444 445 446 447 448
    if (*current == number_map)
      number_map_found = true;
    else if (*current == o->map())
      o_map_found = true;
  }
  CHECK(number_map_found && o_map_found);

  // The degree of polymorphism doesn't change.
  CompileRun("f(100)");
  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
449
  MapHandles maps2;
450
  nexus.ExtractMaps(&maps2);
451
  CHECK_EQ(2, maps2.size());
452
}
453 454 455 456 457 458 459 460 461


TEST(ReferenceContextAllocatesNoSlots) {
  if (i::FLAG_always_opt) return;
  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());
  Isolate* isolate = CcTest::i_isolate();

462 463 464 465 466 467 468 469 470 471 472 473 474
  {
    CompileRun(
        "function testvar(x) {"
        "  y = x;"
        "  y = a;"
        "  return y;"
        "}"
        "a = 3;"
        "testvar({});");

    Handle<JSFunction> f = GetFunction("testvar");

    // There should be two LOAD_ICs, one for a and one for y at the end.
475
    Handle<FeedbackVector> feedback_vector =
476
        handle(f->feedback_vector(), isolate);
477
    FeedbackVectorHelper helper(feedback_vector);
478
    CHECK_EQ(4, helper.slot_count());
479
    CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kStoreGlobalSloppy);
480
    CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
481
    CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreGlobalSloppy);
482
    CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
483
  }
484

485 486 487
  {
    CompileRun(
        "function testprop(x) {"
488
        "  'use strict';"
489 490 491
        "  x.blue = a;"
        "}"
        "testprop({ blue: 3 });");
492

493
    Handle<JSFunction> f = GetFunction("testprop");
494

495
    // There should be one LOAD_IC, for the load of a.
496
    Handle<FeedbackVector> feedback_vector(f->feedback_vector());
497
    FeedbackVectorHelper helper(feedback_vector);
498
    CHECK_EQ(2, helper.slot_count());
499
    CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
500
    CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
501
  }
502

503 504 505 506 507 508 509 510 511 512 513
  {
    CompileRun(
        "function testpropfunc(x) {"
        "  x().blue = a;"
        "  return x().blue;"
        "}"
        "function makeresult() { return { blue: 3 }; }"
        "testpropfunc(makeresult);");

    Handle<JSFunction> f = GetFunction("testpropfunc");

514 515
    // There should be 1 LOAD_GLOBAL_IC to load x (in both cases), 2 CALL_ICs
    // to call x and a LOAD_IC to load blue.
516
    Handle<FeedbackVector> feedback_vector(f->feedback_vector());
517
    FeedbackVectorHelper helper(feedback_vector);
518
    CHECK_EQ(5, helper.slot_count());
519 520
    CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kCall);
    CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
521
    CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedSloppy);
522 523
    CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kCall);
    CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kLoadProperty);
524
  }
525

526 527 528 529 530 531 532 533 534 535
  {
    CompileRun(
        "function testkeyedprop(x) {"
        "  x[0] = a;"
        "  return x[0];"
        "}"
        "testkeyedprop([0, 1, 2]);");

    Handle<JSFunction> f = GetFunction("testkeyedprop");

536 537
    // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
    // KEYED_LOAD_IC for the load of x[0] in the return statement.
538
    Handle<FeedbackVector> feedback_vector(f->feedback_vector());
539
    FeedbackVectorHelper helper(feedback_vector);
540
    CHECK_EQ(3, helper.slot_count());
541 542 543
    CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
    CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedSloppy);
    CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558
  }

  {
    CompileRun(
        "function testkeyedprop(x) {"
        "  'use strict';"
        "  x[0] = a;"
        "  return x[0];"
        "}"
        "testkeyedprop([0, 1, 2]);");

    Handle<JSFunction> f = GetFunction("testkeyedprop");

    // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
    // KEYED_LOAD_IC for the load of x[0] in the return statement.
559
    Handle<FeedbackVector> feedback_vector(f->feedback_vector());
560 561
    FeedbackVectorHelper helper(feedback_vector);
    CHECK_EQ(3, helper.slot_count());
562 563 564
    CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
    CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedStrict);
    CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
565
  }
566

567 568 569
  {
    CompileRun(
        "function testcompound(x) {"
570
        "  'use strict';"
571 572 573 574 575 576 577
        "  x.old = x.young = x.in_between = a;"
        "  return x.old + x.young;"
        "}"
        "testcompound({ old: 3, young: 3, in_between: 3 });");

    Handle<JSFunction> f = GetFunction("testcompound");

578 579
    // There should be 1 LOAD_GLOBAL_IC for load of a and 2 LOAD_ICs, for load
    // of x.old and x.young.
580
    Handle<FeedbackVector> feedback_vector(f->feedback_vector());
581
    FeedbackVectorHelper helper(feedback_vector);
582
    CHECK_EQ(7, helper.slot_count());
583
    CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
584 585 586
    CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
    CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedStrict);
    CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kStoreNamedStrict);
587 588 589
    CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kLoadProperty);
    CHECK_SLOT_KIND(helper, 5, FeedbackSlotKind::kLoadProperty);
    CHECK_SLOT_KIND(helper, 6, FeedbackSlotKind::kBinaryOp);
590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610
  }
}


TEST(VectorStoreICBasic) {
  if (i::FLAG_always_opt) return;

  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());

  CompileRun(
      "function f(a) {"
      "  a.foo = 5;"
      "}"
      "var a = { foo: 3 };"
      "f(a);"
      "f(a);"
      "f(a);");
  Handle<JSFunction> f = GetFunction("f");
  // There should be one IC slot.
611
  Handle<FeedbackVector> feedback_vector(f->feedback_vector());
612 613
  FeedbackVectorHelper helper(feedback_vector);
  CHECK_EQ(1, helper.slot_count());
614
  FeedbackSlot slot(0);
615 616
  StoreICNexus nexus(feedback_vector, slot);
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
617
}
618

619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
TEST(StoreOwnIC) {
  if (i::FLAG_always_opt) return;

  CcTest::InitializeVM();
  LocalContext context;
  v8::HandleScope scope(context->GetIsolate());

  CompileRun(
      "function f(v) {"
      "  return {a: 0, b: v, c: 0};"
      "}"
      "f(1);"
      "f(2);"
      "f(3);");
  Handle<JSFunction> f = GetFunction("f");
  // There should be one IC slot.
  Handle<FeedbackVector> feedback_vector(f->feedback_vector());
  FeedbackVectorHelper helper(feedback_vector);
  CHECK_EQ(2, helper.slot_count());
  CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLiteral);
  CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreOwnNamed);
  StoreOwnICNexus nexus(feedback_vector, helper.slot(1));
  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
}

644
}  // namespace