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 4632039 : bool FeedbackVectorSpec::HasTypeProfileSlot() const {
16 : FeedbackSlot slot =
17 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
18 4632039 : if (slots() <= slot.ToInt()) {
19 : return false;
20 : }
21 3816068 : return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
22 : }
23 :
24 7965872 : static bool IsPropertyNameFeedback(Object* feedback) {
25 7965872 : if (feedback->IsString()) return true;
26 7917570 : if (!feedback->IsSymbol()) return false;
27 : Symbol* symbol = Symbol::cast(feedback);
28 854911 : Heap* heap = symbol->GetHeap();
29 48018 : return symbol != heap->uninitialized_symbol() &&
30 806893 : symbol != heap->premonomorphic_symbol() &&
31 795669 : 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 109682557 : FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
39 : int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
40 : int data = Smi::cast(get(index))->value();
41 219365114 : return VectorICComputer::decode(data, slot.ToInt());
42 : }
43 :
44 47463609 : void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
45 : int index = VectorICComputer::index(kReservedIndexCount, slot.ToInt());
46 : int data = Smi::cast(get(index))->value();
47 94927218 : int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
48 : set(index, Smi::FromInt(new_data));
49 47463609 : }
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 14007186 : 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 14007186 : const int length = slot_kinds_length + kReservedIndexCount;
65 14007186 : 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 2624246 : Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
81 : array->set(kSlotsCountIndex, Smi::FromInt(slot_count));
82 : // Fill the bit-vector part with zeros.
83 11912002 : 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 47463608 : for (int i = 0; i < slot_count; i++) {
90 : FeedbackSlot slot(i);
91 : FeedbackSlotKind kind = spec->GetKind(slot);
92 47463612 : 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 5248494 : metadata->set_map(isolate->heap()->fixed_cow_array_map());
101 :
102 2624247 : return metadata;
103 : }
104 :
105 3778010 : bool FeedbackMetadata::SpecDiffersFrom(
106 : const FeedbackVectorSpec* other_spec) const {
107 3778010 : if (other_spec->slots() != slot_count()) {
108 : return true;
109 : }
110 :
111 3778013 : int slots = slot_count();
112 39846150 : for (int i = 0; i < slots;) {
113 : FeedbackSlot slot(i);
114 32290107 : FeedbackSlotKind kind = GetKind(slot);
115 32290107 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
116 :
117 32290123 : if (kind != other_spec->GetKind(slot)) {
118 : return true;
119 : }
120 32290126 : 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 387622 : bool FeedbackMetadata::HasTypeProfileSlot() const {
177 : FeedbackSlot slot =
178 387622 : FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
179 387622 : return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
180 : }
181 :
182 33027861 : FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
183 : DCHECK(!is_empty());
184 33027861 : 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 8721160 : Handle<FeedbackVector> FeedbackVector::New(Isolate* isolate,
197 : Handle<SharedFunctionInfo> shared) {
198 : Factory* factory = isolate->factory();
199 :
200 8721160 : const int slot_count = shared->feedback_metadata()->slot_count();
201 8721167 : const int length = slot_count + kReservedIndexCount;
202 :
203 8721167 : Handle<FixedArray> array = factory->NewFixedArray(length, TENURED);
204 8721170 : array->set_map_no_write_barrier(isolate->heap()->feedback_vector_map());
205 8721170 : 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 58712871 : for (int i = 0; i < slot_count;) {
213 : FeedbackSlot slot(i);
214 41270527 : FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
215 : int index = FeedbackVector::GetIndex(slot);
216 41270527 : int entry_size = FeedbackMetadata::GetSlotSize(kind);
217 :
218 : Object* extra_value = *uninitialized_sentinel;
219 41270524 : switch (kind) {
220 : case FeedbackSlotKind::kLoadGlobalInsideTypeof:
221 : case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
222 5737142 : array->set(index, isolate->heap()->empty_weak_cell(),
223 5737142 : SKIP_WRITE_BARRIER);
224 5737142 : break;
225 : case FeedbackSlotKind::kCompareOp:
226 : case FeedbackSlotKind::kBinaryOp:
227 : case FeedbackSlotKind::kToBoolean:
228 6084462 : array->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
229 6084462 : break;
230 : case FeedbackSlotKind::kCreateClosure: {
231 7466814 : Handle<Cell> cell = factory->NewNoClosuresCell(undefined_value);
232 7466815 : array->set(index, *cell);
233 : break;
234 : }
235 : case FeedbackSlotKind::kLiteral:
236 1844097 : array->set(index, *undefined_value, SKIP_WRITE_BARRIER);
237 1844097 : break;
238 : case FeedbackSlotKind::kCall:
239 6250745 : array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
240 : extra_value = Smi::kZero;
241 6250743 : 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 13887284 : array->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
255 13887282 : 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 67130530 : for (int j = 1; j < entry_size; j++) {
264 51720018 : array->set(index + j, extra_value, SKIP_WRITE_BARRIER);
265 : }
266 41270521 : i += entry_size;
267 : }
268 :
269 : Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(array);
270 8721169 : if (!isolate->is_best_effort_code_coverage()) {
271 436 : AddToCodeCoverageList(isolate, result);
272 : }
273 8721169 : return result;
274 : }
275 :
276 : // static
277 370868 : Handle<FeedbackVector> FeedbackVector::Copy(Isolate* isolate,
278 : Handle<FeedbackVector> vector) {
279 : Handle<FeedbackVector> result;
280 : result = Handle<FeedbackVector>::cast(
281 370868 : isolate->factory()->CopyFixedArray(Handle<FixedArray>::cast(vector)));
282 370868 : if (!isolate->is_best_effort_code_coverage()) {
283 2 : AddToCodeCoverageList(isolate, result);
284 : }
285 370868 : 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 91981 : void FeedbackVector::ClearSlots(JSFunction* host_function) {
300 : Isolate* isolate = GetIsolate();
301 :
302 : Object* uninitialized_sentinel =
303 : FeedbackVector::RawUninitializedSentinel(isolate);
304 91981 : Oddball* undefined_value = isolate->heap()->undefined_value();
305 :
306 : bool feedback_updated = false;
307 : FeedbackMetadataIterator iter(metadata());
308 364819 : while (iter.HasNext()) {
309 272838 : FeedbackSlot slot = iter.Next();
310 272838 : FeedbackSlotKind kind = iter.kind();
311 :
312 : Object* obj = Get(slot);
313 272838 : if (obj != uninitialized_sentinel) {
314 237533 : switch (kind) {
315 : case FeedbackSlotKind::kCall: {
316 : CallICNexus nexus(this, slot);
317 13515 : if (!nexus.IsCleared()) {
318 : nexus.Clear();
319 : feedback_updated = true;
320 : }
321 : break;
322 : }
323 : case FeedbackSlotKind::kLoadProperty: {
324 : LoadICNexus nexus(this, slot);
325 39995 : 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 5792 : 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 82642 : 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 6415 : 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 4138 : 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 91981 : if (feedback_updated) {
416 50227 : IC::OnFeedbackChanged(isolate, host_function);
417 : }
418 91981 : }
419 :
420 550641 : Handle<FixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
421 : Isolate* isolate = GetIsolate();
422 550641 : Handle<Object> feedback = handle(GetFeedback(), isolate);
423 806776 : if (!feedback->IsFixedArray() ||
424 : FixedArray::cast(*feedback)->length() != length) {
425 511651 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
426 511651 : SetFeedback(*array);
427 511651 : return array;
428 : }
429 : return Handle<FixedArray>::cast(feedback);
430 : }
431 :
432 50282 : Handle<FixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
433 : Isolate* isolate = GetIsolate();
434 50282 : Handle<Object> feedback_extra = handle(GetFeedbackExtra(), isolate);
435 50505 : if (!feedback_extra->IsFixedArray() ||
436 : FixedArray::cast(*feedback_extra)->length() != length) {
437 50059 : Handle<FixedArray> array = isolate->factory()->NewFixedArray(length);
438 50059 : SetFeedbackExtra(*array);
439 50059 : 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 4997771 : void FeedbackNexus::ConfigurePremonomorphic() {
452 : SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
453 4997771 : SKIP_WRITE_BARRIER);
454 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
455 4997771 : SKIP_WRITE_BARRIER);
456 4997771 : }
457 :
458 104990 : void FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
459 : Isolate* isolate = GetIsolate();
460 : SetFeedback(*FeedbackVector::MegamorphicSentinel(isolate),
461 104990 : SKIP_WRITE_BARRIER);
462 104990 : SetFeedbackExtra(Smi::FromInt(static_cast<int>(property_type)),
463 104990 : SKIP_WRITE_BARRIER);
464 104990 : }
465 :
466 5790240 : InlineCacheState LoadICNexus::StateFromFeedback() const {
467 : Isolate* isolate = GetIsolate();
468 5790240 : Object* feedback = GetFeedback();
469 :
470 5790240 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
471 : return UNINITIALIZED;
472 4191955 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
473 : return MEGAMORPHIC;
474 3813264 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
475 : return PREMONOMORPHIC;
476 2013086 : } else if (feedback->IsFixedArray()) {
477 : // Determine state purely by our structure, don't check if the maps are
478 : // cleared.
479 : return POLYMORPHIC;
480 1713393 : } 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 2103217 : InlineCacheState LoadGlobalICNexus::StateFromFeedback() const {
489 : Isolate* isolate = GetIsolate();
490 2103217 : Object* feedback = GetFeedback();
491 :
492 2103217 : Object* extra = GetFeedbackExtra();
493 4196460 : if (!WeakCell::cast(feedback)->cleared() ||
494 : extra != *FeedbackVector::UninitializedSentinel(isolate)) {
495 : return MONOMORPHIC;
496 : }
497 2092988 : return UNINITIALIZED;
498 : }
499 :
500 941541 : InlineCacheState KeyedLoadICNexus::StateFromFeedback() const {
501 : Isolate* isolate = GetIsolate();
502 941541 : Object* feedback = GetFeedback();
503 :
504 941541 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
505 : return UNINITIALIZED;
506 388114 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
507 : return PREMONOMORPHIC;
508 342646 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
509 : return MEGAMORPHIC;
510 151863 : } else if (feedback->IsFixedArray()) {
511 : // Determine state purely by our structure, don't check if the maps are
512 : // cleared.
513 : return POLYMORPHIC;
514 132173 : } else if (feedback->IsWeakCell()) {
515 : // Don't check if the map is cleared.
516 : return MONOMORPHIC;
517 23554 : } else if (feedback->IsName()) {
518 23554 : Object* extra = GetFeedbackExtra();
519 : FixedArray* extra_array = FixedArray::cast(extra);
520 23554 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
521 : }
522 :
523 : return UNINITIALIZED;
524 : }
525 :
526 6205623 : InlineCacheState StoreICNexus::StateFromFeedback() const {
527 : Isolate* isolate = GetIsolate();
528 6205623 : Object* feedback = GetFeedback();
529 :
530 6205623 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
531 : return UNINITIALIZED;
532 1810100 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
533 : return MEGAMORPHIC;
534 1374900 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
535 : return PREMONOMORPHIC;
536 695729 : } else if (feedback->IsFixedArray()) {
537 : // Determine state purely by our structure, don't check if the maps are
538 : // cleared.
539 : return POLYMORPHIC;
540 546659 : } 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 794965 : InlineCacheState KeyedStoreICNexus::StateFromFeedback() const {
549 : Isolate* isolate = GetIsolate();
550 794965 : Object* feedback = GetFeedback();
551 :
552 794965 : if (feedback == *FeedbackVector::UninitializedSentinel(isolate)) {
553 : return UNINITIALIZED;
554 350411 : } else if (feedback == *FeedbackVector::PremonomorphicSentinel(isolate)) {
555 : return PREMONOMORPHIC;
556 328836 : } else if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
557 : return MEGAMORPHIC;
558 92268 : } else if (feedback->IsFixedArray()) {
559 : // Determine state purely by our structure, don't check if the maps are
560 : // cleared.
561 : return POLYMORPHIC;
562 79186 : } else if (feedback->IsWeakCell()) {
563 : // Don't check if the map is cleared.
564 : return MONOMORPHIC;
565 12343 : } else if (feedback->IsName()) {
566 12343 : Object* extra = GetFeedbackExtra();
567 : FixedArray* extra_array = FixedArray::cast(extra);
568 12343 : return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
569 : }
570 :
571 : return UNINITIALIZED;
572 : }
573 :
574 403567 : InlineCacheState CallICNexus::StateFromFeedback() const {
575 : Isolate* isolate = GetIsolate();
576 403567 : Object* feedback = GetFeedback();
577 : DCHECK(GetFeedbackExtra() ==
578 : *FeedbackVector::UninitializedSentinel(isolate) ||
579 : GetFeedbackExtra()->IsSmi());
580 :
581 403567 : if (feedback == *FeedbackVector::MegamorphicSentinel(isolate)) {
582 : return GENERIC;
583 785821 : } else if (feedback->IsAllocationSite() || feedback->IsWeakCell()) {
584 : return MONOMORPHIC;
585 : }
586 :
587 357291 : CHECK(feedback == *FeedbackVector::UninitializedSentinel(isolate));
588 : return UNINITIALIZED;
589 : }
590 :
591 639611 : int CallICNexus::ExtractCallCount() {
592 639611 : Object* call_count = GetFeedbackExtra();
593 639611 : CHECK(call_count->IsSmi());
594 : int value = Smi::cast(call_count)->value();
595 639611 : return value;
596 : }
597 :
598 639591 : float CallICNexus::ComputeCallFrequency() {
599 639591 : double const invocation_count = vector()->invocation_count();
600 639591 : double const call_count = ExtractCallCount();
601 639591 : if (invocation_count == 0) {
602 : // Prevent division by 0.
603 : return 0.0f;
604 : }
605 215460 : return static_cast<float>(call_count / invocation_count);
606 : }
607 :
608 13515 : void CallICNexus::ConfigureUninitialized() {
609 : Isolate* isolate = GetIsolate();
610 : SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
611 13515 : SKIP_WRITE_BARRIER);
612 13515 : SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
613 13515 : }
614 :
615 9415 : void LoadGlobalICNexus::ConfigureUninitialized() {
616 : Isolate* isolate = GetIsolate();
617 9415 : SetFeedback(isolate->heap()->empty_weak_cell(), SKIP_WRITE_BARRIER);
618 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
619 9415 : SKIP_WRITE_BARRIER);
620 9415 : }
621 :
622 3892954 : void LoadGlobalICNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
623 : Isolate* isolate = GetIsolate();
624 7785908 : SetFeedback(*isolate->factory()->NewWeakCell(cell));
625 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
626 3892955 : SKIP_WRITE_BARRIER);
627 3892955 : }
628 :
629 59450 : void LoadGlobalICNexus::ConfigureHandlerMode(Handle<Object> handler) {
630 59450 : SetFeedback(GetIsolate()->heap()->empty_weak_cell());
631 59450 : SetFeedbackExtra(*handler);
632 59450 : }
633 :
634 4668544 : void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
635 : Handle<Map> receiver_map,
636 : Handle<Object> handler) {
637 4668544 : Handle<WeakCell> cell = Map::WeakCellForMap(receiver_map);
638 4668544 : if (name.is_null()) {
639 4618262 : SetFeedback(*cell);
640 4618262 : SetFeedbackExtra(*handler);
641 : } else {
642 50282 : Handle<FixedArray> array = EnsureExtraArrayOfSize(2);
643 50282 : SetFeedback(*name);
644 50282 : array->set(0, *cell);
645 50282 : array->set(1, *handler);
646 : }
647 4668544 : }
648 :
649 550641 : 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 550641 : if (name.is_null()) {
655 550641 : array = EnsureArrayOfSize(receiver_count * 2);
656 : SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
657 550641 : SKIP_WRITE_BARRIER);
658 : } else {
659 0 : array = EnsureExtraArrayOfSize(receiver_count * 2);
660 0 : SetFeedback(*name);
661 : }
662 :
663 2026910 : for (int current = 0; current < receiver_count; ++current) {
664 1476269 : Handle<Map> map = maps->at(current);
665 1476269 : Handle<WeakCell> cell = Map::WeakCellForMap(map);
666 2952538 : array->set(current * 2, *cell);
667 2952538 : array->set(current * 2 + 1, *handlers->at(current));
668 : }
669 550641 : }
670 :
671 3205725 : int FeedbackNexus::ExtractMaps(MapHandleList* maps) const {
672 : Isolate* isolate = GetIsolate();
673 3205725 : Object* feedback = GetFeedback();
674 3205725 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
675 3205725 : if (feedback->IsFixedArray() || is_named_feedback) {
676 : int found = 0;
677 439006 : if (is_named_feedback) {
678 8151 : feedback = GetFeedbackExtra();
679 : }
680 : FixedArray* array = FixedArray::cast(feedback);
681 : const int increment = 2;
682 3274244 : for (int i = 0; i < array->length(); i += increment) {
683 : DCHECK(array->get(i)->IsWeakCell());
684 : WeakCell* cell = WeakCell::cast(array->get(i));
685 1198116 : if (!cell->cleared()) {
686 : Map* map = Map::cast(cell->value());
687 877252 : maps->Add(handle(map, isolate));
688 877252 : found++;
689 : }
690 : }
691 : return found;
692 2766719 : } else if (feedback->IsWeakCell()) {
693 : WeakCell* cell = WeakCell::cast(feedback);
694 2115388 : if (!cell->cleared()) {
695 : Map* map = Map::cast(cell->value());
696 837352 : maps->Add(handle(map, isolate));
697 837352 : return 1;
698 : }
699 : }
700 :
701 : return 0;
702 : }
703 :
704 2201497 : MaybeHandle<Object> FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
705 2201497 : Object* feedback = GetFeedback();
706 : Isolate* isolate = GetIsolate();
707 2201497 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
708 2201497 : if (feedback->IsFixedArray() || is_named_feedback) {
709 394002 : if (is_named_feedback) {
710 7287 : feedback = GetFeedbackExtra();
711 : }
712 : FixedArray* array = FixedArray::cast(feedback);
713 : const int increment = 2;
714 2845244 : for (int i = 0; i < array->length(); i += increment) {
715 : DCHECK(array->get(i)->IsWeakCell());
716 : WeakCell* cell = WeakCell::cast(array->get(i));
717 1057226 : if (!cell->cleared()) {
718 : Map* array_map = Map::cast(cell->value());
719 737993 : if (array_map == *map) {
720 28606 : Object* code = array->get(i + increment - 1);
721 : DCHECK(IC::IsHandler(code));
722 : return handle(code, isolate);
723 : }
724 : }
725 : }
726 1807495 : } else if (feedback->IsWeakCell()) {
727 : WeakCell* cell = WeakCell::cast(feedback);
728 1807495 : if (!cell->cleared()) {
729 : Map* cell_map = Map::cast(cell->value());
730 537553 : if (cell_map == *map) {
731 81449 : Object* code = GetFeedbackExtra();
732 : DCHECK(IC::IsHandler(code));
733 : return handle(code, isolate);
734 : }
735 : }
736 : }
737 :
738 : return MaybeHandle<Code>();
739 : }
740 :
741 2273618 : bool FeedbackNexus::FindHandlers(List<Handle<Object>>* code_list,
742 : int length) const {
743 2273618 : Object* feedback = GetFeedback();
744 : Isolate* isolate = GetIsolate();
745 : int count = 0;
746 2273618 : bool is_named_feedback = IsPropertyNameFeedback(feedback);
747 2273618 : if (feedback->IsFixedArray() || is_named_feedback) {
748 394805 : if (is_named_feedback) {
749 255 : feedback = GetFeedbackExtra();
750 : }
751 : FixedArray* array = FixedArray::cast(feedback);
752 : const int increment = 2;
753 2983302 : 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 1096846 : if (!cell->cleared()) {
758 777635 : Object* code = array->get(i + increment - 1);
759 : DCHECK(IC::IsHandler(code));
760 777635 : code_list->Add(handle(code, isolate));
761 777635 : count++;
762 : }
763 : }
764 1878813 : } else if (feedback->IsWeakCell()) {
765 : WeakCell* cell = WeakCell::cast(feedback);
766 1845101 : if (!cell->cleared()) {
767 577086 : Object* code = GetFeedbackExtra();
768 : DCHECK(IC::IsHandler(code));
769 577086 : code_list->Add(handle(code, isolate));
770 : count++;
771 : }
772 : }
773 2273618 : return count == length;
774 : }
775 :
776 118935 : Name* KeyedLoadICNexus::FindFirstName() const {
777 118935 : Object* feedback = GetFeedback();
778 118935 : if (IsPropertyNameFeedback(feedback)) {
779 20902 : return Name::cast(feedback);
780 : }
781 : return NULL;
782 : }
783 :
784 34402 : Name* KeyedStoreICNexus::FindFirstName() const {
785 34402 : Object* feedback = GetFeedback();
786 34402 : if (IsPropertyNameFeedback(feedback)) {
787 11424 : return Name::cast(feedback);
788 : }
789 : return NULL;
790 : }
791 :
792 81267 : KeyedAccessStoreMode KeyedStoreICNexus::GetKeyedAccessStoreMode() const {
793 : KeyedAccessStoreMode mode = STANDARD_STORE;
794 : MapHandleList maps;
795 : List<Handle<Object>> handlers;
796 :
797 81267 : if (GetKeyType() == PROPERTY) return mode;
798 :
799 80457 : ExtractMaps(&maps);
800 80457 : FindHandlers(&handlers, maps.length());
801 80498 : 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 46786 : Handle<Object> maybe_code_handler = handlers.at(i);
804 : Handle<Code> handler;
805 46786 : 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 46768 : } 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 46786 : 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 46786 : if (major_key != CodeStub::NoCache) {
825 : mode = CommonStoreModeBits::decode(minor_key);
826 : break;
827 : }
828 : }
829 :
830 80457 : return mode;
831 : }
832 :
833 41798 : IcCheckType KeyedLoadICNexus::GetKeyType() const {
834 41798 : Object* feedback = GetFeedback();
835 41798 : if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
836 10290 : return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
837 : }
838 36653 : return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
839 : }
840 :
841 96918 : IcCheckType KeyedStoreICNexus::GetKeyType() const {
842 96918 : Object* feedback = GetFeedback();
843 96918 : if (feedback == *FeedbackVector::MegamorphicSentinel(GetIsolate())) {
844 3752 : return static_cast<IcCheckType>(Smi::cast(GetFeedbackExtra())->value());
845 : }
846 95042 : 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 754179 : BinaryOperationHint BinaryOpICNexus::GetBinaryOperationFeedback() const {
872 754179 : int feedback = Smi::cast(GetFeedback())->value();
873 754179 : return BinaryOperationHintFromFeedback(feedback);
874 : }
875 :
876 903039 : CompareOperationHint CompareICNexus::GetCompareOperationFeedback() const {
877 903039 : int feedback = Smi::cast(GetFeedback())->value();
878 903039 : 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
|