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/feedback-vector.h"
6 : #include "src/code-stubs.h"
7 : #include "src/feedback-vector-inl.h"
8 : #include "src/ic/ic-inl.h"
9 : #include "src/ic/ic-state.h"
10 : #include "src/objects.h"
11 :
12 : namespace v8 {
13 : namespace internal {
14 :
15 4635295 : bool FeedbackVectorSpec::HasTypeProfileSlot() const {
16 : FeedbackSlot slot =
17 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
18 4635295 : if (slots() <= slot.ToInt()) {
19 : return false;
20 : }
21 3819188 : return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
22 : }
23 :
24 7987458 : static bool IsPropertyNameFeedback(Object* feedback) {
25 7987457 : if (feedback->IsString()) return true;
26 7939067 : if (!feedback->IsSymbol()) return false;
27 : Symbol* symbol = Symbol::cast(feedback);
28 857781 : Heap* heap = symbol->GetHeap();
29 48577 : return symbol != heap->uninitialized_symbol() &&
30 809204 : symbol != heap->premonomorphic_symbol() &&
31 797459 : symbol != heap->megamorphic_symbol();
32 : }
33 :
34 0 : std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
35 0 : return os << FeedbackMetadata::Kind2String(kind);
36 : }
37 :
38 109808458 : FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
39 : int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
40 : int data = Smi::cast(get(index))->value();
41 219616916 : return VectorICComputer::decode(data, slot.ToInt());
42 : }
43 :
44 47516593 : void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
45 : int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
46 : int data = Smi::cast(get(index))->value();
47 95033186 : int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
48 : set(index, Smi::FromInt(new_data));
49 47516593 : }
50 :
51 : template Handle<FeedbackMetadata> FeedbackMetadata::New(
52 : Isolate* isolate, const StaticFeedbackVectorSpec* spec);
53 : template Handle<FeedbackMetadata> FeedbackMetadata::New(
54 : Isolate* isolate, const FeedbackVectorSpec* spec);
55 :
56 : // static
57 : template <typename Spec>
58 14016601 : Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
59 : const Spec* spec) {
60 : Factory* factory = isolate->factory();
61 :
62 : const int slot_count = spec->slots();
63 : const int slot_kinds_length = VectorICComputer::word_count(slot_count);
64 14016601 : const int length = slot_kinds_length + kReservedIndexCount;
65 14016601 : if (length == kReservedIndexCount) {
66 : return Handle<FeedbackMetadata>::cast(factory->empty_fixed_array());
67 : }
68 : #ifdef DEBUG
69 : for (int i = 0; i < slot_count;) {
70 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
71 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
72 : for (int j = 1; j < entry_size; j++) {
73 : FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
74 : DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
75 : }
76 : i += entry_size;
77 : }
78 : #endif
79 :
80 2626289 : Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
81 : array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
82 : // Fill the bit-vector part with zeros.
83 11923692 : for (int i = 0; i < slot_kinds_length; i++) {
84 : array->set(kReservedIndexCount + i, Smi::kZero);
85 : }
86 :
87 : Handle<FeedbackMetadata> metadata = Handle<FeedbackMetadata>::cast(array);
88 :
89 47516588 : for (int i = 0; i < slot_count; i++) {
90 : FeedbackSlot slot(i);
91 : FeedbackSlotKind kind = spec->GetKind(slot);
92 47516594 : metadata->SetKind(slot, kind);
93 : }
94 :
95 : // It's important that the FeedbackMetadata have a COW map, since it's
96 : // pointed to by both a SharedFunctionInfo and indirectly by closures through
97 : // the FeedbackVector. The serializer uses the COW map type to decide
98 : // this object belongs in the startup snapshot and not the partial
99 : // snapshot(s).
100 5252578 : metadata->set_map(isolate->heap()->fixed_cow_array_map());
101 :
102 2626287 : return metadata;
103 : }
104 :
105 3780850 : bool FeedbackMetadata::SpecDiffersFrom(
106 : const FeedbackVectorSpec* other_spec) const {
107 3780850 : if (other_spec->slots() != slot_count()) {
108 : return true;
109 : }
110 :
111 3780862 : int slots = slot_count();
112 39887986 : for (int i = 0; i < slots;) {
113 : FeedbackSlot slot(i);
114 32326246 : FeedbackSlotKind kind = GetKind(slot);
115 32326247 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
116 :
117 32326264 : if (kind != other_spec->GetKind(slot)) {
118 : return true;
119 : }
120 32326266 : i += entry_size;
121 : }
122 : return false;
123 : }
124 :
125 0 : const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
126 0 : switch (kind) {
127 : case FeedbackSlotKind::kInvalid:
128 : return "Invalid";
129 : case FeedbackSlotKind::kCall:
130 0 : return "Call";
131 : case FeedbackSlotKind::kLoadProperty:
132 0 : return "LoadProperty";
133 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
134 0 : return "LoadGlobalInsideTypeof";
135 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
136 0 : return "LoadGlobalNotInsideTypeof";
137 : case FeedbackSlotKind::kLoadKeyed:
138 0 : return "LoadKeyed";
139 : case FeedbackSlotKind::kStoreNamedSloppy:
140 0 : return "StoreNamedSloppy";
141 : case FeedbackSlotKind::kStoreNamedStrict:
142 0 : return "StoreNamedStrict";
143 : case FeedbackSlotKind::kStoreOwnNamed:
144 0 : return "StoreOwnNamed";
145 : case FeedbackSlotKind::kStoreGlobalSloppy:
146 0 : return "StoreGlobalSloppy";
147 : case FeedbackSlotKind::kStoreGlobalStrict:
148 0 : return "StoreGlobalStrict";
149 : case FeedbackSlotKind::kStoreKeyedSloppy:
150 0 : return "StoreKeyedSloppy";
151 : case FeedbackSlotKind::kStoreKeyedStrict:
152 0 : return "StoreKeyedStrict";
153 : case FeedbackSlotKind::kBinaryOp:
154 0 : return "BinaryOp";
155 : case FeedbackSlotKind::kCompareOp:
156 0 : return "CompareOp";
157 : case FeedbackSlotKind::kToBoolean:
158 0 : return "ToBoolean";
159 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
160 0 : return "StoreDataPropertyInLiteral";
161 : case FeedbackSlotKind::kCreateClosure:
162 0 : return "kCreateClosure";
163 : case FeedbackSlotKind::kLiteral:
164 0 : return "Literal";
165 : case FeedbackSlotKind::kTypeProfile:
166 0 : return "TypeProfile";
167 : case FeedbackSlotKind::kGeneral:
168 0 : return "General";
169 : case FeedbackSlotKind::kKindsNumber:
170 : break;
171 : }
172 0 : UNREACHABLE();
173 : return "?";
174 : }
175 :
176 388147 : bool FeedbackMetadata::HasTypeProfileSlot() const {
177 : FeedbackSlot slot =
178 388147 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
179 388147 : return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
180 : }
181 :
182 33076271 : FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
183 : DCHECK(!is_empty());
184 33076271 : return metadata()->GetKind(slot);
185 : }
186 :
187 1916 : FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
188 : DCHECK(metadata()->HasTypeProfileSlot());
189 : FeedbackSlot slot =
190 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
191 : DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
192 1916 : return slot;
193 : }
194 :
195 : // static
196 8725897 : Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
197 : Handle<SharedFunctionInfo> shared) {
198 : Factory* factory = isolate->factory();
199 :
200 8725897 : const int slot_count = shared->feedback_metadata()->slot_count();
201 8725910 : const int length = slot_count + kReservedIndexCount;
202 :
203 8725910 : Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
204 8725915 : array->set_map_no_write_barrier(isolate->heap()->feedback_vector_map());
205 8725915 : array->set(kSharedFunctionInfoIndex, *shared);
206 : array->set(kInvocationCountIndex, Smi::kZero);
207 :
208 : // Ensure we can skip the write barrier
209 : Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
210 : DCHECK_EQ(isolate->heap()->uninitialized_symbol(), *uninitialized_sentinel);
211 : Handle<Oddball> undefined_value = factory->undefined_value();
212 58764626 : for (int i = 0; i < slot_count;) {
213 : FeedbackSlot slot(i);
214 41312788 : FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
215 : int index = FeedbackVector::GetIndex(slot);
216 41312780 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
217 :
218 : Object* extra_value = *uninitialized_sentinel;
219 41312769 : switch (kind) {
220 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
221 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
222 5741452 : array->set(index, isolate->heap()->empty_weak_cell(),
223 5741452 : SKIP_WRITE_BARRIER);
224 5741452 : break;
225 : case FeedbackSlotKind::kCompareOp:
226 : case FeedbackSlotKind::kBinaryOp:
227 : case FeedbackSlotKind::kToBoolean:
228 6089705 : array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
229 6089705 : break;
230 : case FeedbackSlotKind::kCreateClosure: {
231 7472435 : Handle<Cell> cell = factory->NewNoClosuresCell(undefined_value);
232 7472441 : array->set(index, *cell);
233 : break;
234 : }
235 : case FeedbackSlotKind::kLiteral:
236 1849250 : array->set(index, *undefined_value, SKIP_WRITE_BARRIER);
237 1849251 : break;
238 : case FeedbackSlotKind::kCall:
239 6258018 : array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
240 : extra_value = Smi::kZero;
241 6258019 : break;
242 : case FeedbackSlotKind::kLoadProperty:
243 : case FeedbackSlotKind::kLoadKeyed:
244 : case FeedbackSlotKind::kStoreNamedSloppy:
245 : case FeedbackSlotKind::kStoreNamedStrict:
246 : case FeedbackSlotKind::kStoreOwnNamed:
247 : case FeedbackSlotKind::kStoreGlobalSloppy:
248 : case FeedbackSlotKind::kStoreGlobalStrict:
249 : case FeedbackSlotKind::kStoreKeyedSloppy:
250 : case FeedbackSlotKind::kStoreKeyedStrict:
251 : case FeedbackSlotKind::kStoreDataPropertyInLiteral:
252 : case FeedbackSlotKind::kGeneral:
253 : case FeedbackSlotKind::kTypeProfile:
254 13901926 : array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
255 13901926 : break;
256 :
257 : case FeedbackSlotKind::kInvalid:
258 : case FeedbackSlotKind::kKindsNumber:
259 0 : UNREACHABLE();
260 : array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
261 : break;
262 : }
263 67199017 : for (int j = 1; j < entry_size; j++) {
264 51772470 : array->set(index + j, extra_value, SKIP_WRITE_BARRIER);
265 : }
266 41312782 : i += entry_size;
267 : }
268 :
269 : Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(array);
270 8725916 : if (!isolate->is_best_effort_code_coverage()) {
271 436 : AddToCodeCoverageList(isolate, result);
272 : }
273 8725916 : return result;
274 : }
275 :
276 : // static
277 371311 : Handle<FeedbackVector> FeedbackVector::Copy(Isolate* isolate,
278 : Handle<FeedbackVector> vector) {
279 : Handle<FeedbackVector> result;
280 : result = Handle<FeedbackVector>::cast(
281 371311 : isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
282 371311 : if (!isolate->is_best_effort_code_coverage()) {
283 2 : AddToCodeCoverageList(isolate, result);
284 : }
285 371311 : return result;
286 : }
287 :
288 : // static
289 438 : void FeedbackVector::AddToCodeCoverageList(Isolate* isolate,
290 : Handle<FeedbackVector> vector) {
291 : DCHECK(!isolate->is_best_effort_code_coverage());
292 876 : if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
293 : Handle<ArrayList> list =
294 : Handle<ArrayList>::cast(isolate->factory()->code_coverage_list());
295 318 : list = ArrayList::Add(list, vector);
296 318 : isolate->SetCodeCoverageList(*list);
297 : }
298 :
299 92305 : void FeedbackVector::ClearSlots(JSFunction* host_function) {
300 : Isolate* isolate = GetIsolate();
301 :
302 : Object* uninitialized_sentinel =
303 : FeedbackVector::RawUninitializedSentinel(isolate);
304 92305 : Oddball* undefined_value = isolate->heap()->undefined_value();
305 :
306 : bool feedback_updated = false;
307 : FeedbackMetadataIterator iter(metadata());
308 371809 : while (iter.HasNext()) {
309 279504 : FeedbackSlot slot = iter.Next();
310 279504 : FeedbackSlotKind kind = iter.kind();
311 :
312 : Object* obj = Get(slot);
313 279504 : if (obj != uninitialized_sentinel) {
314 242792 : switch (kind) {
315 : case FeedbackSlotKind::kCall: {
316 : CallICNexus nexus(this, slot);
317 13602 : if (!nexus.IsCleared()) {
318 : nexus.Clear();
319 : feedback_updated = true;
320 : }
321 : break;
322 : }
323 : case FeedbackSlotKind::kLoadProperty: {
324 : LoadICNexus nexus(this, slot);
325 41537 : if (!nexus.IsCleared()) {
326 : nexus.Clear();
327 : feedback_updated = true;
328 : }
329 : break;
330 : }
331 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
332 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof: {
333 : LoadGlobalICNexus nexus(this, slot);
334 10823 : if (!nexus.IsCleared()) {
335 : nexus.Clear();
336 : feedback_updated = true;
337 : }
338 : break;
339 : }
340 : case FeedbackSlotKind::kLoadKeyed: {
341 : KeyedLoadICNexus nexus(this, slot);
342 5858 : if (!nexus.IsCleared()) {
343 : nexus.Clear();
344 : feedback_updated = true;
345 : }
346 : break;
347 : }
348 : case FeedbackSlotKind::kStoreNamedSloppy:
349 : case FeedbackSlotKind::kStoreNamedStrict:
350 : case FeedbackSlotKind::kStoreOwnNamed:
351 : case FeedbackSlotKind::kStoreGlobalSloppy:
352 : case FeedbackSlotKind::kStoreGlobalStrict: {
353 : StoreICNexus nexus(this, slot);
354 82948 : if (!nexus.IsCleared()) {
355 : nexus.Clear();
356 : feedback_updated = true;
357 : }
358 : break;
359 : }
360 : case FeedbackSlotKind::kStoreKeyedSloppy:
361 : case FeedbackSlotKind::kStoreKeyedStrict: {
362 : KeyedStoreICNexus nexus(this, slot);
363 6565 : if (!nexus.IsCleared()) {
364 : nexus.Clear();
365 : feedback_updated = true;
366 : }
367 : break;
368 : }
369 : case FeedbackSlotKind::kBinaryOp:
370 : case FeedbackSlotKind::kCompareOp: {
371 : DCHECK(Get(slot)->IsSmi());
372 : // don't clear these smi slots.
373 : // Set(slot, Smi::kZero);
374 : break;
375 : }
376 : case FeedbackSlotKind::kCreateClosure: {
377 : case FeedbackSlotKind::kTypeProfile:
378 : break;
379 : }
380 : case FeedbackSlotKind::kGeneral: {
381 21 : if (obj->IsHeapObject()) {
382 : InstanceType instance_type =
383 : HeapObject::cast(obj)->map()->instance_type();
384 : // AllocationSites are exempt from clearing. They don't store Maps
385 : // or Code pointers which can cause memory leaks if not cleared
386 : // regularly.
387 14 : if (instance_type != ALLOCATION_SITE_TYPE) {
388 : Set(slot, uninitialized_sentinel, SKIP_WRITE_BARRIER);
389 : feedback_updated = true;
390 : }
391 : }
392 : break;
393 : }
394 : case FeedbackSlotKind::kLiteral: {
395 : Set(slot, undefined_value, SKIP_WRITE_BARRIER);
396 : feedback_updated = true;
397 4330 : break;
398 : }
399 : case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
400 : StoreDataPropertyInLiteralICNexus nexus(this, slot);
401 0 : if (!nexus.IsCleared()) {
402 : nexus.Clear();
403 : feedback_updated = true;
404 : }
405 : break;
406 : }
407 : case FeedbackSlotKind::kToBoolean:
408 : case FeedbackSlotKind::kInvalid:
409 : case FeedbackSlotKind::kKindsNumber:
410 0 : UNREACHABLE();
411 : break;
412 : }
413 : }
414 : }
415 92305 : if (feedback_updated) {
416 50380 : IC::OnFeedbackChanged(isolate, host_function);
417 : }
418 92305 : }
419 :
420 553319 : Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
421 : Isolate* isolate = GetIsolate();
422 553319 : Handle<Object> feedback = handle(GetFeedback(), isolate);
423 811200 : if (!feedback->IsFixedArray() ||
424 : FixedArray::cast(*feedback)->length() != length) {
425 514278 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
426 514278 : SetFeedback(*array);
427 514278 : return array;
428 : }
429 : return Handle<FixedArray>::cast(feedback);
430 : }
431 :
432 50592 : Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
433 : Isolate* isolate = GetIsolate();
434 50592 : Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
435 50815 : if (!feedback_extra->IsFixedArray() ||
436 : FixedArray::cast(*feedback_extra)->length() != length) {
437 50369 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
438 50369 : SetFeedbackExtra(*array);
439 50369 : return array;
440 : }
441 : return Handle<FixedArray>::cast(feedback_extra);
442 : }
443 :
444 0 : void FeedbackNexus::ConfigureUninitialized() {
445 : SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()),
446 0 : SKIP_WRITE_BARRIER);
447 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
448 0 : SKIP_WRITE_BARRIER);
449 0 : }
450 :
451 5003348 : void FeedbackNexus::ConfigurePremonomorphic() {
452 : SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
453 5003348 : SKIP_WRITE_BARRIER);
454 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
455 5003348 : SKIP_WRITE_BARRIER);
456 5003348 : }
457 :
458 105967 : void FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
459 : Isolate* isolate = GetIsolate();
460 : SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate),
461 105967 : SKIP_WRITE_BARRIER);
462 105967 : SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
463 105967 : SKIP_WRITE_BARRIER);
464 105967 : }
465 :
466 5807330 : InlineCacheState LoadICNexus::StateFromFeedback() const {
467 : Isolate* isolate = GetIsolate();
468 5807330 : Object* feedback = GetFeedback();
469 :
470 5807330 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
471 : return UNINITIALIZED;
472 4205784 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
473 : return MEGAMORPHIC;
474 3826789 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
475 : return PREMONOMORPHIC;
476 2021546 : } else if (feedback->IsFixedArray()) {
477 : // Determine state purely by our structure, don't check if the maps are
478 : // cleared.
479 : return POLYMORPHIC;
480 1718211 : } else if (feedback->IsWeakCell()) {
481 : // Don't check if the map is cleared.
482 : return MONOMORPHIC;
483 : }
484 :
485 0 : return UNINITIALIZED;
486 : }
487 :
488 2105411 : InlineCacheState LoadGlobalICNexus::StateFromFeedback() const {
489 : Isolate* isolate = GetIsolate();
490 2105411 : Object* feedback = GetFeedback();
491 :
492 2105411 : Object* extra = GetFeedbackExtra();
493 4200854 : if (!WeakCell::cast(feedback)->cleared() ||
494 : extra != *FeedbackVector::UninitializedSentinel(isolate)) {
495 : return MONOMORPHIC;
496 : }
497 2095186 : return UNINITIALIZED;
498 : }
499 :
500 945376 : InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
501 : Isolate* isolate = GetIsolate();
502 945376 : Object* feedback = GetFeedback();
503 :
504 945376 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
505 : return UNINITIALIZED;
506 390952 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
507 : return PREMONOMORPHIC;
508 345298 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
509 : return MEGAMORPHIC;
510 152813 : } else if (feedback->IsFixedArray()) {
511 : // Determine state purely by our structure, don't check if the maps are
512 : // cleared.
513 : return POLYMORPHIC;
514 132735 : } else if (feedback->IsWeakCell()) {
515 : // Don't check if the map is cleared.
516 : return MONOMORPHIC;
517 23712 : } else if (feedback->IsName()) {
518 23712 : Object* extra = GetFeedbackExtra();
519 : FixedArray* extra_array = FixedArray::cast(extra);
520 23712 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
521 : }
522 :
523 : return UNINITIALIZED;
524 : }
525 :
526 6213955 : InlineCacheState StoreICNexus::StateFromFeedback() const {
527 : Isolate* isolate = GetIsolate();
528 6213955 : Object* feedback = GetFeedback();
529 :
530 6213955 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
531 : return UNINITIALIZED;
532 1813935 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
533 : return MEGAMORPHIC;
534 1378082 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
535 : return PREMONOMORPHIC;
536 697968 : } else if (feedback->IsFixedArray()) {
537 : // Determine state purely by our structure, don't check if the maps are
538 : // cleared.
539 : return POLYMORPHIC;
540 547944 : } else if (feedback->IsWeakCell()) {
541 : // Don't check if the map is cleared.
542 : return MONOMORPHIC;
543 : }
544 :
545 0 : return UNINITIALIZED;
546 : }
547 :
548 796174 : InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
549 : Isolate* isolate = GetIsolate();
550 796174 : Object* feedback = GetFeedback();
551 :
552 796174 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
553 : return UNINITIALIZED;
554 350994 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
555 : return PREMONOMORPHIC;
556 329122 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
557 : return MEGAMORPHIC;
558 92485 : } else if (feedback->IsFixedArray()) {
559 : // Determine state purely by our structure, don't check if the maps are
560 : // cleared.
561 : return POLYMORPHIC;
562 79308 : } else if (feedback->IsWeakCell()) {
563 : // Don't check if the map is cleared.
564 : return MONOMORPHIC;
565 12355 : } else if (feedback->IsName()) {
566 12355 : Object* extra = GetFeedbackExtra();
567 : FixedArray* extra_array = FixedArray::cast(extra);
568 12355 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
569 : }
570 :
571 : return UNINITIALIZED;
572 : }
573 :
574 403553 : InlineCacheState CallICNexus::StateFromFeedback() const {
575 : Isolate* isolate = GetIsolate();
576 403553 : Object* feedback = GetFeedback();
577 : DCHECK(GetFeedbackExtra() ==
578 : *FeedbackVector::UninitializedSentinel(isolate) ||
579 : GetFeedbackExtra()->IsSmi());
580 :
581 403553 : if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
582 : return GENERIC;
583 786173 : } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
584 : return MONOMORPHIC;
585 : }
586 :
587 357387 : CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate));
588 : return UNINITIALIZED;
589 : }
590 :
591 640043 : int CallICNexus::ExtractCallCount() {
592 640043 : Object* call_count = GetFeedbackExtra();
593 640043 : CHECK(call_count->IsSmi());
594 : int value = Smi::cast(call_count)->value();
595 640043 : return value;
596 : }
597 :
598 640023 : float CallICNexus::ComputeCallFrequency() {
599 640023 : double const invocation_count = vector()->invocation_count();
600 640023 : double const call_count = ExtractCallCount();
601 640023 : if (invocation_count == 0) {
602 : // Prevent division by 0.
603 : return 0.0f;
604 : }
605 215360 : return static_cast<float>(call_count / invocation_count);
606 : }
607 :
608 13602 : void CallICNexus::ConfigureUninitialized() {
609 : Isolate* isolate = GetIsolate();
610 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
611 13602 : SKIP_WRITE_BARRIER);
612 13602 : SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
613 13602 : }
614 :
615 9413 : void LoadGlobalICNexus::ConfigureUninitialized() {
616 : Isolate* isolate = GetIsolate();
617 9413 : SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
618 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
619 9413 : SKIP_WRITE_BARRIER);
620 9413 : }
621 :
622 3896330 : void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
623 : Isolate* isolate = GetIsolate();
624 7792662 : SetFeedback(*isolate->factory()->NewWeakCell(cell));
625 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
626 3896332 : SKIP_WRITE_BARRIER);
627 3896332 : }
628 :
629 59462 : void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) {
630 59462 : SetFeedback(GetIsolate()->heap()->empty_weak_cell());
631 59462 : SetFeedbackExtra(*handler);
632 59462 : }
633 :
634 4676883 : void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
635 : Handle<Map> receiver_map,
636 : Handle<Object> handler) {
637 4676883 : Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
638 4676885 : if (name.is_null()) {
639 4626293 : SetFeedback(*cell);
640 4626293 : SetFeedbackExtra(*handler);
641 : } else {
642 50592 : Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
643 50592 : SetFeedback(*name);
644 50592 : array->set(0, *cell);
645 50592 : array->set(1, *handler);
646 : }
647 4676885 : }
648 :
649 553319 : void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
650 : List<Handle<Object>>* handlers) {
651 : int receiver_count = maps->length();
652 : DCHECK(receiver_count > 1);
653 : Handle<FixedArray> array;
654 553319 : if (name.is_null()) {
655 553319 : array = EnsureArrayOfSize(receiver_count * 2);
656 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
657 553319 : SKIP_WRITE_BARRIER);
658 : } else {
659 0 : array = EnsureExtraArrayOfSize(receiver_count * 2);
660 0 : SetFeedback(*name);
661 : }
662 :
663 2037601 : for (int current = 0; current < receiver_count; ++current) {
664 1484282 : Handle<Map> map = maps->at(current);
665 1484282 : Handle<WeakCell> cell = Map::WeakCellForMap(map);
666 2968564 : array->set(current * 2, *cell);
667 2968564 : array->set(current * 2 + 1, *handlers->at(current));
668 : }
669 553319 : }
670 :
671 3215685 : int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
672 : Isolate* isolate = GetIsolate();
673 3215685 : Object* feedback = GetFeedback();
674 3215685 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
675 3215686 : if (feedback->IsFixedArray() || is_named_feedback) {
676 : int found = 0;
677 442600 : if (is_named_feedback) {
678 8177 : feedback = GetFeedbackExtra();
679 : }
680 : FixedArray* array = FixedArray::cast(feedback);
681 : const int increment = 2;
682 3302296 : for (int i = 0; i < array->length(); i += increment) {
683 : DCHECK(array->get(i)->IsWeakCell());
684 : WeakCell* cell = WeakCell::cast(array->get(i));
685 1208548 : if (!cell->cleared()) {
686 : Map* map = Map::cast(cell->value());
687 887281 : maps->Add(handle(map, isolate));
688 887281 : found++;
689 : }
690 : }
691 : return found;
692 2773086 : } else if (feedback->IsWeakCell()) {
693 : WeakCell* cell = WeakCell::cast(feedback);
694 2120521 : if (!cell->cleared()) {
695 : Map* map = Map::cast(cell->value());
696 840393 : maps->Add(handle(map, isolate));
697 840393 : return 1;
698 : }
699 : }
700 :
701 : return 0;
702 : }
703 :
704 2206753 : MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
705 2206753 : Object* feedback = GetFeedback();
706 : Isolate* isolate = GetIsolate();
707 2206753 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
708 2206753 : if (feedback->IsFixedArray() || is_named_feedback) {
709 395936 : if (is_named_feedback) {
710 7305 : feedback = GetFeedbackExtra();
711 : }
712 : FixedArray* array = FixedArray::cast(feedback);
713 : const int increment = 2;
714 2860752 : for (int i = 0; i < array->length(); i += increment) {
715 : DCHECK(array->get(i)->IsWeakCell());
716 : WeakCell* cell = WeakCell::cast(array->get(i));
717 1063105 : if (!cell->cleared()) {
718 : Map* array_map = Map::cast(cell->value());
719 743465 : if (array_map == *map) {
720 28665 : Object* code = array->get(i + increment - 1);
721 : DCHECK(IC::IsHandler(code));
722 : return handle(code, isolate);
723 : }
724 : }
725 : }
726 1810817 : } else if (feedback->IsWeakCell()) {
727 : WeakCell* cell = WeakCell::cast(feedback);
728 1810817 : if (!cell->cleared()) {
729 : Map* cell_map = Map::cast(cell->value());
730 538776 : if (cell_map == *map) {
731 81567 : Object* code = GetFeedbackExtra();
732 : DCHECK(IC::IsHandler(code));
733 : return handle(code, isolate);
734 : }
735 : }
736 : }
737 :
738 : return MaybeHandle<Code>();
739 : }
740 :
741 2279195 : bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
742 : int length) const {
743 2279195 : Object* feedback = GetFeedback();
744 : Isolate* isolate = GetIsolate();
745 : int count = 0;
746 2279195 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
747 2279195 : if (feedback->IsFixedArray() || is_named_feedback) {
748 396864 : if (is_named_feedback) {
749 255 : feedback = GetFeedbackExtra();
750 : }
751 : FixedArray* array = FixedArray::cast(feedback);
752 : const int increment = 2;
753 3000158 : for (int i = 0; i < array->length(); i += increment) {
754 : DCHECK(array->get(i)->IsWeakCell());
755 : WeakCell* cell = WeakCell::cast(array->get(i));
756 : // Be sure to skip handlers whose maps have been cleared.
757 1103215 : if (!cell->cleared()) {
758 783603 : Object* code = array->get(i + increment - 1);
759 : DCHECK(IC::IsHandler(code));
760 783603 : code_list->Add(handle(code, isolate));
761 783603 : count++;
762 : }
763 : }
764 1882331 : } else if (feedback->IsWeakCell()) {
765 : WeakCell* cell = WeakCell::cast(feedback);
766 1848588 : if (!cell->cleared()) {
767 578480 : Object* code = GetFeedbackExtra();
768 : DCHECK(IC::IsHandler(code));
769 578480 : code_list->Add(handle(code, isolate));
770 : count++;
771 : }
772 : }
773 2279195 : return count == length;
774 : }
775 :
776 119401 : Name* KeyedLoadICNexus::FindFirstName() const {
777 119401 : Object* feedback = GetFeedback();
778 119401 : if (IsPropertyNameFeedback(feedback)) {
779 20927 : return Name::cast(feedback);
780 : }
781 : return NULL;
782 : }
783 :
784 34404 : Name* KeyedStoreICNexus::FindFirstName() const {
785 34404 : Object* feedback = GetFeedback();
786 34404 : if (IsPropertyNameFeedback(feedback)) {
787 11437 : return Name::cast(feedback);
788 : }
789 : return NULL;
790 : }
791 :
792 81621 : KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
793 : KeyedAccessStoreMode mode = STANDARD_STORE;
794 : MapHandleList maps;
795 : List<Handle<Object>> handlers;
796 :
797 81621 : if (GetKeyType() == PROPERTY) return mode;
798 :
799 80802 : ExtractMaps(&maps);
800 80802 : FindHandlers(&handlers, maps.length());
801 80843 : for (int i = 0; i < handlers.length(); i++) {
802 : // The first handler that isn't the slow handler will have the bits we need.
803 47100 : Handle<Object> maybe_code_handler = handlers.at(i);
804 : Handle<Code> handler;
805 47100 : if (maybe_code_handler->IsTuple3()) {
806 : // Elements transition.
807 : Handle<Tuple3> data_handler = Handle<Tuple3>::cast(maybe_code_handler);
808 : handler = handle(Code::cast(data_handler->value2()));
809 47082 : } else if (maybe_code_handler->IsTuple2()) {
810 : // Element store with prototype chain check.
811 : Handle<Tuple2> data_handler = Handle<Tuple2>::cast(maybe_code_handler);
812 : handler = handle(Code::cast(data_handler->value2()));
813 : } else {
814 : // Element store without prototype chain check.
815 : handler = Handle<Code>::cast(maybe_code_handler);
816 : }
817 : CodeStub::Major major_key = CodeStub::MajorKeyFromKey(handler->stub_key());
818 : uint32_t minor_key = CodeStub::MinorKeyFromKey(handler->stub_key());
819 47100 : CHECK(major_key == CodeStub::KeyedStoreSloppyArguments ||
820 : major_key == CodeStub::StoreFastElement ||
821 : major_key == CodeStub::StoreSlowElement ||
822 : major_key == CodeStub::ElementsTransitionAndStore ||
823 : major_key == CodeStub::NoCache);
824 47100 : if (major_key != CodeStub::NoCache) {
825 : mode = CommonStoreModeBits::decode(minor_key);
826 : break;
827 : }
828 : }
829 :
830 80802 : return mode;
831 : }
832 :
833 42136 : IcCheckType KeyedLoadICNexus::GetKeyType() const {
834 42136 : Object* feedback = GetFeedback();
835 42136 : if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
836 10894 : return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
837 : }
838 36689 : return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
839 : }
840 :
841 97241 : IcCheckType KeyedStoreICNexus::GetKeyType() const {
842 97241 : Object* feedback = GetFeedback();
843 97241 : if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
844 3820 : return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
845 : }
846 95331 : return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
847 : }
848 :
849 0 : InlineCacheState BinaryOpICNexus::StateFromFeedback() const {
850 : BinaryOperationHint hint = GetBinaryOperationFeedback();
851 0 : if (hint == BinaryOperationHint::kNone) {
852 : return UNINITIALIZED;
853 0 : } else if (hint == BinaryOperationHint::kAny) {
854 : return GENERIC;
855 : }
856 :
857 0 : return MONOMORPHIC;
858 : }
859 :
860 0 : InlineCacheState CompareICNexus::StateFromFeedback() const {
861 : CompareOperationHint hint = GetCompareOperationFeedback();
862 0 : if (hint == CompareOperationHint::kNone) {
863 : return UNINITIALIZED;
864 0 : } else if (hint == CompareOperationHint::kAny) {
865 : return GENERIC;
866 : }
867 :
868 0 : return MONOMORPHIC;
869 : }
870 :
871 754915 : BinaryOperationHint BinaryOpICNexus::GetBinaryOperationFeedback() const {
872 754915 : int feedback = Smi::cast(GetFeedback())->value();
873 754915 : return BinaryOperationHintFromFeedback(feedback);
874 : }
875 :
876 903968 : CompareOperationHint CompareICNexus::GetCompareOperationFeedback() const {
877 903968 : int feedback = Smi::cast(GetFeedback())->value();
878 903968 : return CompareOperationHintFromFeedback(feedback);
879 : }
880 :
881 394885 : InlineCacheState StoreDataPropertyInLiteralICNexus::StateFromFeedback() const {
882 : Isolate* isolate = GetIsolate();
883 394885 : Object* feedback = GetFeedback();
884 :
885 394885 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
886 : return UNINITIALIZED;
887 32928 : } else if (feedback->IsWeakCell()) {
888 : // Don't check if the map is cleared.
889 : return MONOMORPHIC;
890 : }
891 :
892 4458 : return MEGAMORPHIC;
893 : }
894 :
895 317703 : void StoreDataPropertyInLiteralICNexus::ConfigureMonomorphic(
896 : Handle<Name> name, Handle<Map> receiver_map) {
897 317703 : Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
898 :
899 317703 : SetFeedback(*cell);
900 317703 : SetFeedbackExtra(*name);
901 317703 : }
902 :
903 0 : InlineCacheState CollectTypeProfileNexus::StateFromFeedback() const {
904 : Isolate* isolate = GetIsolate();
905 0 : Object* const feedback = GetFeedback();
906 :
907 0 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
908 : return UNINITIALIZED;
909 : }
910 0 : return MONOMORPHIC;
911 : }
912 :
913 1818 : void CollectTypeProfileNexus::Collect(Handle<String> type, int position) {
914 : DCHECK_GE(position, 0);
915 : Isolate* isolate = GetIsolate();
916 :
917 1818 : Object* const feedback = GetFeedback();
918 :
919 : // Map source position to collection of types
920 : Handle<UnseededNumberDictionary> types;
921 :
922 1818 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
923 198 : types = UnseededNumberDictionary::NewEmpty(isolate);
924 : } else {
925 : types = Handle<UnseededNumberDictionary>(
926 : UnseededNumberDictionary::cast(feedback), isolate);
927 : }
928 :
929 : Handle<ArrayList> position_specific_types;
930 :
931 3636 : if (types->Has(position)) {
932 : int entry = types->FindEntry(position);
933 : DCHECK(types->ValueAt(entry)->IsArrayList());
934 : position_specific_types =
935 2850 : Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)));
936 : } else {
937 393 : position_specific_types = ArrayList::New(isolate, 1);
938 : }
939 :
940 : types = UnseededNumberDictionary::Set(
941 3636 : types, position, ArrayList::Add(position_specific_types, type));
942 1818 : SetFeedback(*types);
943 1818 : }
944 :
945 : namespace {
946 :
947 90 : Handle<JSObject> ConvertToJSObject(Isolate* isolate,
948 : Handle<UnseededNumberDictionary> feedback) {
949 : Handle<JSObject> type_profile =
950 90 : isolate->factory()->NewJSObject(isolate->object_function());
951 :
952 1020 : for (int index = UnseededNumberDictionary::kElementsStartIndex;
953 : index < feedback->length();
954 : index += UnseededNumberDictionary::kEntrySize) {
955 : int key_index = index + UnseededNumberDictionary::kEntryKeyIndex;
956 : Object* key = feedback->get(key_index);
957 420 : if (key->IsSmi()) {
958 210 : int value_index = index + UnseededNumberDictionary::kEntryValueIndex;
959 :
960 : Handle<ArrayList> position_specific_types = Handle<ArrayList>(
961 : ArrayList::cast(feedback->get(value_index)), isolate);
962 :
963 : int position = Smi::cast(key)->value();
964 : JSObject::AddDataElement(type_profile, position,
965 : isolate->factory()->NewJSArrayWithElements(
966 : position_specific_types->Elements()),
967 : PropertyAttributes::NONE)
968 630 : .ToHandleChecked();
969 : }
970 : }
971 90 : return type_profile;
972 : }
973 : } // namespace
974 :
975 98 : JSObject* CollectTypeProfileNexus::GetTypeProfile() const {
976 : Isolate* isolate = GetIsolate();
977 :
978 98 : Object* const feedback = GetFeedback();
979 :
980 98 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
981 16 : return *isolate->factory()->NewJSMap();
982 : }
983 :
984 : return *ConvertToJSObject(
985 : isolate, Handle<UnseededNumberDictionary>(
986 180 : UnseededNumberDictionary::cast(feedback), isolate));
987 : }
988 :
989 : } // namespace internal
990 : } // namespace v8
|