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