Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 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" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 9 | #include "src/debug/debug.h" |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 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.h" |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 15 | #include "test/cctest/test-feedback-vector.h" |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 16 | |
| 17 | using namespace v8::internal; |
| 18 | |
| 19 | namespace { |
| 20 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 21 | #define CHECK_SLOT_KIND(helper, index, expected_kind) \ |
| 22 | CHECK_EQ(expected_kind, helper.vector()->GetKind(helper.slot(index))); |
| 23 | |
| 24 | |
| 25 | static Handle<JSFunction> GetFunction(const char* name) { |
| 26 | v8::MaybeLocal<v8::Value> v8_f = CcTest::global()->Get( |
| 27 | v8::Isolate::GetCurrent()->GetCurrentContext(), v8_str(name)); |
| 28 | Handle<JSFunction> f = |
| 29 | Handle<JSFunction>::cast(v8::Utils::OpenHandle(*v8_f.ToLocalChecked())); |
| 30 | return f; |
| 31 | } |
| 32 | |
| 33 | |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 34 | TEST(VectorStructure) { |
| 35 | LocalContext context; |
| 36 | v8::HandleScope scope(context->GetIsolate()); |
| 37 | Isolate* isolate = CcTest::i_isolate(); |
| 38 | Factory* factory = isolate->factory(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 39 | Zone* zone = isolate->runtime_zone(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 40 | |
| 41 | // Empty vectors are the empty fixed array. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 42 | StaticFeedbackVectorSpec empty; |
| 43 | Handle<TypeFeedbackVector> vector = NewTypeFeedbackVector(isolate, &empty); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 44 | CHECK(Handle<FixedArray>::cast(vector) |
| 45 | .is_identical_to(factory->empty_fixed_array())); |
| 46 | // Which can nonetheless be queried. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 47 | CHECK(vector->is_empty()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 48 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 49 | { |
| 50 | FeedbackVectorSpec one_slot(zone); |
| 51 | one_slot.AddGeneralSlot(); |
| 52 | vector = NewTypeFeedbackVector(isolate, &one_slot); |
| 53 | FeedbackVectorHelper helper(vector); |
| 54 | CHECK_EQ(1, helper.slot_count()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 55 | } |
| 56 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 57 | { |
| 58 | FeedbackVectorSpec one_icslot(zone); |
| 59 | one_icslot.AddCallICSlot(); |
| 60 | vector = NewTypeFeedbackVector(isolate, &one_icslot); |
| 61 | FeedbackVectorHelper helper(vector); |
| 62 | CHECK_EQ(1, helper.slot_count()); |
| 63 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 64 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 65 | { |
| 66 | FeedbackVectorSpec spec(zone); |
| 67 | for (int i = 0; i < 3; i++) { |
| 68 | spec.AddGeneralSlot(); |
| 69 | } |
| 70 | for (int i = 0; i < 5; i++) { |
| 71 | spec.AddCallICSlot(); |
| 72 | } |
| 73 | vector = NewTypeFeedbackVector(isolate, &spec); |
| 74 | FeedbackVectorHelper helper(vector); |
| 75 | CHECK_EQ(8, helper.slot_count()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 76 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 77 | int index = vector->GetIndex(helper.slot(0)); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 78 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 79 | CHECK_EQ(TypeFeedbackVector::kReservedIndexCount, index); |
| 80 | CHECK_EQ(helper.slot(0), vector->ToSlot(index)); |
| 81 | |
| 82 | index = vector->GetIndex(helper.slot(3)); |
| 83 | CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3, index); |
| 84 | CHECK_EQ(helper.slot(3), vector->ToSlot(index)); |
| 85 | |
| 86 | index = vector->GetIndex(helper.slot(7)); |
| 87 | CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3 + |
| 88 | 4 * TypeFeedbackMetadata::GetSlotSize( |
| 89 | FeedbackVectorSlotKind::CALL_IC), |
| 90 | index); |
| 91 | CHECK_EQ(helper.slot(7), vector->ToSlot(index)); |
| 92 | |
| 93 | CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + 3 + |
| 94 | 5 * TypeFeedbackMetadata::GetSlotSize( |
| 95 | FeedbackVectorSlotKind::CALL_IC), |
| 96 | vector->length()); |
| 97 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 98 | } |
| 99 | |
| 100 | |
| 101 | // IC slots need an encoding to recognize what is in there. |
| 102 | TEST(VectorICMetadata) { |
| 103 | LocalContext context; |
| 104 | v8::HandleScope scope(context->GetIsolate()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 105 | Isolate* isolate = CcTest::i_isolate(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 106 | Zone* zone = isolate->runtime_zone(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 107 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 108 | FeedbackVectorSpec spec(zone); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 109 | // Set metadata. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 110 | for (int i = 0; i < 40; i++) { |
| 111 | switch (i % 4) { |
| 112 | case 0: |
| 113 | spec.AddGeneralSlot(); |
| 114 | break; |
| 115 | case 1: |
| 116 | spec.AddCallICSlot(); |
| 117 | break; |
| 118 | case 2: |
| 119 | spec.AddLoadICSlot(); |
| 120 | break; |
| 121 | case 3: |
| 122 | spec.AddKeyedLoadICSlot(); |
| 123 | break; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 124 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 125 | } |
| 126 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 127 | Handle<TypeFeedbackVector> vector = NewTypeFeedbackVector(isolate, &spec); |
| 128 | FeedbackVectorHelper helper(vector); |
| 129 | CHECK_EQ(40, helper.slot_count()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 130 | |
| 131 | // Meanwhile set some feedback values and type feedback values to |
| 132 | // verify the data structure remains intact. |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 133 | vector->Set(FeedbackVectorSlot(0), *vector); |
| 134 | |
| 135 | // Verify the metadata is correctly set up from the spec. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 136 | for (int i = 0; i < 40; i++) { |
| 137 | FeedbackVectorSlotKind kind = vector->GetKind(helper.slot(i)); |
| 138 | switch (i % 4) { |
| 139 | case 0: |
| 140 | CHECK_EQ(FeedbackVectorSlotKind::GENERAL, kind); |
| 141 | break; |
| 142 | case 1: |
| 143 | CHECK_EQ(FeedbackVectorSlotKind::CALL_IC, kind); |
| 144 | break; |
| 145 | case 2: |
| 146 | CHECK_EQ(FeedbackVectorSlotKind::LOAD_IC, kind); |
| 147 | break; |
| 148 | case 3: |
| 149 | CHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, kind); |
| 150 | break; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 151 | } |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | |
| 156 | TEST(VectorSlotClearing) { |
| 157 | LocalContext context; |
| 158 | v8::HandleScope scope(context->GetIsolate()); |
| 159 | Isolate* isolate = CcTest::i_isolate(); |
| 160 | Factory* factory = isolate->factory(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 161 | Zone* zone = isolate->runtime_zone(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 162 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 163 | // We only test clearing FeedbackVectorSlots, not FeedbackVectorSlots. |
| 164 | // The reason is that FeedbackVectorSlots need a full code environment |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 165 | // to fully test (See VectorICProfilerStatistics test below). |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 166 | FeedbackVectorSpec spec(zone); |
| 167 | for (int i = 0; i < 5; i++) { |
| 168 | spec.AddGeneralSlot(); |
| 169 | } |
| 170 | Handle<TypeFeedbackVector> vector = NewTypeFeedbackVector(isolate, &spec); |
| 171 | FeedbackVectorHelper helper(vector); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 172 | |
| 173 | // Fill with information |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 174 | vector->Set(helper.slot(0), Smi::FromInt(1)); |
| 175 | Handle<WeakCell> cell = factory->NewWeakCell(factory->fixed_array_map()); |
| 176 | vector->Set(helper.slot(1), *cell); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 177 | Handle<AllocationSite> site = factory->NewAllocationSite(); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 178 | vector->Set(helper.slot(2), *site); |
| 179 | |
| 180 | // GC time clearing leaves slots alone. |
| 181 | vector->ClearSlotsAtGCTime(NULL); |
| 182 | Object* obj = vector->Get(helper.slot(1)); |
| 183 | CHECK(obj->IsWeakCell() && !WeakCell::cast(obj)->cleared()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 184 | |
| 185 | vector->ClearSlots(NULL); |
| 186 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 187 | // The feedback vector slots are cleared. AllocationSites are still granted |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 188 | // an exemption from clearing, as are smis. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 189 | CHECK_EQ(Smi::FromInt(1), vector->Get(helper.slot(0))); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 190 | CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate), |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 191 | vector->Get(helper.slot(1))); |
| 192 | CHECK(vector->Get(helper.slot(2))->IsAllocationSite()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 193 | } |
| 194 | |
| 195 | |
| 196 | TEST(VectorCallICStates) { |
| 197 | if (i::FLAG_always_opt) return; |
| 198 | CcTest::InitializeVM(); |
| 199 | LocalContext context; |
| 200 | v8::HandleScope scope(context->GetIsolate()); |
| 201 | Isolate* isolate = CcTest::i_isolate(); |
| 202 | Heap* heap = isolate->heap(); |
| 203 | |
| 204 | // Make sure function f has a call that uses a type feedback slot. |
| 205 | CompileRun( |
| 206 | "function foo() { return 17; }" |
| 207 | "function f(a) { a(); } f(foo);"); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 208 | Handle<JSFunction> f = GetFunction("f"); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 209 | // There should be one IC. |
| 210 | Handle<TypeFeedbackVector> feedback_vector = |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 211 | Handle<TypeFeedbackVector>(f->feedback_vector(), isolate); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 212 | FeedbackVectorSlot slot(0); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 213 | CallICNexus nexus(feedback_vector, slot); |
| 214 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 215 | // CallIC doesn't return map feedback. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 216 | CHECK(!nexus.FindFirstMap()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 217 | |
| 218 | CompileRun("f(function() { return 16; })"); |
| 219 | CHECK_EQ(GENERIC, nexus.StateFromFeedback()); |
| 220 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 221 | // After a collection, state should remain GENERIC. |
| 222 | heap->CollectAllGarbage(); |
| 223 | CHECK_EQ(GENERIC, nexus.StateFromFeedback()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 224 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 225 | // A call to Array is special, it contains an AllocationSite as feedback. |
| 226 | // Clear the IC manually in order to test this case. |
| 227 | nexus.Clear(f->shared()->code()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 228 | CompileRun("f(Array)"); |
| 229 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 230 | CHECK(nexus.GetFeedback()->IsAllocationSite()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 231 | |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 232 | heap->CollectAllGarbage(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 233 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 234 | } |
| 235 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 236 | TEST(VectorCallCounts) { |
| 237 | if (i::FLAG_always_opt) return; |
| 238 | CcTest::InitializeVM(); |
| 239 | LocalContext context; |
| 240 | v8::HandleScope scope(context->GetIsolate()); |
| 241 | Isolate* isolate = CcTest::i_isolate(); |
| 242 | |
| 243 | // Make sure function f has a call that uses a type feedback slot. |
| 244 | CompileRun( |
| 245 | "function foo() { return 17; }" |
| 246 | "function f(a) { a(); } f(foo);"); |
| 247 | Handle<JSFunction> f = GetFunction("f"); |
| 248 | // There should be one IC. |
| 249 | Handle<TypeFeedbackVector> feedback_vector = |
| 250 | Handle<TypeFeedbackVector>(f->feedback_vector(), isolate); |
| 251 | FeedbackVectorSlot slot(0); |
| 252 | CallICNexus nexus(feedback_vector, slot); |
| 253 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 254 | |
| 255 | CompileRun("f(foo); f(foo);"); |
| 256 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 257 | CHECK_EQ(3, nexus.ExtractCallCount()); |
| 258 | |
| 259 | CompileRun( |
| 260 | "function Foo() {}" |
| 261 | "function f(a) { new a(); } f(Foo);"); |
| 262 | f = GetFunction("f"); |
| 263 | // There should be one IC. |
| 264 | feedback_vector = Handle<TypeFeedbackVector>(f->feedback_vector(), isolate); |
| 265 | FeedbackVectorSlot cslot(1); |
| 266 | |
| 267 | CompileRun("f(Foo); f(Foo);"); |
| 268 | CHECK(feedback_vector->Get(cslot)->IsSmi()); |
| 269 | CHECK_EQ(3, Smi::cast(feedback_vector->Get(cslot))->value()); |
| 270 | } |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 271 | |
| 272 | TEST(VectorLoadICStates) { |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 273 | if (i::FLAG_always_opt) return; |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 274 | CcTest::InitializeVM(); |
| 275 | LocalContext context; |
| 276 | v8::HandleScope scope(context->GetIsolate()); |
| 277 | Isolate* isolate = CcTest::i_isolate(); |
| 278 | Heap* heap = isolate->heap(); |
| 279 | |
| 280 | // Make sure function f has a call that uses a type feedback slot. |
| 281 | CompileRun( |
| 282 | "var o = { foo: 3 };" |
| 283 | "function f(a) { return a.foo; } f(o);"); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 284 | Handle<JSFunction> f = GetFunction("f"); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 285 | // There should be one IC. |
| 286 | Handle<TypeFeedbackVector> feedback_vector = |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 287 | Handle<TypeFeedbackVector>(f->feedback_vector(), isolate); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 288 | FeedbackVectorSlot slot(0); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 289 | LoadICNexus nexus(feedback_vector, slot); |
| 290 | CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback()); |
| 291 | |
| 292 | CompileRun("f(o)"); |
| 293 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 294 | // Verify that the monomorphic map is the one we expect. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 295 | v8::MaybeLocal<v8::Value> v8_o = |
| 296 | CcTest::global()->Get(context.local(), v8_str("o")); |
| 297 | Handle<JSObject> o = |
| 298 | Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked())); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 299 | CHECK_EQ(o->map(), nexus.FindFirstMap()); |
| 300 | |
| 301 | // Now go polymorphic. |
| 302 | CompileRun("f({ blarg: 3, foo: 2 })"); |
| 303 | CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 304 | |
| 305 | CompileRun( |
| 306 | "delete o.foo;" |
| 307 | "f(o)"); |
| 308 | CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 309 | |
| 310 | CompileRun("f({ blarg: 3, torino: 10, foo: 2 })"); |
| 311 | CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 312 | MapHandleList maps; |
| 313 | nexus.FindAllMaps(&maps); |
| 314 | CHECK_EQ(4, maps.length()); |
| 315 | |
| 316 | // Finally driven megamorphic. |
| 317 | CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })"); |
| 318 | CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 319 | CHECK(!nexus.FindFirstMap()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 320 | |
| 321 | // After a collection, state should not be reset to PREMONOMORPHIC. |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 322 | heap->CollectAllGarbage(); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 323 | CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback()); |
| 324 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 325 | |
| 326 | |
| 327 | TEST(VectorLoadICSlotSharing) { |
| 328 | if (i::FLAG_always_opt) return; |
| 329 | CcTest::InitializeVM(); |
| 330 | LocalContext context; |
| 331 | v8::HandleScope scope(context->GetIsolate()); |
| 332 | Isolate* isolate = CcTest::i_isolate(); |
| 333 | |
| 334 | // Function f has 3 LoadICs, one for each o, but the ICs share the same |
| 335 | // feedback vector IC slot. |
| 336 | CompileRun( |
| 337 | "o = 10;" |
| 338 | "function f() {" |
| 339 | " var x = o + 10;" |
| 340 | " return o + x + o;" |
| 341 | "}" |
| 342 | "f();"); |
| 343 | Handle<JSFunction> f = GetFunction("f"); |
| 344 | // There should be one IC slot. |
| 345 | Handle<TypeFeedbackVector> feedback_vector = |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 346 | Handle<TypeFeedbackVector>(f->feedback_vector(), isolate); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 347 | FeedbackVectorHelper helper(feedback_vector); |
| 348 | CHECK_EQ(1, helper.slot_count()); |
| 349 | FeedbackVectorSlot slot(0); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 350 | LoadGlobalICNexus nexus(feedback_vector, slot); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 351 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
Emily Bernier | d0a1eb7 | 2015-03-24 16:35:39 -0400 | [diff] [blame] | 352 | } |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 353 | |
| 354 | |
| 355 | TEST(VectorLoadICOnSmi) { |
| 356 | if (i::FLAG_always_opt) return; |
| 357 | CcTest::InitializeVM(); |
| 358 | LocalContext context; |
| 359 | v8::HandleScope scope(context->GetIsolate()); |
| 360 | Isolate* isolate = CcTest::i_isolate(); |
| 361 | Heap* heap = isolate->heap(); |
| 362 | |
| 363 | // Make sure function f has a call that uses a type feedback slot. |
| 364 | CompileRun( |
| 365 | "var o = { foo: 3 };" |
| 366 | "function f(a) { return a.foo; } f(o);"); |
| 367 | Handle<JSFunction> f = GetFunction("f"); |
| 368 | // There should be one IC. |
| 369 | Handle<TypeFeedbackVector> feedback_vector = |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 370 | Handle<TypeFeedbackVector>(f->feedback_vector(), isolate); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 371 | FeedbackVectorSlot slot(0); |
| 372 | LoadICNexus nexus(feedback_vector, slot); |
| 373 | CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback()); |
| 374 | |
| 375 | CompileRun("f(34)"); |
| 376 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 377 | // Verify that the monomorphic map is the one we expect. |
| 378 | Map* number_map = heap->heap_number_map(); |
| 379 | CHECK_EQ(number_map, nexus.FindFirstMap()); |
| 380 | |
| 381 | // Now go polymorphic on o. |
| 382 | CompileRun("f(o)"); |
| 383 | CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 384 | |
| 385 | MapHandleList maps; |
| 386 | nexus.FindAllMaps(&maps); |
| 387 | CHECK_EQ(2, maps.length()); |
| 388 | |
| 389 | // One of the maps should be the o map. |
| 390 | v8::MaybeLocal<v8::Value> v8_o = |
| 391 | CcTest::global()->Get(context.local(), v8_str("o")); |
| 392 | Handle<JSObject> o = |
| 393 | Handle<JSObject>::cast(v8::Utils::OpenHandle(*v8_o.ToLocalChecked())); |
| 394 | bool number_map_found = false; |
| 395 | bool o_map_found = false; |
| 396 | for (int i = 0; i < maps.length(); i++) { |
| 397 | Handle<Map> current = maps[i]; |
| 398 | if (*current == number_map) |
| 399 | number_map_found = true; |
| 400 | else if (*current == o->map()) |
| 401 | o_map_found = true; |
| 402 | } |
| 403 | CHECK(number_map_found && o_map_found); |
| 404 | |
| 405 | // The degree of polymorphism doesn't change. |
| 406 | CompileRun("f(100)"); |
| 407 | CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback()); |
| 408 | MapHandleList maps2; |
| 409 | nexus.FindAllMaps(&maps2); |
| 410 | CHECK_EQ(2, maps2.length()); |
| 411 | } |
| 412 | |
| 413 | |
| 414 | TEST(ReferenceContextAllocatesNoSlots) { |
| 415 | if (i::FLAG_always_opt) return; |
| 416 | CcTest::InitializeVM(); |
| 417 | LocalContext context; |
| 418 | v8::HandleScope scope(context->GetIsolate()); |
| 419 | Isolate* isolate = CcTest::i_isolate(); |
| 420 | |
| 421 | { |
| 422 | CompileRun( |
| 423 | "function testvar(x) {" |
| 424 | " y = x;" |
| 425 | " y = a;" |
| 426 | " return y;" |
| 427 | "}" |
| 428 | "a = 3;" |
| 429 | "testvar({});"); |
| 430 | |
| 431 | Handle<JSFunction> f = GetFunction("testvar"); |
| 432 | |
| 433 | // There should be two LOAD_ICs, one for a and one for y at the end. |
| 434 | Handle<TypeFeedbackVector> feedback_vector = |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 435 | handle(f->feedback_vector(), isolate); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 436 | FeedbackVectorHelper helper(feedback_vector); |
| 437 | CHECK_EQ(4, helper.slot_count()); |
| 438 | CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::STORE_IC); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 439 | CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::LOAD_GLOBAL_IC); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 440 | CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 441 | CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::LOAD_GLOBAL_IC); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 442 | } |
| 443 | |
| 444 | { |
| 445 | CompileRun( |
| 446 | "function testprop(x) {" |
| 447 | " x.blue = a;" |
| 448 | "}" |
| 449 | "testprop({ blue: 3 });"); |
| 450 | |
| 451 | Handle<JSFunction> f = GetFunction("testprop"); |
| 452 | |
| 453 | // There should be one LOAD_IC, for the load of a. |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 454 | Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 455 | FeedbackVectorHelper helper(feedback_vector); |
| 456 | CHECK_EQ(2, helper.slot_count()); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 457 | CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_GLOBAL_IC); |
| 458 | CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::STORE_IC); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 459 | } |
| 460 | |
| 461 | { |
| 462 | CompileRun( |
| 463 | "function testpropfunc(x) {" |
| 464 | " x().blue = a;" |
| 465 | " return x().blue;" |
| 466 | "}" |
| 467 | "function makeresult() { return { blue: 3 }; }" |
| 468 | "testpropfunc(makeresult);"); |
| 469 | |
| 470 | Handle<JSFunction> f = GetFunction("testpropfunc"); |
| 471 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 472 | // There should be 1 LOAD_GLOBAL_IC to load x (in both cases), 2 CALL_ICs |
| 473 | // to call x and a LOAD_IC to load blue. |
| 474 | Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 475 | FeedbackVectorHelper helper(feedback_vector); |
| 476 | CHECK_EQ(5, helper.slot_count()); |
| 477 | CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::CALL_IC); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 478 | CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::LOAD_GLOBAL_IC); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 479 | CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC); |
| 480 | CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::CALL_IC); |
| 481 | CHECK_SLOT_KIND(helper, 4, FeedbackVectorSlotKind::LOAD_IC); |
| 482 | } |
| 483 | |
| 484 | { |
| 485 | CompileRun( |
| 486 | "function testkeyedprop(x) {" |
| 487 | " x[0] = a;" |
| 488 | " return x[0];" |
| 489 | "}" |
| 490 | "testkeyedprop([0, 1, 2]);"); |
| 491 | |
| 492 | Handle<JSFunction> f = GetFunction("testkeyedprop"); |
| 493 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 494 | // There should be 1 LOAD_GLOBAL_ICs for the load of a, and one |
| 495 | // KEYED_LOAD_IC for the load of x[0] in the return statement. |
| 496 | Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 497 | FeedbackVectorHelper helper(feedback_vector); |
| 498 | CHECK_EQ(3, helper.slot_count()); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 499 | CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_GLOBAL_IC); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 500 | CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::KEYED_STORE_IC); |
| 501 | CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::KEYED_LOAD_IC); |
| 502 | } |
| 503 | |
| 504 | { |
| 505 | CompileRun( |
| 506 | "function testcompound(x) {" |
| 507 | " x.old = x.young = x.in_between = a;" |
| 508 | " return x.old + x.young;" |
| 509 | "}" |
| 510 | "testcompound({ old: 3, young: 3, in_between: 3 });"); |
| 511 | |
| 512 | Handle<JSFunction> f = GetFunction("testcompound"); |
| 513 | |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 514 | // There should be 1 LOAD_GLOBAL_IC for load of a and 2 LOAD_ICs, for load |
| 515 | // of x.old and x.young. |
| 516 | Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 517 | FeedbackVectorHelper helper(feedback_vector); |
| 518 | CHECK_EQ(6, helper.slot_count()); |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 519 | CHECK_SLOT_KIND(helper, 0, FeedbackVectorSlotKind::LOAD_GLOBAL_IC); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 520 | CHECK_SLOT_KIND(helper, 1, FeedbackVectorSlotKind::STORE_IC); |
| 521 | CHECK_SLOT_KIND(helper, 2, FeedbackVectorSlotKind::STORE_IC); |
| 522 | CHECK_SLOT_KIND(helper, 3, FeedbackVectorSlotKind::STORE_IC); |
| 523 | CHECK_SLOT_KIND(helper, 4, FeedbackVectorSlotKind::LOAD_IC); |
| 524 | CHECK_SLOT_KIND(helper, 5, FeedbackVectorSlotKind::LOAD_IC); |
| 525 | } |
| 526 | } |
| 527 | |
| 528 | |
| 529 | TEST(VectorStoreICBasic) { |
| 530 | if (i::FLAG_always_opt) return; |
| 531 | |
| 532 | CcTest::InitializeVM(); |
| 533 | LocalContext context; |
| 534 | v8::HandleScope scope(context->GetIsolate()); |
| 535 | |
| 536 | CompileRun( |
| 537 | "function f(a) {" |
| 538 | " a.foo = 5;" |
| 539 | "}" |
| 540 | "var a = { foo: 3 };" |
| 541 | "f(a);" |
| 542 | "f(a);" |
| 543 | "f(a);"); |
| 544 | Handle<JSFunction> f = GetFunction("f"); |
| 545 | // There should be one IC slot. |
Ben Murdoch | 61f157c | 2016-09-16 13:49:30 +0100 | [diff] [blame] | 546 | Handle<TypeFeedbackVector> feedback_vector(f->feedback_vector()); |
Ben Murdoch | 4a90d5f | 2016-03-22 12:00:34 +0000 | [diff] [blame] | 547 | FeedbackVectorHelper helper(feedback_vector); |
| 548 | CHECK_EQ(1, helper.slot_count()); |
| 549 | FeedbackVectorSlot slot(0); |
| 550 | StoreICNexus nexus(feedback_vector, slot); |
| 551 | CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback()); |
| 552 | } |
| 553 | |
| 554 | } // namespace |