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-inl.h"
9 : #include "src/debug/debug.h"
10 : #include "src/execution.h"
11 : #include "src/global-handles.h"
12 : #include "src/heap/factory.h"
13 : #include "src/macro-assembler.h"
14 : #include "src/objects-inl.h"
15 : #include "src/objects/feedback-cell-inl.h"
16 : #include "test/cctest/test-feedback-vector.h"
17 :
18 : namespace v8 {
19 : namespace internal {
20 :
21 : namespace {
22 :
23 : #define CHECK_SLOT_KIND(helper, index, expected_kind) \
24 : CHECK_EQ(expected_kind, helper.vector()->GetKind(helper.slot(index)));
25 :
26 :
27 72 : static Handle<JSFunction> GetFunction(const char* name) {
28 144 : v8::MaybeLocal<v8::Value> v8_f = CcTest::global()->Get(
29 288 : v8::Isolate::GetCurrent()->GetCurrentContext(), v8_str(name));
30 : Handle<JSFunction> f =
31 : Handle<JSFunction>::cast(v8::Utils::OpenHandle(*v8_f.ToLocalChecked()));
32 72 : return f;
33 : }
34 :
35 :
36 26644 : TEST(VectorStructure) {
37 5 : LocalContext context;
38 10 : v8::HandleScope scope(context->GetIsolate());
39 : Isolate* isolate = CcTest::i_isolate();
40 : Factory* factory = isolate->factory();
41 10 : Zone zone(isolate->allocator(), ZONE_NAME);
42 :
43 : Handle<FeedbackVector> vector;
44 :
45 : {
46 : FeedbackVectorSpec one_slot(&zone);
47 : one_slot.AddForInSlot();
48 5 : vector = NewFeedbackVector(isolate, &one_slot);
49 5 : FeedbackVectorHelper helper(vector);
50 5 : CHECK_EQ(1, helper.slot_count());
51 : }
52 :
53 : {
54 : FeedbackVectorSpec one_icslot(&zone);
55 : one_icslot.AddCallICSlot();
56 5 : vector = NewFeedbackVector(isolate, &one_icslot);
57 5 : FeedbackVectorHelper helper(vector);
58 5 : CHECK_EQ(1, helper.slot_count());
59 : }
60 :
61 : {
62 : FeedbackVectorSpec spec(&zone);
63 35 : for (int i = 0; i < 3; i++) {
64 : spec.AddForInSlot();
65 : }
66 55 : for (int i = 0; i < 5; i++) {
67 : spec.AddCallICSlot();
68 : }
69 5 : vector = NewFeedbackVector(isolate, &spec);
70 5 : FeedbackVectorHelper helper(vector);
71 5 : CHECK_EQ(8, helper.slot_count());
72 :
73 : int index = vector->GetIndex(helper.slot(0));
74 :
75 : CHECK_EQ(helper.slot(0), vector->ToSlot(index));
76 :
77 : index = vector->GetIndex(helper.slot(3));
78 : CHECK_EQ(helper.slot(3), vector->ToSlot(index));
79 :
80 : index = vector->GetIndex(helper.slot(7));
81 5 : CHECK_EQ(3 + 4 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
82 : index);
83 : CHECK_EQ(helper.slot(7), vector->ToSlot(index));
84 :
85 5 : CHECK_EQ(3 + 5 * FeedbackMetadata::GetSlotSize(FeedbackSlotKind::kCall),
86 : vector->length());
87 : }
88 :
89 : {
90 : FeedbackVectorSpec spec(&zone);
91 : spec.AddForInSlot();
92 : spec.AddFeedbackCellForCreateClosure();
93 : spec.AddForInSlot();
94 5 : vector = NewFeedbackVector(isolate, &spec);
95 5 : FeedbackVectorHelper helper(vector);
96 : FeedbackCell cell = *vector->GetClosureFeedbackCell(0);
97 5 : CHECK_EQ(cell->value(), *factory->undefined_value());
98 : }
99 5 : }
100 :
101 :
102 : // IC slots need an encoding to recognize what is in there.
103 26644 : TEST(VectorICMetadata) {
104 5 : LocalContext context;
105 10 : v8::HandleScope scope(context->GetIsolate());
106 : Isolate* isolate = CcTest::i_isolate();
107 10 : Zone zone(isolate->allocator(), ZONE_NAME);
108 :
109 : FeedbackVectorSpec spec(&zone);
110 : // Set metadata.
111 405 : for (int i = 0; i < 40; i++) {
112 200 : switch (i % 4) {
113 : case 0:
114 : spec.AddForInSlot();
115 : break;
116 : case 1:
117 : spec.AddCallICSlot();
118 : break;
119 : case 2:
120 : spec.AddLoadICSlot();
121 : break;
122 : case 3:
123 : spec.AddKeyedLoadICSlot();
124 : break;
125 : }
126 : }
127 :
128 5 : Handle<FeedbackVector> vector = NewFeedbackVector(isolate, &spec);
129 5 : FeedbackVectorHelper helper(vector);
130 5 : CHECK_EQ(40, helper.slot_count());
131 :
132 : // Meanwhile set some feedback values and type feedback values to
133 : // verify the data structure remains intact.
134 10 : vector->Set(FeedbackSlot(0), MaybeObject::FromObject(*vector));
135 :
136 : // Verify the metadata is correctly set up from the spec.
137 405 : for (int i = 0; i < 40; i++) {
138 200 : FeedbackSlotKind kind = vector->GetKind(helper.slot(i));
139 200 : switch (i % 4) {
140 : case 0:
141 50 : CHECK_EQ(FeedbackSlotKind::kForIn, kind);
142 : break;
143 : case 1:
144 50 : CHECK_EQ(FeedbackSlotKind::kCall, kind);
145 : break;
146 : case 2:
147 50 : CHECK_EQ(FeedbackSlotKind::kLoadProperty, kind);
148 : break;
149 : case 3:
150 50 : CHECK_EQ(FeedbackSlotKind::kLoadKeyed, kind);
151 : break;
152 : }
153 : }
154 5 : }
155 :
156 :
157 26644 : TEST(VectorCallICStates) {
158 6 : if (!i::FLAG_use_ic) return;
159 5 : if (i::FLAG_always_opt) return;
160 4 : FLAG_allow_natives_syntax = true;
161 :
162 4 : CcTest::InitializeVM();
163 4 : LocalContext context;
164 8 : v8::HandleScope scope(context->GetIsolate());
165 : Isolate* isolate = CcTest::i_isolate();
166 : // Make sure function f has a call that uses a type feedback slot.
167 : CompileRun(
168 : "function foo() { return 17; };"
169 : "%EnsureFeedbackVectorForFunction(f);"
170 : "function f(a) { a(); } f(foo);");
171 4 : Handle<JSFunction> f = GetFunction("f");
172 : // There should be one IC.
173 : Handle<FeedbackVector> feedback_vector =
174 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
175 : FeedbackSlot slot(0);
176 : FeedbackNexus nexus(feedback_vector, slot);
177 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
178 :
179 : CompileRun("f(function() { return 16; })");
180 4 : CHECK_EQ(GENERIC, nexus.ic_state());
181 :
182 : // After a collection, state should remain GENERIC.
183 4 : CcTest::CollectAllGarbage();
184 4 : CHECK_EQ(GENERIC, nexus.ic_state());
185 : }
186 :
187 26644 : TEST(VectorCallFeedback) {
188 6 : if (!i::FLAG_use_ic) return;
189 5 : if (i::FLAG_always_opt) return;
190 4 : FLAG_allow_natives_syntax = true;
191 :
192 4 : CcTest::InitializeVM();
193 4 : LocalContext context;
194 8 : v8::HandleScope scope(context->GetIsolate());
195 : Isolate* isolate = CcTest::i_isolate();
196 : // Make sure function f has a call that uses a type feedback slot.
197 : CompileRun(
198 : "function foo() { return 17; }"
199 : "%EnsureFeedbackVectorForFunction(f);"
200 : "function f(a) { a(); } f(foo);");
201 4 : Handle<JSFunction> f = GetFunction("f");
202 4 : Handle<JSFunction> foo = GetFunction("foo");
203 : // There should be one IC.
204 : Handle<FeedbackVector> feedback_vector =
205 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
206 : FeedbackSlot slot(0);
207 : FeedbackNexus nexus(feedback_vector, slot);
208 :
209 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
210 : HeapObject heap_object;
211 8 : CHECK(nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object));
212 4 : CHECK_EQ(*foo, heap_object);
213 :
214 4 : CcTest::CollectAllGarbage();
215 : // It should stay monomorphic even after a GC.
216 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
217 : }
218 :
219 26644 : TEST(VectorCallFeedbackForArray) {
220 6 : if (!i::FLAG_use_ic) return;
221 5 : if (i::FLAG_always_opt) return;
222 4 : FLAG_allow_natives_syntax = true;
223 :
224 4 : CcTest::InitializeVM();
225 4 : LocalContext context;
226 8 : v8::HandleScope scope(context->GetIsolate());
227 : Isolate* isolate = CcTest::i_isolate();
228 : // Make sure function f has a call that uses a type feedback slot.
229 : CompileRun(
230 : "function f(a) { a(); };"
231 : "%EnsureFeedbackVectorForFunction(f);"
232 : "f(Array);");
233 4 : Handle<JSFunction> f = GetFunction("f");
234 : // There should be one IC.
235 : Handle<FeedbackVector> feedback_vector =
236 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
237 : FeedbackSlot slot(0);
238 : FeedbackNexus nexus(feedback_vector, slot);
239 :
240 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
241 : HeapObject heap_object;
242 8 : CHECK(nexus.GetFeedback()->GetHeapObjectIfWeak(&heap_object));
243 8 : CHECK_EQ(*isolate->array_function(), heap_object);
244 :
245 4 : CcTest::CollectAllGarbage();
246 : // It should stay monomorphic even after a GC.
247 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
248 : }
249 :
250 24 : size_t GetFeedbackVectorLength(Isolate* isolate, const char* src,
251 : bool with_oneshot_opt) {
252 24 : i::FLAG_enable_one_shot_optimization = with_oneshot_opt;
253 : i::Handle<i::Object> i_object = v8::Utils::OpenHandle(*CompileRun(src));
254 : i::Handle<i::JSFunction> f = i::Handle<i::JSFunction>::cast(i_object);
255 : Handle<FeedbackVector> feedback_vector =
256 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
257 24 : return feedback_vector->length();
258 : }
259 :
260 26644 : TEST(OneShotCallICSlotCount) {
261 6 : if (!i::FLAG_use_ic) return;
262 5 : if (i::FLAG_always_opt) return;
263 4 : if (i::FLAG_lazy_feedback_allocation) return;
264 4 : FLAG_allow_natives_syntax = true;
265 :
266 4 : CcTest::InitializeVM();
267 4 : LocalContext context;
268 8 : v8::HandleScope scope(context->GetIsolate());
269 : Isolate* isolate = CcTest::i_isolate();
270 4 : i::FLAG_compilation_cache = false;
271 :
272 : const char* no_call = R"(
273 : function f1() {};
274 : function f2() {};
275 : (function() {
276 : return arguments.callee;
277 : })();
278 : )";
279 : // len = 2 * 1 ldaNamed property
280 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, false), 2);
281 : // no slots of named property loads/stores in one shot
282 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, no_call, true), 0);
283 :
284 : const char* single_call = R"(
285 : function f1() {};
286 : function f2() {};
287 : (function() {
288 : f1();
289 : return arguments.callee;
290 : })();
291 : )";
292 : // len = 2 * 1 ldaNamed Slot + 2 * 1 CachedGlobalSlot + 2 * 1 CallICSlot
293 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, false), 6);
294 : // len = 2 * 1 CachedGlobalSlot
295 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, single_call, true), 2);
296 :
297 : const char* multiple_calls = R"(
298 : function f1() {};
299 : function f2() {};
300 : (function() {
301 : f1();
302 : f2();
303 : f1();
304 : f2();
305 : return arguments.callee;
306 : })();
307 : )";
308 : // len = 2 * 1 ldaNamedSlot + 2 * 2 CachedGlobalSlot (one for each unique
309 : // function) + 2 * 4 CallICSlot (one for each function call)
310 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, false), 14);
311 : // CachedGlobalSlot (one for each unique function)
312 : // len = 2 * 2 CachedGlobalSlot (one for each unique function)
313 8 : CHECK_EQ(GetFeedbackVectorLength(isolate, multiple_calls, true), 4);
314 : }
315 :
316 26644 : TEST(VectorCallCounts) {
317 6 : if (!i::FLAG_use_ic) return;
318 5 : if (i::FLAG_always_opt) return;
319 4 : FLAG_allow_natives_syntax = true;
320 :
321 4 : CcTest::InitializeVM();
322 4 : LocalContext context;
323 8 : v8::HandleScope scope(context->GetIsolate());
324 : Isolate* isolate = CcTest::i_isolate();
325 :
326 : // Make sure function f has a call that uses a type feedback slot.
327 : CompileRun(
328 : "function foo() { return 17; }"
329 : "%EnsureFeedbackVectorForFunction(f);"
330 : "function f(a) { a(); } f(foo);");
331 4 : Handle<JSFunction> f = GetFunction("f");
332 : // There should be one IC.
333 : Handle<FeedbackVector> feedback_vector =
334 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
335 : FeedbackSlot slot(0);
336 : FeedbackNexus nexus(feedback_vector, slot);
337 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
338 :
339 : CompileRun("f(foo); f(foo);");
340 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
341 4 : CHECK_EQ(3, nexus.GetCallCount());
342 :
343 : // Send the IC megamorphic, but we should still have incrementing counts.
344 : CompileRun("f(function() { return 12; });");
345 4 : CHECK_EQ(GENERIC, nexus.ic_state());
346 4 : CHECK_EQ(4, nexus.GetCallCount());
347 : }
348 :
349 26644 : TEST(VectorConstructCounts) {
350 6 : if (!i::FLAG_use_ic) return;
351 5 : if (i::FLAG_always_opt) return;
352 4 : FLAG_allow_natives_syntax = true;
353 :
354 4 : CcTest::InitializeVM();
355 4 : LocalContext context;
356 8 : v8::HandleScope scope(context->GetIsolate());
357 : Isolate* isolate = CcTest::i_isolate();
358 :
359 : // Make sure function f has a call that uses a type feedback slot.
360 : CompileRun(
361 : "function Foo() {}"
362 : "%EnsureFeedbackVectorForFunction(f);"
363 : "function f(a) { new a(); } f(Foo);");
364 4 : Handle<JSFunction> f = GetFunction("f");
365 : Handle<FeedbackVector> feedback_vector =
366 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
367 :
368 : FeedbackSlot slot(0);
369 : FeedbackNexus nexus(feedback_vector, slot);
370 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
371 :
372 4 : CHECK(feedback_vector->Get(slot)->IsWeak());
373 :
374 : CompileRun("f(Foo); f(Foo);");
375 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
376 4 : CHECK_EQ(3, nexus.GetCallCount());
377 :
378 : // Send the IC megamorphic, but we should still have incrementing counts.
379 : CompileRun("f(function() {});");
380 4 : CHECK_EQ(GENERIC, nexus.ic_state());
381 4 : CHECK_EQ(4, nexus.GetCallCount());
382 : }
383 :
384 26644 : TEST(VectorSpeculationMode) {
385 6 : if (!i::FLAG_use_ic) return;
386 5 : if (i::FLAG_always_opt) return;
387 4 : FLAG_allow_natives_syntax = true;
388 :
389 4 : CcTest::InitializeVM();
390 4 : LocalContext context;
391 8 : v8::HandleScope scope(context->GetIsolate());
392 : Isolate* isolate = CcTest::i_isolate();
393 :
394 : // Make sure function f has a call that uses a type feedback slot.
395 : CompileRun(
396 : "function Foo() {}"
397 : "%EnsureFeedbackVectorForFunction(f);"
398 : "function f(a) { new a(); } f(Foo);");
399 4 : Handle<JSFunction> f = GetFunction("f");
400 : Handle<FeedbackVector> feedback_vector =
401 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
402 :
403 : FeedbackSlot slot(0);
404 : FeedbackNexus nexus(feedback_vector, slot);
405 4 : CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
406 :
407 : CompileRun("f(Foo); f(Foo);");
408 4 : CHECK_EQ(3, nexus.GetCallCount());
409 4 : CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
410 :
411 4 : nexus.SetSpeculationMode(SpeculationMode::kDisallowSpeculation);
412 4 : CHECK_EQ(SpeculationMode::kDisallowSpeculation, nexus.GetSpeculationMode());
413 4 : CHECK_EQ(3, nexus.GetCallCount());
414 :
415 4 : nexus.SetSpeculationMode(SpeculationMode::kAllowSpeculation);
416 4 : CHECK_EQ(SpeculationMode::kAllowSpeculation, nexus.GetSpeculationMode());
417 4 : CHECK_EQ(3, nexus.GetCallCount());
418 : }
419 :
420 26644 : TEST(VectorLoadICStates) {
421 6 : if (!i::FLAG_use_ic) return;
422 5 : if (i::FLAG_always_opt) return;
423 4 : FLAG_allow_natives_syntax = true;
424 :
425 4 : CcTest::InitializeVM();
426 4 : LocalContext context;
427 8 : v8::HandleScope scope(context->GetIsolate());
428 : Isolate* isolate = CcTest::i_isolate();
429 :
430 : // Make sure function f has a call that uses a type feedback slot.
431 : CompileRun(
432 : "var o = { foo: 3 };"
433 : "%EnsureFeedbackVectorForFunction(f);"
434 : "function f(a) { return a.foo; } f(o);");
435 4 : Handle<JSFunction> f = GetFunction("f");
436 : // There should be one IC.
437 : Handle<FeedbackVector> feedback_vector =
438 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
439 : FeedbackSlot slot(0);
440 : FeedbackNexus nexus(feedback_vector, slot);
441 4 : CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
442 :
443 : CompileRun("f(o)");
444 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
445 : // Verify that the monomorphic map is the one we expect.
446 : v8::MaybeLocal<v8::Value> v8_o =
447 12 : CcTest::global()->Get(context.local(), v8_str("o"));
448 : Handle<JSObject> o =
449 : Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
450 8 : CHECK_EQ(o->map(), nexus.GetFirstMap());
451 :
452 : // Now go polymorphic.
453 : CompileRun("f({ blarg: 3, foo: 2 })");
454 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
455 :
456 : CompileRun(
457 : "delete o.foo;"
458 : "f(o)");
459 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
460 :
461 : CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
462 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
463 : MapHandles maps;
464 4 : nexus.ExtractMaps(&maps);
465 4 : CHECK_EQ(4, maps.size());
466 :
467 : // Finally driven megamorphic.
468 : CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
469 4 : CHECK_EQ(MEGAMORPHIC, nexus.ic_state());
470 8 : CHECK(nexus.GetFirstMap().is_null());
471 :
472 : // After a collection, state should not be reset to PREMONOMORPHIC.
473 4 : CcTest::CollectAllGarbage();
474 4 : CHECK_EQ(MEGAMORPHIC, nexus.ic_state());
475 : }
476 :
477 26644 : TEST(VectorLoadGlobalICSlotSharing) {
478 6 : if (!i::FLAG_use_ic) return;
479 5 : if (i::FLAG_always_opt) return;
480 4 : FLAG_allow_natives_syntax = true;
481 :
482 4 : CcTest::InitializeVM();
483 4 : LocalContext context;
484 8 : v8::HandleScope scope(context->GetIsolate());
485 : Isolate* isolate = CcTest::i_isolate();
486 :
487 : // Function f has 5 LoadGlobalICs: 3 for {o} references outside of "typeof"
488 : // operator and 2 for {o} references inside "typeof" operator.
489 : CompileRun(
490 : "o = 10;"
491 : "function f() {"
492 : " var x = o || 10;"
493 : " var y = typeof o;"
494 : " return o , typeof o, x , y, o;"
495 : "}"
496 : "%EnsureFeedbackVectorForFunction(f);"
497 : "f();");
498 4 : Handle<JSFunction> f = GetFunction("f");
499 : // There should be two IC slots for {o} references outside and inside
500 : // typeof operator respectively.
501 : Handle<FeedbackVector> feedback_vector =
502 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
503 4 : FeedbackVectorHelper helper(feedback_vector);
504 4 : CHECK_EQ(2, helper.slot_count());
505 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
506 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalInsideTypeof);
507 : FeedbackSlot slot1 = helper.slot(0);
508 : FeedbackSlot slot2 = helper.slot(1);
509 4 : CHECK_EQ(MONOMORPHIC, FeedbackNexus(feedback_vector, slot1).ic_state());
510 4 : CHECK_EQ(MONOMORPHIC, FeedbackNexus(feedback_vector, slot2).ic_state());
511 : }
512 :
513 :
514 26644 : TEST(VectorLoadICOnSmi) {
515 6 : if (!i::FLAG_use_ic) return;
516 5 : if (i::FLAG_always_opt) return;
517 4 : FLAG_allow_natives_syntax = true;
518 :
519 4 : CcTest::InitializeVM();
520 4 : LocalContext context;
521 8 : v8::HandleScope scope(context->GetIsolate());
522 : Isolate* isolate = CcTest::i_isolate();
523 : Heap* heap = isolate->heap();
524 :
525 : // Make sure function f has a call that uses a type feedback slot.
526 : CompileRun(
527 : "var o = { foo: 3 };"
528 : "%EnsureFeedbackVectorForFunction(f);"
529 : "function f(a) { return a.foo; } f(o);");
530 4 : Handle<JSFunction> f = GetFunction("f");
531 : // There should be one IC.
532 : Handle<FeedbackVector> feedback_vector =
533 : Handle<FeedbackVector>(f->feedback_vector(), isolate);
534 : FeedbackSlot slot(0);
535 : FeedbackNexus nexus(feedback_vector, slot);
536 4 : CHECK_EQ(PREMONOMORPHIC, nexus.ic_state());
537 :
538 : CompileRun("f(34)");
539 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
540 : // Verify that the monomorphic map is the one we expect.
541 : Map number_map = ReadOnlyRoots(heap).heap_number_map();
542 4 : CHECK_EQ(number_map, nexus.GetFirstMap());
543 :
544 : // Now go polymorphic on o.
545 : CompileRun("f(o)");
546 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
547 :
548 : MapHandles maps;
549 4 : nexus.ExtractMaps(&maps);
550 4 : CHECK_EQ(2, maps.size());
551 :
552 : // One of the maps should be the o map.
553 : v8::MaybeLocal<v8::Value> v8_o =
554 12 : CcTest::global()->Get(context.local(), v8_str("o"));
555 : Handle<JSObject> o =
556 : Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked()));
557 : bool number_map_found = false;
558 : bool o_map_found = false;
559 12 : for (Handle<Map> current : maps) {
560 8 : if (*current == number_map)
561 : number_map_found = true;
562 4 : else if (*current == o->map())
563 : o_map_found = true;
564 : }
565 4 : CHECK(number_map_found && o_map_found);
566 :
567 : // The degree of polymorphism doesn't change.
568 : CompileRun("f(100)");
569 4 : CHECK_EQ(POLYMORPHIC, nexus.ic_state());
570 : MapHandles maps2;
571 4 : nexus.ExtractMaps(&maps2);
572 4 : CHECK_EQ(2, maps2.size());
573 : }
574 :
575 :
576 26644 : TEST(ReferenceContextAllocatesNoSlots) {
577 6 : if (!i::FLAG_use_ic) return;
578 5 : if (i::FLAG_always_opt) return;
579 4 : FLAG_allow_natives_syntax = true;
580 :
581 4 : CcTest::InitializeVM();
582 4 : LocalContext context;
583 8 : v8::HandleScope scope(context->GetIsolate());
584 : Isolate* isolate = CcTest::i_isolate();
585 :
586 : {
587 : CompileRun(
588 : "function testvar(x) {"
589 : " y = x;"
590 : " y = a;"
591 : " return y;"
592 : "}"
593 : "%EnsureFeedbackVectorForFunction(testvar);"
594 : "a = 3;"
595 : "testvar({});");
596 :
597 4 : Handle<JSFunction> f = GetFunction("testvar");
598 :
599 : // There should be two LOAD_ICs, one for a and one for y at the end.
600 : Handle<FeedbackVector> feedback_vector =
601 4 : handle(f->feedback_vector(), isolate);
602 4 : FeedbackVectorHelper helper(feedback_vector);
603 4 : CHECK_EQ(3, helper.slot_count());
604 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kStoreGlobalSloppy);
605 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
606 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
607 : }
608 :
609 : {
610 : CompileRun(
611 : "function testprop(x) {"
612 : " 'use strict';"
613 : " x.blue = a;"
614 : "}"
615 : "%EnsureFeedbackVectorForFunction(testprop);"
616 : "testprop({ blue: 3 });");
617 :
618 4 : Handle<JSFunction> f = GetFunction("testprop");
619 :
620 : // There should be one LOAD_IC, for the load of a.
621 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
622 4 : FeedbackVectorHelper helper(feedback_vector);
623 4 : CHECK_EQ(2, helper.slot_count());
624 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
625 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
626 : }
627 :
628 : {
629 : CompileRun(
630 : "function testpropfunc(x) {"
631 : " x().blue = a;"
632 : " return x().blue;"
633 : "}"
634 : "%EnsureFeedbackVectorForFunction(testpropfunc);"
635 : "function makeresult() { return { blue: 3 }; }"
636 : "testpropfunc(makeresult);");
637 :
638 4 : Handle<JSFunction> f = GetFunction("testpropfunc");
639 :
640 : // There should be 1 LOAD_GLOBAL_IC to load x (in both cases), 2 CALL_ICs
641 : // to call x and a LOAD_IC to load blue.
642 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
643 4 : FeedbackVectorHelper helper(feedback_vector);
644 4 : CHECK_EQ(5, helper.slot_count());
645 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kCall);
646 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
647 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedSloppy);
648 4 : CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kCall);
649 4 : CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kLoadProperty);
650 : }
651 :
652 : {
653 : CompileRun(
654 : "function testkeyedprop(x) {"
655 : " x[0] = a;"
656 : " return x[0];"
657 : "}"
658 : "%EnsureFeedbackVectorForFunction(testkeyedprop);"
659 : "testkeyedprop([0, 1, 2]);");
660 :
661 4 : Handle<JSFunction> f = GetFunction("testkeyedprop");
662 :
663 : // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
664 : // KEYED_LOAD_IC for the load of x[0] in the return statement.
665 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
666 4 : FeedbackVectorHelper helper(feedback_vector);
667 4 : CHECK_EQ(3, helper.slot_count());
668 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
669 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedSloppy);
670 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
671 : }
672 :
673 : {
674 : CompileRun(
675 : "function testkeyedprop(x) {"
676 : " 'use strict';"
677 : " x[0] = a;"
678 : " return x[0];"
679 : "}"
680 : "%EnsureFeedbackVectorForFunction(testkeyedprop);"
681 : "testkeyedprop([0, 1, 2]);");
682 :
683 4 : Handle<JSFunction> f = GetFunction("testkeyedprop");
684 :
685 : // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one
686 : // KEYED_LOAD_IC for the load of x[0] in the return statement.
687 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
688 4 : FeedbackVectorHelper helper(feedback_vector);
689 4 : CHECK_EQ(3, helper.slot_count());
690 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
691 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreKeyedStrict);
692 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kLoadKeyed);
693 : }
694 :
695 : {
696 : CompileRun(
697 : "function testcompound(x) {"
698 : " 'use strict';"
699 : " x.old = x.young = x.in_between = a;"
700 : " return x.old + x.young;"
701 : "}"
702 : "%EnsureFeedbackVectorForFunction(testcompound);"
703 : "testcompound({ old: 3, young: 3, in_between: 3 });");
704 :
705 4 : Handle<JSFunction> f = GetFunction("testcompound");
706 :
707 : // There should be 1 LOAD_GLOBAL_IC for load of a and 2 LOAD_ICs, for load
708 : // of x.old and x.young.
709 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), isolate);
710 4 : FeedbackVectorHelper helper(feedback_vector);
711 4 : CHECK_EQ(7, helper.slot_count());
712 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLoadGlobalNotInsideTypeof);
713 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreNamedStrict);
714 4 : CHECK_SLOT_KIND(helper, 2, FeedbackSlotKind::kStoreNamedStrict);
715 4 : CHECK_SLOT_KIND(helper, 3, FeedbackSlotKind::kStoreNamedStrict);
716 4 : CHECK_SLOT_KIND(helper, 4, FeedbackSlotKind::kBinaryOp);
717 4 : CHECK_SLOT_KIND(helper, 5, FeedbackSlotKind::kLoadProperty);
718 4 : CHECK_SLOT_KIND(helper, 6, FeedbackSlotKind::kLoadProperty);
719 : }
720 : }
721 :
722 :
723 26644 : TEST(VectorStoreICBasic) {
724 6 : if (!i::FLAG_use_ic) return;
725 5 : if (i::FLAG_always_opt) return;
726 4 : FLAG_allow_natives_syntax = true;
727 :
728 4 : CcTest::InitializeVM();
729 4 : LocalContext context;
730 8 : v8::HandleScope scope(context->GetIsolate());
731 :
732 : CompileRun(
733 : "function f(a) {"
734 : " a.foo = 5;"
735 : "};"
736 : "%EnsureFeedbackVectorForFunction(f);"
737 : "var a = { foo: 3 };"
738 : "f(a);"
739 : "f(a);"
740 : "f(a);");
741 4 : Handle<JSFunction> f = GetFunction("f");
742 : // There should be one IC slot.
743 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), f->GetIsolate());
744 4 : FeedbackVectorHelper helper(feedback_vector);
745 4 : CHECK_EQ(1, helper.slot_count());
746 : FeedbackSlot slot(0);
747 : FeedbackNexus nexus(feedback_vector, slot);
748 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
749 : }
750 :
751 26644 : TEST(StoreOwnIC) {
752 6 : if (!i::FLAG_use_ic) return;
753 5 : if (i::FLAG_always_opt) return;
754 4 : FLAG_allow_natives_syntax = true;
755 :
756 4 : CcTest::InitializeVM();
757 4 : LocalContext context;
758 8 : v8::HandleScope scope(context->GetIsolate());
759 :
760 : CompileRun(
761 : "function f(v) {"
762 : " return {a: 0, b: v, c: 0};"
763 : "}"
764 : "%EnsureFeedbackVectorForFunction(f);"
765 : "f(1);"
766 : "f(2);"
767 : "f(3);");
768 4 : Handle<JSFunction> f = GetFunction("f");
769 : // There should be one IC slot.
770 : Handle<FeedbackVector> feedback_vector(f->feedback_vector(), f->GetIsolate());
771 4 : FeedbackVectorHelper helper(feedback_vector);
772 4 : CHECK_EQ(2, helper.slot_count());
773 4 : CHECK_SLOT_KIND(helper, 0, FeedbackSlotKind::kLiteral);
774 4 : CHECK_SLOT_KIND(helper, 1, FeedbackSlotKind::kStoreOwnNamed);
775 : FeedbackNexus nexus(feedback_vector, helper.slot(1));
776 4 : CHECK_EQ(MONOMORPHIC, nexus.ic_state());
777 : }
778 :
779 : } // namespace
780 :
781 : } // namespace internal
782 79917 : } // namespace v8
|