Line data Source code
1 : // Copyright 2014 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/v8.h"
6 : #include "test/cctest/cctest.h"
7 :
8 : #include "src/api.h"
9 : #include "src/debug/debug.h"
10 : #include "src/execution.h"
11 : #include "src/factory.h"
12 : #include "src/global-handles.h"
13 : #include "src/macro-assembler.h"
14 : #include "src/objects-inl.h"
15 : #include "test/cctest/test-feedback-vector.h"
16 :
17 : namespace v8 {
18 : namespace internal {
19 :
20 : namespace {
21 :
22 : #define CHECK_SLOT_KIND(helper, index, expected_kind) \
23 : CHECK_EQ(expected_kind, helper.vector()->GetKind(helper.slot(index)));
24 :
25 :
26 85 : static Handle<JSFunction> GetFunction(const char* name) {
27 : v8::MaybeLocal<v8::Value> v8_f = CcTest::global()->Get(
28 255 : v8::Isolate::GetCurrent()->GetCurrentContext(), v8_str(name));
29 : Handle<JSFunction> f =
30 : Handle<JSFunction>::cast(v8::Utils::OpenHandle(*v8_f.ToLocalChecked()));
31 85 : return f;
32 : }
33 :
34 :
35 23724 : TEST(VectorStructure) {
36 6 : LocalContext context;
37 12 : v8::HandleScope scope(context->GetIsolate());
38 6 : Isolate* isolate = CcTest::i_isolate();
39 : Factory* factory = isolate->factory();
40 12 : Zone zone(isolate->allocator(), ZONE_NAME);
41 :
42 : Handle<FeedbackVector> vector;
43 :
44 : {
45 : FeedbackVectorSpec one_slot(&zone);
46 : one_slot.AddForInSlot();
47 6 : vector = NewFeedbackVector(isolate, &one_slot);
48 6 : FeedbackVectorHelper helper(vector);
49 6 : CHECK_EQ(1, helper.slot_count());
50 : }
51 :
52 : {
53 : FeedbackVectorSpec one_icslot(&zone);
54 : one_icslot.AddCallICSlot();
55 6 : vector = NewFeedbackVector(isolate, &one_icslot);
56 6 : FeedbackVectorHelper helper(vector);
57 6 : CHECK_EQ(1, helper.slot_count());
58 : }
59 :
60 : {
61 : FeedbackVectorSpec spec(&zone);
62 24 : for (int i = 0; i < 3; i++) {
63 : spec.AddForInSlot();
64 : }
65 30 : for (int i = 0; i < 5; i++) {
66 : spec.AddCallICSlot();
67 : }
68 6 : vector = NewFeedbackVector(isolate, &spec);
69 6 : FeedbackVectorHelper helper(vector);
70 6 : CHECK_EQ(8, helper.slot_count());
71 :
72 : int index = vector->GetIndex(helper.slot(0));
73 :
74 12 : CHECK_EQ(helper.slot(0), vector->ToSlot(index));
75 :
76 : index = vector->GetIndex(helper.slot(3));
77 12 : CHECK_EQ(helper.slot(3), vector->ToSlot(index));
78 :
79 : index = vector->GetIndex(helper.slot(7));
80 6 : CHECK_EQ(3 + 4 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
81 : index);
82 12 : CHECK_EQ(helper.slot(7), vector->ToSlot(index));
83 :
84 6 : CHECK_EQ(3 + 5 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
85 : vector->length());
86 : }
87 :
88 : {
89 : FeedbackVectorSpec spec(&zone);
90 : spec.AddForInSlot();
91 : spec.AddCreateClosureSlot();
92 : spec.AddForInSlot();
93 6 : vector = NewFeedbackVector(isolate, &spec);
94 6 : FeedbackVectorHelper helper(vector);
95 6 : CHECK_EQ(1,
96 : FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCreateClosure));
97 : FeedbackSlot slot = helper.slot(1);
98 : Cell* cell = Cell::cast(vector->Get(slot));
99 6 : CHECK_EQ(cell->value(), *factory->undefined_value());
100 6 : }
101 6 : }
102 :
103 :
104 : // IC slots need an encoding to recognize what is in there.
105 23724 : TEST(VectorICMetadata) {
106 6 : LocalContext context;
107 12 : v8::HandleScope scope(context->GetIsolate());
108 6 : Isolate* isolate = CcTest::i_isolate();
109 12 : Zone zone(isolate->allocator(), ZONE_NAME);
110 :
111 : FeedbackVectorSpec spec(&zone);
112 : // Set metadata.
113 246 : for (int i = 0; i < 40; i++) {
114 240 : switch (i % 4) {
115 : case 0:
116 : spec.AddForInSlot();
117 : break;
118 : case 1:
119 : spec.AddCallICSlot();
120 : break;
121 : case 2:
122 : spec.AddLoadICSlot();
123 : break;
124 : case 3:
125 : spec.AddKeyedLoadICSlot();
126 : break;
127 : }
128 : }
129 :
130 6 : Handle<FeedbackVector> vector = NewFeedbackVector(isolate, &spec);
131 6 : FeedbackVectorHelper helper(vector);
132 6 : CHECK_EQ(40, helper.slot_count());
133 :
134 : // Meanwhile set some feedback values and type feedback values to
135 : // verify the data structure remains intact.
136 : vector->Set(FeedbackSlot(0), *vector);
137 :
138 : // Verify the metadata is correctly set up from the spec.
139 246 : for (int i = 0; i < 40; i++) {
140 240 : FeedbackSlotKind kind = vector->GetKind(helper.slot(i));
141 240 : switch (i % 4) {
142 : case 0:
143 60 : CHECK_EQ(FeedbackSlotKind::kForIn, kind);
144 : break;
145 : case 1:
146 60 : CHECK_EQ(FeedbackSlotKind::kCall, kind);
147 : break;
148 : case 2:
149 60 : CHECK_EQ(FeedbackSlotKind::kLoadProperty, kind);
150 : break;
151 : case 3:
152 60 : CHECK_EQ(FeedbackSlotKind::kLoadKeyed, kind);
153 : break;
154 : }
155 6 : }
156 6 : }
157 :
158 :
159 23724 : TEST(VectorCallICStates) {
160 7 : if (i::FLAG_always_opt) return;
161 5 : CcTest::InitializeVM();
162 5 : LocalContext context;
163 10 : v8::HandleScope scope(context->GetIsolate());
164 : Isolate* isolate = CcTest::i_isolate();
165 : // Make sure function f has a call that uses a type feedback slot.
166 : CompileRun(
167 : "function foo() { return 17; }"
168 : "function f(a) { a(); } f(foo);");
169 5 : Handle<JSFunction> f = GetFunction("f");
170 : // There should be one IC.
171 : Handle<FeedbackVector> feedback_vector =
172 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
173 : FeedbackSlot slot(0);
174 : CallICNexus nexus(feedback_vector, slot);
175 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
176 : // CallIC doesn't return map feedback.
177 5 : CHECK(!nexus.FindFirstMap());
178 :
179 : CompileRun("f(function() { return 16; })");
180 5 : CHECK_EQ(GENERIC, nexus.StateFromFeedback());
181 :
182 : // After a collection, state should remain GENERIC.
183 5 : CcTest::CollectAllGarbage();
184 10 : CHECK_EQ(GENERIC, nexus.StateFromFeedback());
185 : }
186 :
187 23724 : TEST(VectorCallFeedback) {
188 7 : if (i::FLAG_always_opt) return;
189 5 : CcTest::InitializeVM();
190 5 : LocalContext context;
191 10 : v8::HandleScope scope(context->GetIsolate());
192 : Isolate* isolate = CcTest::i_isolate();
193 : // Make sure function f has a call that uses a type feedback slot.
194 : CompileRun(
195 : "function foo() { return 17; }"
196 : "function f(a) { a(); } f(foo);");
197 5 : Handle<JSFunction> f = GetFunction("f");
198 5 : Handle<JSFunction> foo = GetFunction("foo");
199 : // There should be one IC.
200 : Handle<FeedbackVector> feedback_vector =
201 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
202 : FeedbackSlot slot(0);
203 : CallICNexus nexus(feedback_vector, slot);
204 :
205 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
206 10 : CHECK(nexus.GetFeedback()->IsWeakCell());
207 10 : CHECK(*foo == WeakCell::cast(nexus.GetFeedback())->value());
208 :
209 5 : CcTest::CollectAllGarbage();
210 : // It should stay monomorphic even after a GC.
211 10 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
212 : }
213 :
214 23724 : TEST(VectorCallFeedbackForArray) {
215 7 : if (i::FLAG_always_opt) return;
216 5 : CcTest::InitializeVM();
217 5 : LocalContext context;
218 10 : v8::HandleScope scope(context->GetIsolate());
219 : Isolate* isolate = CcTest::i_isolate();
220 : // Make sure function f has a call that uses a type feedback slot.
221 : CompileRun("function f(a) { a(); } f(Array);");
222 5 : Handle<JSFunction> f = GetFunction("f");
223 : // There should be one IC.
224 : Handle<FeedbackVector> feedback_vector =
225 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
226 : FeedbackSlot slot(0);
227 : CallICNexus nexus(feedback_vector, slot);
228 :
229 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
230 10 : CHECK(nexus.GetFeedback()->IsWeakCell());
231 15 : CHECK(*isolate->array_function() ==
232 : WeakCell::cast(nexus.GetFeedback())->value());
233 :
234 5 : CcTest::CollectAllGarbage();
235 : // It should stay monomorphic even after a GC.
236 10 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
237 : }
238 :
239 23724 : TEST(VectorCallCounts) {
240 7 : if (i::FLAG_always_opt) return;
241 5 : CcTest::InitializeVM();
242 5 : LocalContext context;
243 10 : v8::HandleScope scope(context->GetIsolate());
244 : Isolate* isolate = CcTest::i_isolate();
245 :
246 : // Make sure function f has a call that uses a type feedback slot.
247 : CompileRun(
248 : "function foo() { return 17; }"
249 : "function f(a) { a(); } f(foo);");
250 5 : Handle<JSFunction> f = GetFunction("f");
251 : // There should be one IC.
252 : Handle<FeedbackVector> feedback_vector =
253 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
254 : FeedbackSlot slot(0);
255 : CallICNexus nexus(feedback_vector, slot);
256 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
257 :
258 : CompileRun("f(foo); f(foo);");
259 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
260 5 : CHECK_EQ(3, nexus.ExtractCallCount());
261 :
262 : // Send the IC megamorphic, but we should still have incrementing counts.
263 : CompileRun("f(function() { return 12; });");
264 5 : CHECK_EQ(GENERIC, nexus.StateFromFeedback());
265 10 : CHECK_EQ(4, nexus.ExtractCallCount());
266 : }
267 :
268 23724 : TEST(VectorConstructCounts) {
269 7 : if (i::FLAG_always_opt) return;
270 5 : CcTest::InitializeVM();
271 5 : LocalContext context;
272 10 : v8::HandleScope scope(context->GetIsolate());
273 : Isolate* isolate = CcTest::i_isolate();
274 :
275 : // Make sure function f has a call that uses a type feedback slot.
276 : CompileRun(
277 : "function Foo() {}"
278 : "function f(a) { new a(); } f(Foo);");
279 5 : Handle<JSFunction> f = GetFunction("f");
280 : Handle<FeedbackVector> feedback_vector =
281 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
282 :
283 : FeedbackSlot slot(0);
284 : CallICNexus nexus(feedback_vector, slot);
285 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
286 :
287 5 : CHECK(feedback_vector->Get(slot)->IsWeakCell());
288 :
289 : CompileRun("f(Foo); f(Foo);");
290 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
291 5 : CHECK_EQ(3, nexus.ExtractCallCount());
292 :
293 : // Send the IC megamorphic, but we should still have incrementing counts.
294 : CompileRun("f(function() {});");
295 5 : CHECK_EQ(GENERIC, nexus.StateFromFeedback());
296 10 : CHECK_EQ(4, nexus.ExtractCallCount());
297 : }
298 :
299 23724 : TEST(VectorLoadICStates) {
300 7 : if (i::FLAG_always_opt) return;
301 5 : CcTest::InitializeVM();
302 5 : LocalContext context;
303 10 : v8::HandleScope scope(context->GetIsolate());
304 : Isolate* isolate = CcTest::i_isolate();
305 :
306 : // Make sure function f has a call that uses a type feedback slot.
307 : CompileRun(
308 : "var o = { foo: 3 };"
309 : "function f(a) { return a.foo; } f(o);");
310 5 : Handle<JSFunction> f = GetFunction("f");
311 : // There should be one IC.
312 : Handle<FeedbackVector> feedback_vector =
313 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
314 : FeedbackSlot slot(0);
315 : LoadICNexus nexus(feedback_vector, slot);
316 5 : CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
317 :
318 : CompileRun("f(o)");
319 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
320 : // Verify that the monomorphic map is the one we expect.
321 : v8::MaybeLocal<v8::Value> v8_o =
322 15 : CcTest::global()->Get(context.local(), v8_str("o"));
323 : Handle<JSObject> o =
324 : Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
325 10 : CHECK_EQ(o->map(), nexus.FindFirstMap());
326 :
327 : // Now go polymorphic.
328 : CompileRun("f({ blarg: 3, foo: 2 })");
329 5 : CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
330 :
331 : CompileRun(
332 : "delete o.foo;"
333 : "f(o)");
334 5 : CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
335 :
336 : CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
337 5 : CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
338 : MapHandles maps;
339 5 : nexus.ExtractMaps(&maps);
340 10 : CHECK_EQ(4, maps.size());
341 :
342 : // Finally driven megamorphic.
343 : CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
344 5 : CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
345 5 : CHECK(!nexus.FindFirstMap());
346 :
347 : // After a collection, state should not be reset to PREMONOMORPHIC.
348 5 : CcTest::CollectAllGarbage();
349 10 : CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
350 : }
351 :
352 23724 : TEST(VectorLoadGlobalICSlotSharing) {
353 7 : if (i::FLAG_always_opt) return;
354 5 : CcTest::InitializeVM();
355 5 : LocalContext context;
356 10 : v8::HandleScope scope(context->GetIsolate());
357 : Isolate* isolate = CcTest::i_isolate();
358 :
359 : // Function f has 5 LoadGlobalICs: 3 for {o} references outside of "typeof"
360 : // operator and 2 for {o} references inside "typeof" operator.
361 : CompileRun(
362 : "o = 10;"
363 : "function f() {"
364 : " var x = o || 10;"
365 : " var y = typeof o;"
366 : " return o , typeof o, x , y, o;"
367 : "}"
368 : "f();");
369 5 : Handle<JSFunction> f = GetFunction("f");
370 : // There should be two IC slots for {o} references outside and inside
371 : // typeof operator respectively.
372 : Handle<FeedbackVector> feedback_vector =
373 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
374 5 : FeedbackVectorHelper helper(feedback_vector);
375 5 : CHECK_EQ(2, helper.slot_count());
376 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
377 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalInsideTypeof);
378 : FeedbackSlot slot1 = helper.slot(0);
379 : FeedbackSlot slot2 = helper.slot(1);
380 10 : CHECK_EQ(MONOMORPHIC,
381 : LoadGlobalICNexus(feedback_vector, slot1).StateFromFeedback());
382 10 : CHECK_EQ(MONOMORPHIC,
383 5 : LoadGlobalICNexus(feedback_vector, slot2).StateFromFeedback());
384 : }
385 :
386 :
387 23724 : TEST(VectorLoadICOnSmi) {
388 7 : if (i::FLAG_always_opt) return;
389 5 : CcTest::InitializeVM();
390 5 : LocalContext context;
391 10 : v8::HandleScope scope(context->GetIsolate());
392 : Isolate* isolate = CcTest::i_isolate();
393 5 : Heap* heap = isolate->heap();
394 :
395 : // Make sure function f has a call that uses a type feedback slot.
396 : CompileRun(
397 : "var o = { foo: 3 };"
398 : "function f(a) { return a.foo; } f(o);");
399 5 : Handle<JSFunction> f = GetFunction("f");
400 : // There should be one IC.
401 : Handle<FeedbackVector> feedback_vector =
402 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
403 : FeedbackSlot slot(0);
404 : LoadICNexus nexus(feedback_vector, slot);
405 5 : CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
406 :
407 : CompileRun("f(34)");
408 5 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
409 : // Verify that the monomorphic map is the one we expect.
410 : Map* number_map = heap->heap_number_map();
411 5 : CHECK_EQ(number_map, nexus.FindFirstMap());
412 :
413 : // Now go polymorphic on o.
414 : CompileRun("f(o)");
415 5 : CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
416 :
417 : MapHandles maps;
418 5 : nexus.ExtractMaps(&maps);
419 10 : CHECK_EQ(2, maps.size());
420 :
421 : // One of the maps should be the o map.
422 : v8::MaybeLocal<v8::Value> v8_o =
423 15 : CcTest::global()->Get(context.local(), v8_str("o"));
424 : Handle<JSObject> o =
425 : Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
426 : bool number_map_found = false;
427 : bool o_map_found = false;
428 20 : for (Handle<Map> current : maps) {
429 10 : if (*current == number_map)
430 : number_map_found = true;
431 5 : else if (*current == o->map())
432 : o_map_found = true;
433 : }
434 5 : CHECK(number_map_found && o_map_found);
435 :
436 : // The degree of polymorphism doesn't change.
437 : CompileRun("f(100)");
438 5 : CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
439 : MapHandles maps2;
440 5 : nexus.ExtractMaps(&maps2);
441 15 : CHECK_EQ(2, maps2.size());
442 : }
443 :
444 :
445 23724 : TEST(ReferenceContextAllocatesNoSlots) {
446 7 : if (i::FLAG_always_opt) return;
447 5 : CcTest::InitializeVM();
448 5 : LocalContext context;
449 10 : v8::HandleScope scope(context->GetIsolate());
450 : Isolate* isolate = CcTest::i_isolate();
451 :
452 : {
453 : CompileRun(
454 : "function testvar(x) {"
455 : " y = x;"
456 : " y = a;"
457 : " return y;"
458 : "}"
459 : "a = 3;"
460 : "testvar({});");
461 :
462 5 : Handle<JSFunction> f = GetFunction("testvar");
463 :
464 : // There should be two LOAD_ICs, one for a and one for y at the end.
465 : Handle<FeedbackVector> feedback_vector =
466 5 : handle(f->feedback_vector(), isolate);
467 5 : FeedbackVectorHelper helper(feedback_vector);
468 5 : CHECK_EQ(4, helper.slot_count());
469 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kStoreGlobalSloppy);
470 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
471 5 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreGlobalSloppy);
472 5 : CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
473 : }
474 :
475 : {
476 : CompileRun(
477 : "function testprop(x) {"
478 : " 'use strict';"
479 : " x.blue = a;"
480 : "}"
481 : "testprop({ blue: 3 });");
482 :
483 5 : Handle<JSFunction> f = GetFunction("testprop");
484 :
485 : // There should be one LOAD_IC, for the load of a.
486 : Handle<FeedbackVector> feedback_vector(f->feedback_vector());
487 5 : FeedbackVectorHelper helper(feedback_vector);
488 5 : CHECK_EQ(2, helper.slot_count());
489 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
490 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
491 : }
492 :
493 : {
494 : CompileRun(
495 : "function testpropfunc(x) {"
496 : " x().blue = a;"
497 : " return x().blue;"
498 : "}"
499 : "function makeresult() { return { blue: 3 }; }"
500 : "testpropfunc(makeresult);");
501 :
502 5 : Handle<JSFunction> f = GetFunction("testpropfunc");
503 :
504 : // There should be 1 LOAD_GLOBAL_IC to load x (in both cases), 2 CALL_ICs
505 : // to call x and a LOAD_IC to load blue.
506 : Handle<FeedbackVector> feedback_vector(f->feedback_vector());
507 5 : FeedbackVectorHelper helper(feedback_vector);
508 5 : CHECK_EQ(5, helper.slot_count());
509 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kCall);
510 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
511 5 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedSloppy);
512 5 : CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kCall);
513 5 : CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kLoadProperty);
514 : }
515 :
516 : {
517 : CompileRun(
518 : "function testkeyedprop(x) {"
519 : " x[0] = a;"
520 : " return x[0];"
521 : "}"
522 : "testkeyedprop([0, 1, 2]);");
523 :
524 5 : Handle<JSFunction> f = GetFunction("testkeyedprop");
525 :
526 : // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
527 : // KEYED_LOAD_IC for the load of x[0] in the return statement.
528 : Handle<FeedbackVector> feedback_vector(f->feedback_vector());
529 5 : FeedbackVectorHelper helper(feedback_vector);
530 5 : CHECK_EQ(3, helper.slot_count());
531 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
532 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedSloppy);
533 5 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
534 : }
535 :
536 : {
537 : CompileRun(
538 : "function testkeyedprop(x) {"
539 : " 'use strict';"
540 : " x[0] = a;"
541 : " return x[0];"
542 : "}"
543 : "testkeyedprop([0, 1, 2]);");
544 :
545 5 : Handle<JSFunction> f = GetFunction("testkeyedprop");
546 :
547 : // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
548 : // KEYED_LOAD_IC for the load of x[0] in the return statement.
549 : Handle<FeedbackVector> feedback_vector(f->feedback_vector());
550 5 : FeedbackVectorHelper helper(feedback_vector);
551 5 : CHECK_EQ(3, helper.slot_count());
552 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
553 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedStrict);
554 5 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
555 : }
556 :
557 : {
558 : CompileRun(
559 : "function testcompound(x) {"
560 : " 'use strict';"
561 : " x.old = x.young = x.in_between = a;"
562 : " return x.old + x.young;"
563 : "}"
564 : "testcompound({ old: 3, young: 3, in_between: 3 });");
565 :
566 5 : Handle<JSFunction> f = GetFunction("testcompound");
567 :
568 : // There should be 1 LOAD_GLOBAL_IC for load of a and 2 LOAD_ICs, for load
569 : // of x.old and x.young.
570 : Handle<FeedbackVector> feedback_vector(f->feedback_vector());
571 5 : FeedbackVectorHelper helper(feedback_vector);
572 5 : CHECK_EQ(7, helper.slot_count());
573 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
574 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
575 5 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedStrict);
576 5 : CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kStoreNamedStrict);
577 5 : CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kBinaryOp);
578 5 : CHECK_SLOT_KIND(helper, 5, FeedbackSlotKind::kLoadProperty);
579 5 : CHECK_SLOT_KIND(helper, 6, FeedbackSlotKind::kLoadProperty);
580 5 : }
581 : }
582 :
583 :
584 23724 : TEST(VectorStoreICBasic) {
585 7 : if (i::FLAG_always_opt) return;
586 :
587 5 : CcTest::InitializeVM();
588 5 : LocalContext context;
589 10 : v8::HandleScope scope(context->GetIsolate());
590 :
591 : CompileRun(
592 : "function f(a) {"
593 : " a.foo = 5;"
594 : "}"
595 : "var a = { foo: 3 };"
596 : "f(a);"
597 : "f(a);"
598 : "f(a);");
599 5 : Handle<JSFunction> f = GetFunction("f");
600 : // There should be one IC slot.
601 : Handle<FeedbackVector> feedback_vector(f->feedback_vector());
602 5 : FeedbackVectorHelper helper(feedback_vector);
603 5 : CHECK_EQ(1, helper.slot_count());
604 : FeedbackSlot slot(0);
605 : StoreICNexus nexus(feedback_vector, slot);
606 10 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
607 : }
608 :
609 23724 : TEST(StoreOwnIC) {
610 7 : if (i::FLAG_always_opt) return;
611 :
612 5 : CcTest::InitializeVM();
613 5 : LocalContext context;
614 10 : v8::HandleScope scope(context->GetIsolate());
615 :
616 : CompileRun(
617 : "function f(v) {"
618 : " return {a: 0, b: v, c: 0};"
619 : "}"
620 : "f(1);"
621 : "f(2);"
622 : "f(3);");
623 5 : Handle<JSFunction> f = GetFunction("f");
624 : // There should be one IC slot.
625 : Handle<FeedbackVector> feedback_vector(f->feedback_vector());
626 5 : FeedbackVectorHelper helper(feedback_vector);
627 5 : CHECK_EQ(2, helper.slot_count());
628 5 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLiteral);
629 5 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreOwnNamed);
630 : StoreOwnICNexus nexus(feedback_vector, helper.slot(1));
631 10 : CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
632 : }
633 :
634 : } // namespace
635 :
636 : } // namespace internal
637 71154 : } // namespace v8
|