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/feedback-vector-inl.h"
7#include "src/ic/handler-configuration-inl.h"
8#include "src/ic/ic-inl.h"
9#include "src/objects.h"
10#include "src/objects/data-handler-inl.h"
11#include "src/objects/hash-table-inl.h"
12#include "src/objects/map-inl.h"
13#include "src/objects/object-macros.h"
14
15namespace v8 {
16namespace internal {
17
18FeedbackSlot FeedbackVectorSpec::AddSlot(FeedbackSlotKind kind) {
19 int slot = slots();
20 int entries_per_slot = FeedbackMetadata::GetSlotSize(kind);
21 append(kind);
22 for (int i = 1; i < entries_per_slot; i++) {
23 append(FeedbackSlotKind::kInvalid);
24 }
25 return FeedbackSlot(slot);
26}
27
28FeedbackSlot FeedbackVectorSpec::AddTypeProfileSlot() {
29 FeedbackSlot slot = AddSlot(FeedbackSlotKind::kTypeProfile);
30 CHECK_EQ(FeedbackVectorSpec::kTypeProfileSlotIndex,
31 FeedbackVector::GetIndex(slot));
32 return slot;
33}
34
35bool FeedbackVectorSpec::HasTypeProfileSlot() const {
36 FeedbackSlot slot =
37 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
38 if (slots() <= slot.ToInt()) {
39 return false;
40 }
41 return GetKind(slot) == FeedbackSlotKind::kTypeProfile;
42}
43
44static bool IsPropertyNameFeedback(MaybeObject feedback) {
45 HeapObject heap_object;
46 if (!feedback->GetHeapObjectIfStrong(&heap_object)) return false;
47 if (heap_object->IsString()) {
48 DCHECK(heap_object->IsInternalizedString());
49 return true;
50 }
51 if (!heap_object->IsSymbol()) return false;
52 Symbol symbol = Symbol::cast(heap_object);
53 ReadOnlyRoots roots = symbol->GetReadOnlyRoots();
54 return symbol != roots.uninitialized_symbol() &&
55 symbol != roots.premonomorphic_symbol() &&
56 symbol != roots.megamorphic_symbol();
57}
58
59std::ostream& operator<<(std::ostream& os, FeedbackSlotKind kind) {
60 return os << FeedbackMetadata::Kind2String(kind);
61}
62
63FeedbackSlotKind FeedbackMetadata::GetKind(FeedbackSlot slot) const {
64 int index = VectorICComputer::index(0, slot.ToInt());
65 int data = get(index);
66 return VectorICComputer::decode(data, slot.ToInt());
67}
68
69void FeedbackMetadata::SetKind(FeedbackSlot slot, FeedbackSlotKind kind) {
70 int index = VectorICComputer::index(0, slot.ToInt());
71 int data = get(index);
72 int new_data = VectorICComputer::encode(data, slot.ToInt(), kind);
73 set(index, new_data);
74}
75
76// static
77Handle<FeedbackMetadata> FeedbackMetadata::New(Isolate* isolate,
78 const FeedbackVectorSpec* spec) {
79 Factory* factory = isolate->factory();
80
81 const int slot_count = spec == nullptr ? 0 : spec->slots();
82 const int closure_feedback_cell_count =
83 spec == nullptr ? 0 : spec->closure_feedback_cells();
84 if (slot_count == 0 && closure_feedback_cell_count == 0) {
85 return factory->empty_feedback_metadata();
86 }
87#ifdef DEBUG
88 for (int i = 0; i < slot_count;) {
89 DCHECK(spec);
90 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i));
91 int entry_size = FeedbackMetadata::GetSlotSize(kind);
92 for (int j = 1; j < entry_size; j++) {
93 FeedbackSlotKind kind = spec->GetKind(FeedbackSlot(i + j));
94 DCHECK_EQ(FeedbackSlotKind::kInvalid, kind);
95 }
96 i += entry_size;
97 }
98#endif
99
100 Handle<FeedbackMetadata> metadata =
101 factory->NewFeedbackMetadata(slot_count, closure_feedback_cell_count);
102
103 // Initialize the slots. The raw data section has already been pre-zeroed in
104 // NewFeedbackMetadata.
105 for (int i = 0; i < slot_count; i++) {
106 DCHECK(spec);
107 FeedbackSlot slot(i);
108 FeedbackSlotKind kind = spec->GetKind(slot);
109 metadata->SetKind(slot, kind);
110 }
111
112 return metadata;
113}
114
115bool FeedbackMetadata::SpecDiffersFrom(
116 const FeedbackVectorSpec* other_spec) const {
117 if (other_spec->slots() != slot_count()) {
118 return true;
119 }
120
121 int slots = slot_count();
122 for (int i = 0; i < slots;) {
123 FeedbackSlot slot(i);
124 FeedbackSlotKind kind = GetKind(slot);
125 int entry_size = FeedbackMetadata::GetSlotSize(kind);
126
127 if (kind != other_spec->GetKind(slot)) {
128 return true;
129 }
130 i += entry_size;
131 }
132 return false;
133}
134
135const char* FeedbackMetadata::Kind2String(FeedbackSlotKind kind) {
136 switch (kind) {
137 case FeedbackSlotKind::kInvalid:
138 return "Invalid";
139 case FeedbackSlotKind::kCall:
140 return "Call";
141 case FeedbackSlotKind::kLoadProperty:
142 return "LoadProperty";
143 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
144 return "LoadGlobalInsideTypeof";
145 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
146 return "LoadGlobalNotInsideTypeof";
147 case FeedbackSlotKind::kLoadKeyed:
148 return "LoadKeyed";
149 case FeedbackSlotKind::kHasKeyed:
150 return "HasKeyed";
151 case FeedbackSlotKind::kStoreNamedSloppy:
152 return "StoreNamedSloppy";
153 case FeedbackSlotKind::kStoreNamedStrict:
154 return "StoreNamedStrict";
155 case FeedbackSlotKind::kStoreOwnNamed:
156 return "StoreOwnNamed";
157 case FeedbackSlotKind::kStoreGlobalSloppy:
158 return "StoreGlobalSloppy";
159 case FeedbackSlotKind::kStoreGlobalStrict:
160 return "StoreGlobalStrict";
161 case FeedbackSlotKind::kStoreKeyedSloppy:
162 return "StoreKeyedSloppy";
163 case FeedbackSlotKind::kStoreKeyedStrict:
164 return "StoreKeyedStrict";
165 case FeedbackSlotKind::kStoreInArrayLiteral:
166 return "StoreInArrayLiteral";
167 case FeedbackSlotKind::kBinaryOp:
168 return "BinaryOp";
169 case FeedbackSlotKind::kCompareOp:
170 return "CompareOp";
171 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
172 return "StoreDataPropertyInLiteral";
173 case FeedbackSlotKind::kLiteral:
174 return "Literal";
175 case FeedbackSlotKind::kTypeProfile:
176 return "TypeProfile";
177 case FeedbackSlotKind::kForIn:
178 return "ForIn";
179 case FeedbackSlotKind::kInstanceOf:
180 return "InstanceOf";
181 case FeedbackSlotKind::kCloneObject:
182 return "CloneObject";
183 case FeedbackSlotKind::kKindsNumber:
184 break;
185 }
186 UNREACHABLE();
187}
188
189bool FeedbackMetadata::HasTypeProfileSlot() const {
190 FeedbackSlot slot =
191 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
192 return slot.ToInt() < slot_count() &&
193 GetKind(slot) == FeedbackSlotKind::kTypeProfile;
194}
195
196FeedbackSlotKind FeedbackVector::GetKind(FeedbackSlot slot) const {
197 DCHECK(!is_empty());
198 return metadata()->GetKind(slot);
199}
200
201FeedbackSlot FeedbackVector::GetTypeProfileSlot() const {
202 DCHECK(metadata()->HasTypeProfileSlot());
203 FeedbackSlot slot =
204 FeedbackVector::ToSlot(FeedbackVectorSpec::kTypeProfileSlotIndex);
205 DCHECK_EQ(FeedbackSlotKind::kTypeProfile, GetKind(slot));
206 return slot;
207}
208
209// static
210Handle<ClosureFeedbackCellArray> ClosureFeedbackCellArray::New(
211 Isolate* isolate, Handle<SharedFunctionInfo> shared) {
212 Factory* factory = isolate->factory();
213
214 int num_feedback_cells =
215 shared->feedback_metadata()->closure_feedback_cell_count();
216
217 Handle<ClosureFeedbackCellArray> feedback_cell_array =
218 factory->NewClosureFeedbackCellArray(num_feedback_cells);
219
220 for (int i = 0; i < num_feedback_cells; i++) {
221 Handle<FeedbackCell> cell =
222 factory->NewNoClosuresCell(factory->undefined_value());
223 feedback_cell_array->set(i, *cell);
224 }
225 return feedback_cell_array;
226}
227
228// static
229Handle<FeedbackVector> FeedbackVector::New(
230 Isolate* isolate, Handle<SharedFunctionInfo> shared,
231 Handle<ClosureFeedbackCellArray> closure_feedback_cell_array) {
232 Factory* factory = isolate->factory();
233
234 const int slot_count = shared->feedback_metadata()->slot_count();
235
236 Handle<FeedbackVector> vector = factory->NewFeedbackVector(
237 shared, closure_feedback_cell_array, AllocationType::kOld);
238
239 DCHECK_EQ(vector->length(), slot_count);
240
241 DCHECK_EQ(vector->shared_function_info(), *shared);
242 DCHECK_EQ(
243 vector->optimized_code_weak_or_smi(),
244 MaybeObject::FromSmi(Smi::FromEnum(
245 FLAG_log_function_events ? OptimizationMarker::kLogFirstExecution
246 : OptimizationMarker::kNone)));
247 DCHECK_EQ(vector->invocation_count(), 0);
248 DCHECK_EQ(vector->profiler_ticks(), 0);
249 DCHECK_EQ(vector->deopt_count(), 0);
250
251 // Ensure we can skip the write barrier
252 Handle<Object> uninitialized_sentinel = UninitializedSentinel(isolate);
253 DCHECK_EQ(ReadOnlyRoots(isolate).uninitialized_symbol(),
254 *uninitialized_sentinel);
255 for (int i = 0; i < slot_count;) {
256 FeedbackSlot slot(i);
257 FeedbackSlotKind kind = shared->feedback_metadata()->GetKind(slot);
258 int index = FeedbackVector::GetIndex(slot);
259 int entry_size = FeedbackMetadata::GetSlotSize(kind);
260
261 Object extra_value = *uninitialized_sentinel;
262 switch (kind) {
263 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
264 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
265 case FeedbackSlotKind::kStoreGlobalSloppy:
266 case FeedbackSlotKind::kStoreGlobalStrict:
267 vector->set(index, HeapObjectReference::ClearedValue(isolate),
268 SKIP_WRITE_BARRIER);
269 break;
270 case FeedbackSlotKind::kForIn:
271 case FeedbackSlotKind::kCompareOp:
272 case FeedbackSlotKind::kBinaryOp:
273 vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
274 break;
275 case FeedbackSlotKind::kLiteral:
276 vector->set(index, Smi::kZero, SKIP_WRITE_BARRIER);
277 break;
278 case FeedbackSlotKind::kCall:
279 vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
280 extra_value = Smi::kZero;
281 break;
282 case FeedbackSlotKind::kCloneObject:
283 case FeedbackSlotKind::kLoadProperty:
284 case FeedbackSlotKind::kLoadKeyed:
285 case FeedbackSlotKind::kHasKeyed:
286 case FeedbackSlotKind::kStoreNamedSloppy:
287 case FeedbackSlotKind::kStoreNamedStrict:
288 case FeedbackSlotKind::kStoreOwnNamed:
289 case FeedbackSlotKind::kStoreKeyedSloppy:
290 case FeedbackSlotKind::kStoreKeyedStrict:
291 case FeedbackSlotKind::kStoreInArrayLiteral:
292 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
293 case FeedbackSlotKind::kTypeProfile:
294 case FeedbackSlotKind::kInstanceOf:
295 vector->set(index, *uninitialized_sentinel, SKIP_WRITE_BARRIER);
296 break;
297
298 case FeedbackSlotKind::kInvalid:
299 case FeedbackSlotKind::kKindsNumber:
300 UNREACHABLE();
301 break;
302 }
303 for (int j = 1; j < entry_size; j++) {
304 vector->set(index + j, extra_value, SKIP_WRITE_BARRIER);
305 }
306 i += entry_size;
307 }
308
309 Handle<FeedbackVector> result = Handle<FeedbackVector>::cast(vector);
310 if (!isolate->is_best_effort_code_coverage() ||
311 isolate->is_collecting_type_profile()) {
312 AddToVectorsForProfilingTools(isolate, result);
313 }
314 return result;
315}
316
317// static
318void FeedbackVector::AddToVectorsForProfilingTools(
319 Isolate* isolate, Handle<FeedbackVector> vector) {
320 DCHECK(!isolate->is_best_effort_code_coverage() ||
321 isolate->is_collecting_type_profile());
322 if (!vector->shared_function_info()->IsSubjectToDebugging()) return;
323 Handle<ArrayList> list = Handle<ArrayList>::cast(
324 isolate->factory()->feedback_vectors_for_profiling_tools());
325 list = ArrayList::Add(isolate, list, vector);
326 isolate->SetFeedbackVectorsForProfilingTools(*list);
327}
328
329// static
330void FeedbackVector::SetOptimizedCode(Handle<FeedbackVector> vector,
331 Handle<Code> code) {
332 DCHECK_EQ(code->kind(), Code::OPTIMIZED_FUNCTION);
333 vector->set_optimized_code_weak_or_smi(HeapObjectReference::Weak(*code));
334}
335
336void FeedbackVector::ClearOptimizedCode() {
337 DCHECK(has_optimized_code());
338 SetOptimizationMarker(OptimizationMarker::kNone);
339}
340
341void FeedbackVector::ClearOptimizationMarker() {
342 DCHECK(!has_optimized_code());
343 SetOptimizationMarker(OptimizationMarker::kNone);
344}
345
346void FeedbackVector::SetOptimizationMarker(OptimizationMarker marker) {
347 set_optimized_code_weak_or_smi(MaybeObject::FromSmi(Smi::FromEnum(marker)));
348}
349
350void FeedbackVector::EvictOptimizedCodeMarkedForDeoptimization(
351 SharedFunctionInfo shared, const char* reason) {
352 MaybeObject slot = optimized_code_weak_or_smi();
353 if (slot->IsSmi()) {
354 return;
355 }
356
357 if (slot->IsCleared()) {
358 ClearOptimizationMarker();
359 return;
360 }
361
362 Code code = Code::cast(slot->GetHeapObject());
363 if (code->marked_for_deoptimization()) {
364 if (FLAG_trace_deopt) {
365 PrintF("[evicting optimizing code marked for deoptimization (%s) for ",
366 reason);
367 shared->ShortPrint();
368 PrintF("]\n");
369 }
370 if (!code->deopt_already_counted()) {
371 increment_deopt_count();
372 code->set_deopt_already_counted(true);
373 }
374 ClearOptimizedCode();
375 }
376}
377
378bool FeedbackVector::ClearSlots(Isolate* isolate) {
379 MaybeObject uninitialized_sentinel = MaybeObject::FromObject(
380 FeedbackVector::RawUninitializedSentinel(isolate));
381
382 bool feedback_updated = false;
383 FeedbackMetadataIterator iter(metadata());
384 while (iter.HasNext()) {
385 FeedbackSlot slot = iter.Next();
386
387 MaybeObject obj = Get(slot);
388 if (obj != uninitialized_sentinel) {
389 FeedbackNexus nexus(*this, slot);
390 feedback_updated |= nexus.Clear();
391 }
392 }
393 return feedback_updated;
394}
395
396void FeedbackVector::AssertNoLegacyTypes(MaybeObject object) {
397#ifdef DEBUG
398 HeapObject heap_object;
399 if (object->GetHeapObject(&heap_object)) {
400 // Instead of FixedArray, the Feedback and the Extra should contain
401 // WeakFixedArrays. The only allowed FixedArray subtype is HashTable.
402 DCHECK_IMPLIES(heap_object->IsFixedArray(), heap_object->IsHashTable());
403 }
404#endif
405}
406
407Handle<WeakFixedArray> FeedbackNexus::EnsureArrayOfSize(int length) {
408 Isolate* isolate = GetIsolate();
409 HeapObject heap_object;
410 if (GetFeedback()->GetHeapObjectIfStrong(&heap_object) &&
411 heap_object->IsWeakFixedArray() &&
412 WeakFixedArray::cast(heap_object)->length() == length) {
413 return handle(WeakFixedArray::cast(heap_object), isolate);
414 }
415 Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
416 SetFeedback(*array);
417 return array;
418}
419
420Handle<WeakFixedArray> FeedbackNexus::EnsureExtraArrayOfSize(int length) {
421 Isolate* isolate = GetIsolate();
422 HeapObject heap_object;
423 if (GetFeedbackExtra()->GetHeapObjectIfStrong(&heap_object) &&
424 heap_object->IsWeakFixedArray() &&
425 WeakFixedArray::cast(heap_object)->length() == length) {
426 return handle(WeakFixedArray::cast(heap_object), isolate);
427 }
428 Handle<WeakFixedArray> array = isolate->factory()->NewWeakFixedArray(length);
429 SetFeedbackExtra(*array);
430 return array;
431}
432
433void FeedbackNexus::ConfigureUninitialized() {
434 Isolate* isolate = GetIsolate();
435 switch (kind()) {
436 case FeedbackSlotKind::kStoreGlobalSloppy:
437 case FeedbackSlotKind::kStoreGlobalStrict:
438 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
439 case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
440 SetFeedback(HeapObjectReference::ClearedValue(isolate),
441 SKIP_WRITE_BARRIER);
442 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
443 SKIP_WRITE_BARRIER);
444 break;
445 }
446 case FeedbackSlotKind::kCloneObject:
447 case FeedbackSlotKind::kCall: {
448 SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
449 SKIP_WRITE_BARRIER);
450 SetFeedbackExtra(Smi::kZero, SKIP_WRITE_BARRIER);
451 break;
452 }
453 case FeedbackSlotKind::kInstanceOf: {
454 SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
455 SKIP_WRITE_BARRIER);
456 break;
457 }
458 case FeedbackSlotKind::kStoreNamedSloppy:
459 case FeedbackSlotKind::kStoreNamedStrict:
460 case FeedbackSlotKind::kStoreKeyedSloppy:
461 case FeedbackSlotKind::kStoreKeyedStrict:
462 case FeedbackSlotKind::kStoreInArrayLiteral:
463 case FeedbackSlotKind::kStoreOwnNamed:
464 case FeedbackSlotKind::kLoadProperty:
465 case FeedbackSlotKind::kLoadKeyed:
466 case FeedbackSlotKind::kHasKeyed:
467 case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
468 SetFeedback(*FeedbackVector::UninitializedSentinel(isolate),
469 SKIP_WRITE_BARRIER);
470 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
471 SKIP_WRITE_BARRIER);
472 break;
473 }
474 default:
475 UNREACHABLE();
476 }
477}
478
479bool FeedbackNexus::Clear() {
480 bool feedback_updated = false;
481
482 switch (kind()) {
483 case FeedbackSlotKind::kTypeProfile:
484 // We don't clear these kinds ever.
485 break;
486
487 case FeedbackSlotKind::kCompareOp:
488 case FeedbackSlotKind::kForIn:
489 case FeedbackSlotKind::kBinaryOp:
490 // We don't clear these, either.
491 break;
492
493 case FeedbackSlotKind::kLiteral:
494 SetFeedback(Smi::kZero, SKIP_WRITE_BARRIER);
495 feedback_updated = true;
496 break;
497
498 case FeedbackSlotKind::kStoreNamedSloppy:
499 case FeedbackSlotKind::kStoreNamedStrict:
500 case FeedbackSlotKind::kStoreKeyedSloppy:
501 case FeedbackSlotKind::kStoreKeyedStrict:
502 case FeedbackSlotKind::kStoreInArrayLiteral:
503 case FeedbackSlotKind::kStoreOwnNamed:
504 case FeedbackSlotKind::kLoadProperty:
505 case FeedbackSlotKind::kLoadKeyed:
506 case FeedbackSlotKind::kHasKeyed:
507 case FeedbackSlotKind::kStoreGlobalSloppy:
508 case FeedbackSlotKind::kStoreGlobalStrict:
509 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
510 case FeedbackSlotKind::kLoadGlobalInsideTypeof:
511 case FeedbackSlotKind::kCall:
512 case FeedbackSlotKind::kInstanceOf:
513 case FeedbackSlotKind::kStoreDataPropertyInLiteral:
514 case FeedbackSlotKind::kCloneObject:
515 if (!IsCleared()) {
516 ConfigureUninitialized();
517 feedback_updated = true;
518 }
519 break;
520
521 case FeedbackSlotKind::kInvalid:
522 case FeedbackSlotKind::kKindsNumber:
523 UNREACHABLE();
524 break;
525 }
526 return feedback_updated;
527}
528
529void FeedbackNexus::ConfigurePremonomorphic(Handle<Map> receiver_map) {
530 SetFeedback(*FeedbackVector::PremonomorphicSentinel(GetIsolate()),
531 SKIP_WRITE_BARRIER);
532 SetFeedbackExtra(HeapObjectReference::Weak(*receiver_map));
533}
534
535bool FeedbackNexus::ConfigureMegamorphic() {
536 DisallowHeapAllocation no_gc;
537 Isolate* isolate = GetIsolate();
538 MaybeObject sentinel =
539 MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
540 if (GetFeedback() != sentinel) {
541 SetFeedback(sentinel, SKIP_WRITE_BARRIER);
542 SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
543 return true;
544 }
545
546 return false;
547}
548
549bool FeedbackNexus::ConfigureMegamorphic(IcCheckType property_type) {
550 DisallowHeapAllocation no_gc;
551 Isolate* isolate = GetIsolate();
552 bool changed = false;
553 MaybeObject sentinel =
554 MaybeObject::FromObject(*FeedbackVector::MegamorphicSentinel(isolate));
555 if (GetFeedback() != sentinel) {
556 SetFeedback(sentinel, SKIP_WRITE_BARRIER);
557 changed = true;
558 }
559
560 Smi extra = Smi::FromInt(static_cast<int>(property_type));
561 if (changed || GetFeedbackExtra() != MaybeObject::FromSmi(extra)) {
562 SetFeedbackExtra(extra, SKIP_WRITE_BARRIER);
563 changed = true;
564 }
565 return changed;
566}
567
568Map FeedbackNexus::GetFirstMap() const {
569 MapHandles maps;
570 ExtractMaps(&maps);
571 if (maps.size() > 0) return *maps.at(0);
572 return Map();
573}
574
575InlineCacheState FeedbackNexus::ic_state() const {
576 Isolate* isolate = GetIsolate();
577 MaybeObject feedback = GetFeedback();
578
579 switch (kind()) {
580 case FeedbackSlotKind::kLiteral:
581 if (feedback->IsSmi()) return UNINITIALIZED;
582 return MONOMORPHIC;
583
584 case FeedbackSlotKind::kStoreGlobalSloppy:
585 case FeedbackSlotKind::kStoreGlobalStrict:
586 case FeedbackSlotKind::kLoadGlobalNotInsideTypeof:
587 case FeedbackSlotKind::kLoadGlobalInsideTypeof: {
588 if (feedback->IsSmi()) return MONOMORPHIC;
589
590 if (feedback == MaybeObject::FromObject(
591 *FeedbackVector::PremonomorphicSentinel(isolate))) {
592 DCHECK(kind() == FeedbackSlotKind::kStoreGlobalSloppy ||
593 kind() == FeedbackSlotKind::kStoreGlobalStrict);
594 return PREMONOMORPHIC;
595 }
596
597 DCHECK(feedback->IsWeakOrCleared());
598 MaybeObject extra = GetFeedbackExtra();
599 if (!feedback->IsCleared() ||
600 extra != MaybeObject::FromObject(
601 *FeedbackVector::UninitializedSentinel(isolate))) {
602 return MONOMORPHIC;
603 }
604 return UNINITIALIZED;
605 }
606
607 case FeedbackSlotKind::kStoreNamedSloppy:
608 case FeedbackSlotKind::kStoreNamedStrict:
609 case FeedbackSlotKind::kStoreKeyedSloppy:
610 case FeedbackSlotKind::kStoreKeyedStrict:
611 case FeedbackSlotKind::kStoreInArrayLiteral:
612 case FeedbackSlotKind::kStoreOwnNamed:
613 case FeedbackSlotKind::kLoadProperty:
614 case FeedbackSlotKind::kLoadKeyed:
615 case FeedbackSlotKind::kHasKeyed: {
616 if (feedback == MaybeObject::FromObject(
617 *FeedbackVector::UninitializedSentinel(isolate))) {
618 return UNINITIALIZED;
619 }
620 if (feedback == MaybeObject::FromObject(
621 *FeedbackVector::MegamorphicSentinel(isolate))) {
622 return MEGAMORPHIC;
623 }
624 if (feedback == MaybeObject::FromObject(
625 *FeedbackVector::PremonomorphicSentinel(isolate))) {
626 return PREMONOMORPHIC;
627 }
628 if (feedback->IsWeakOrCleared()) {
629 // Don't check if the map is cleared.
630 return MONOMORPHIC;
631 }
632 HeapObject heap_object;
633 if (feedback->GetHeapObjectIfStrong(&heap_object)) {
634 if (heap_object->IsWeakFixedArray()) {
635 // Determine state purely by our structure, don't check if the maps
636 // are cleared.
637 return POLYMORPHIC;
638 }
639 if (heap_object->IsName()) {
640 DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
641 IsKeyedHasICKind(kind()));
642 Object extra = GetFeedbackExtra()->GetHeapObjectAssumeStrong();
643 WeakFixedArray extra_array = WeakFixedArray::cast(extra);
644 return extra_array->length() > 2 ? POLYMORPHIC : MONOMORPHIC;
645 }
646 }
647 UNREACHABLE();
648 }
649 case FeedbackSlotKind::kCall: {
650 HeapObject heap_object;
651 if (feedback == MaybeObject::FromObject(
652 *FeedbackVector::MegamorphicSentinel(isolate))) {
653 return GENERIC;
654 } else if (feedback->IsWeakOrCleared() ||
655 (feedback->GetHeapObjectIfStrong(&heap_object) &&
656 heap_object->IsAllocationSite())) {
657 return MONOMORPHIC;
658 }
659
660 CHECK_EQ(feedback, MaybeObject::FromObject(
661 *FeedbackVector::UninitializedSentinel(isolate)));
662 return UNINITIALIZED;
663 }
664 case FeedbackSlotKind::kBinaryOp: {
665 BinaryOperationHint hint = GetBinaryOperationFeedback();
666 if (hint == BinaryOperationHint::kNone) {
667 return UNINITIALIZED;
668 } else if (hint == BinaryOperationHint::kAny) {
669 return GENERIC;
670 }
671
672 return MONOMORPHIC;
673 }
674 case FeedbackSlotKind::kCompareOp: {
675 CompareOperationHint hint = GetCompareOperationFeedback();
676 if (hint == CompareOperationHint::kNone) {
677 return UNINITIALIZED;
678 } else if (hint == CompareOperationHint::kAny) {
679 return GENERIC;
680 }
681
682 return MONOMORPHIC;
683 }
684 case FeedbackSlotKind::kForIn: {
685 ForInHint hint = GetForInFeedback();
686 if (hint == ForInHint::kNone) {
687 return UNINITIALIZED;
688 } else if (hint == ForInHint::kAny) {
689 return GENERIC;
690 }
691 return MONOMORPHIC;
692 }
693 case FeedbackSlotKind::kInstanceOf: {
694 if (feedback == MaybeObject::FromObject(
695 *FeedbackVector::UninitializedSentinel(isolate))) {
696 return UNINITIALIZED;
697 } else if (feedback ==
698 MaybeObject::FromObject(
699 *FeedbackVector::MegamorphicSentinel(isolate))) {
700 return MEGAMORPHIC;
701 }
702 return MONOMORPHIC;
703 }
704 case FeedbackSlotKind::kStoreDataPropertyInLiteral: {
705 if (feedback == MaybeObject::FromObject(
706 *FeedbackVector::UninitializedSentinel(isolate))) {
707 return UNINITIALIZED;
708 } else if (feedback->IsWeakOrCleared()) {
709 // Don't check if the map is cleared.
710 return MONOMORPHIC;
711 }
712
713 return MEGAMORPHIC;
714 }
715 case FeedbackSlotKind::kTypeProfile: {
716 if (feedback == MaybeObject::FromObject(
717 *FeedbackVector::UninitializedSentinel(isolate))) {
718 return UNINITIALIZED;
719 }
720 return MONOMORPHIC;
721 }
722
723 case FeedbackSlotKind::kCloneObject: {
724 if (feedback == MaybeObject::FromObject(
725 *FeedbackVector::UninitializedSentinel(isolate))) {
726 return UNINITIALIZED;
727 }
728 if (feedback == MaybeObject::FromObject(
729 *FeedbackVector::MegamorphicSentinel(isolate))) {
730 return MEGAMORPHIC;
731 }
732 if (feedback->IsWeakOrCleared()) {
733 return MONOMORPHIC;
734 }
735
736 DCHECK(feedback->GetHeapObjectAssumeStrong()->IsWeakFixedArray());
737 return POLYMORPHIC;
738 }
739
740 case FeedbackSlotKind::kInvalid:
741 case FeedbackSlotKind::kKindsNumber:
742 UNREACHABLE();
743 break;
744 }
745 return UNINITIALIZED;
746}
747
748void FeedbackNexus::ConfigurePropertyCellMode(Handle<PropertyCell> cell) {
749 DCHECK(IsGlobalICKind(kind()));
750 Isolate* isolate = GetIsolate();
751 SetFeedback(HeapObjectReference::Weak(*cell));
752 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
753 SKIP_WRITE_BARRIER);
754}
755
756bool FeedbackNexus::ConfigureLexicalVarMode(int script_context_index,
757 int context_slot_index,
758 bool immutable) {
759 DCHECK(IsGlobalICKind(kind()));
760 DCHECK_LE(0, script_context_index);
761 DCHECK_LE(0, context_slot_index);
762 if (!ContextIndexBits::is_valid(script_context_index) ||
763 !SlotIndexBits::is_valid(context_slot_index) ||
764 !ImmutabilityBit::is_valid(immutable)) {
765 return false;
766 }
767 int config = ContextIndexBits::encode(script_context_index) |
768 SlotIndexBits::encode(context_slot_index) |
769 ImmutabilityBit::encode(immutable);
770
771 SetFeedback(Smi::From31BitPattern(config));
772 Isolate* isolate = GetIsolate();
773 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(isolate),
774 SKIP_WRITE_BARRIER);
775 return true;
776}
777
778void FeedbackNexus::ConfigureHandlerMode(const MaybeObjectHandle& handler) {
779 DCHECK(IsGlobalICKind(kind()));
780 DCHECK(IC::IsHandler(*handler));
781 SetFeedback(HeapObjectReference::ClearedValue(GetIsolate()));
782 SetFeedbackExtra(*handler);
783}
784
785void FeedbackNexus::ConfigureCloneObject(Handle<Map> source_map,
786 Handle<Map> result_map) {
787 Isolate* isolate = GetIsolate();
788 MaybeObject maybe_feedback = GetFeedback();
789 Handle<HeapObject> feedback(maybe_feedback->IsStrongOrWeak()
790 ? maybe_feedback->GetHeapObject()
791 : HeapObject(),
792 isolate);
793 switch (ic_state()) {
794 case UNINITIALIZED:
795 // Cache the first map seen which meets the fast case requirements.
796 SetFeedback(HeapObjectReference::Weak(*source_map));
797 SetFeedbackExtra(*result_map);
798 break;
799 case MONOMORPHIC:
800 if (maybe_feedback->IsCleared() || feedback.is_identical_to(source_map) ||
801 Map::cast(*feedback)->is_deprecated()) {
802 // Remain in MONOMORPHIC state if previous feedback has been collected.
803 SetFeedback(HeapObjectReference::Weak(*source_map));
804 SetFeedbackExtra(*result_map);
805 } else {
806 // Transition to POLYMORPHIC.
807 Handle<WeakFixedArray> array =
808 EnsureArrayOfSize(2 * kCloneObjectPolymorphicEntrySize);
809 array->Set(0, maybe_feedback);
810 array->Set(1, GetFeedbackExtra());
811 array->Set(2, HeapObjectReference::Weak(*source_map));
812 array->Set(3, MaybeObject::FromObject(*result_map));
813 SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
814 }
815 break;
816 case POLYMORPHIC: {
817 const int kMaxElements =
818 FLAG_max_polymorphic_map_count * kCloneObjectPolymorphicEntrySize;
819 Handle<WeakFixedArray> array = Handle<WeakFixedArray>::cast(feedback);
820 int i = 0;
821 for (; i < array->length(); i += kCloneObjectPolymorphicEntrySize) {
822 MaybeObject feedback = array->Get(i);
823 if (feedback->IsCleared()) break;
824 Handle<Map> cached_map(Map::cast(feedback->GetHeapObject()), isolate);
825 if (cached_map.is_identical_to(source_map) ||
826 cached_map->is_deprecated())
827 break;
828 }
829
830 if (i >= array->length()) {
831 if (i == kMaxElements) {
832 // Transition to MEGAMORPHIC.
833 MaybeObject sentinel = MaybeObject::FromObject(
834 *FeedbackVector::MegamorphicSentinel(isolate));
835 SetFeedback(sentinel, SKIP_WRITE_BARRIER);
836 SetFeedbackExtra(HeapObjectReference::ClearedValue(isolate));
837 break;
838 }
839
840 // Grow polymorphic feedback array.
841 Handle<WeakFixedArray> new_array = EnsureArrayOfSize(
842 array->length() + kCloneObjectPolymorphicEntrySize);
843 for (int j = 0; j < array->length(); ++j) {
844 new_array->Set(j, array->Get(j));
845 }
846 array = new_array;
847 }
848
849 array->Set(i, HeapObjectReference::Weak(*source_map));
850 array->Set(i + 1, MaybeObject::FromObject(*result_map));
851 break;
852 }
853
854 default:
855 UNREACHABLE();
856 }
857}
858
859int FeedbackNexus::GetCallCount() {
860 DCHECK(IsCallICKind(kind()));
861
862 Object call_count = GetFeedbackExtra()->cast<Object>();
863 CHECK(call_count->IsSmi());
864 uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
865 return CallCountField::decode(value);
866}
867
868void FeedbackNexus::SetSpeculationMode(SpeculationMode mode) {
869 DCHECK(IsCallICKind(kind()));
870
871 Object call_count = GetFeedbackExtra()->cast<Object>();
872 CHECK(call_count->IsSmi());
873 uint32_t count = static_cast<uint32_t>(Smi::ToInt(call_count));
874 uint32_t value = CallCountField::encode(CallCountField::decode(count));
875 int result = static_cast<int>(value | SpeculationModeField::encode(mode));
876 SetFeedbackExtra(Smi::FromInt(result), SKIP_WRITE_BARRIER);
877}
878
879SpeculationMode FeedbackNexus::GetSpeculationMode() {
880 DCHECK(IsCallICKind(kind()));
881
882 Object call_count = GetFeedbackExtra()->cast<Object>();
883 CHECK(call_count->IsSmi());
884 uint32_t value = static_cast<uint32_t>(Smi::ToInt(call_count));
885 return SpeculationModeField::decode(value);
886}
887
888float FeedbackNexus::ComputeCallFrequency() {
889 DCHECK(IsCallICKind(kind()));
890
891 double const invocation_count = vector()->invocation_count();
892 double const call_count = GetCallCount();
893 if (invocation_count == 0) {
894 // Prevent division by 0.
895 return 0.0f;
896 }
897 return static_cast<float>(call_count / invocation_count);
898}
899
900void FeedbackNexus::ConfigureMonomorphic(Handle<Name> name,
901 Handle<Map> receiver_map,
902 const MaybeObjectHandle& handler) {
903 DCHECK(handler.is_null() || IC::IsHandler(*handler));
904 if (kind() == FeedbackSlotKind::kStoreDataPropertyInLiteral) {
905 SetFeedback(HeapObjectReference::Weak(*receiver_map));
906 SetFeedbackExtra(*name);
907 } else {
908 if (name.is_null()) {
909 SetFeedback(HeapObjectReference::Weak(*receiver_map));
910 SetFeedbackExtra(*handler);
911 } else {
912 Handle<WeakFixedArray> array = EnsureExtraArrayOfSize(2);
913 SetFeedback(*name);
914 array->Set(0, HeapObjectReference::Weak(*receiver_map));
915 array->Set(1, *handler);
916 }
917 }
918}
919
920void FeedbackNexus::ConfigurePolymorphic(Handle<Name> name,
921 MapHandles const& maps,
922 MaybeObjectHandles* handlers) {
923 DCHECK_EQ(handlers->size(), maps.size());
924 int receiver_count = static_cast<int>(maps.size());
925 DCHECK_GT(receiver_count, 1);
926 Handle<WeakFixedArray> array;
927 if (name.is_null()) {
928 array = EnsureArrayOfSize(receiver_count * 2);
929 SetFeedbackExtra(*FeedbackVector::UninitializedSentinel(GetIsolate()),
930 SKIP_WRITE_BARRIER);
931 } else {
932 array = EnsureExtraArrayOfSize(receiver_count * 2);
933 SetFeedback(*name);
934 }
935
936 for (int current = 0; current < receiver_count; ++current) {
937 Handle<Map> map = maps[current];
938 array->Set(current * 2, HeapObjectReference::Weak(*map));
939 DCHECK(IC::IsHandler(*handlers->at(current)));
940 array->Set(current * 2 + 1, *handlers->at(current));
941 }
942}
943
944int FeedbackNexus::ExtractMaps(MapHandles* maps) const {
945 DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
946 IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
947 IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
948 IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
949
950 Isolate* isolate = GetIsolate();
951 MaybeObject feedback = GetFeedback();
952 bool is_named_feedback = IsPropertyNameFeedback(feedback);
953 HeapObject heap_object;
954 if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
955 heap_object->IsWeakFixedArray()) ||
956 is_named_feedback) {
957 int found = 0;
958 WeakFixedArray array;
959 if (is_named_feedback) {
960 array =
961 WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
962 } else {
963 array = WeakFixedArray::cast(heap_object);
964 }
965 const int increment = 2;
966 HeapObject heap_object;
967 for (int i = 0; i < array->length(); i += increment) {
968 DCHECK(array->Get(i)->IsWeakOrCleared());
969 if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
970 Map map = Map::cast(heap_object);
971 maps->push_back(handle(map, isolate));
972 found++;
973 }
974 }
975 return found;
976 } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
977 Map map = Map::cast(heap_object);
978 maps->push_back(handle(map, isolate));
979 return 1;
980 } else if (feedback->GetHeapObjectIfStrong(&heap_object) &&
981 heap_object ==
982 heap_object->GetReadOnlyRoots().premonomorphic_symbol()) {
983 if (GetFeedbackExtra()->GetHeapObjectIfWeak(&heap_object)) {
984 Map map = Map::cast(heap_object);
985 maps->push_back(handle(map, isolate));
986 return 1;
987 }
988 }
989
990 return 0;
991}
992
993MaybeObjectHandle FeedbackNexus::FindHandlerForMap(Handle<Map> map) const {
994 DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
995 IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
996 IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
997 IsKeyedHasICKind(kind()));
998
999 MaybeObject feedback = GetFeedback();
1000 Isolate* isolate = GetIsolate();
1001 bool is_named_feedback = IsPropertyNameFeedback(feedback);
1002 HeapObject heap_object;
1003 if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1004 heap_object->IsWeakFixedArray()) ||
1005 is_named_feedback) {
1006 WeakFixedArray array;
1007 if (is_named_feedback) {
1008 array =
1009 WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1010 } else {
1011 array = WeakFixedArray::cast(heap_object);
1012 }
1013 const int increment = 2;
1014 HeapObject heap_object;
1015 for (int i = 0; i < array->length(); i += increment) {
1016 DCHECK(array->Get(i)->IsWeakOrCleared());
1017 if (array->Get(i)->GetHeapObjectIfWeak(&heap_object)) {
1018 Map array_map = Map::cast(heap_object);
1019 if (array_map == *map && !array->Get(i + increment - 1)->IsCleared()) {
1020 MaybeObject handler = array->Get(i + increment - 1);
1021 DCHECK(IC::IsHandler(handler));
1022 return handle(handler, isolate);
1023 }
1024 }
1025 }
1026 } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1027 Map cell_map = Map::cast(heap_object);
1028 if (cell_map == *map && !GetFeedbackExtra()->IsCleared()) {
1029 MaybeObject handler = GetFeedbackExtra();
1030 DCHECK(IC::IsHandler(handler));
1031 return handle(handler, isolate);
1032 }
1033 }
1034
1035 return MaybeObjectHandle();
1036}
1037
1038bool FeedbackNexus::FindHandlers(MaybeObjectHandles* code_list,
1039 int length) const {
1040 DCHECK(IsLoadICKind(kind()) || IsStoreICKind(kind()) ||
1041 IsKeyedLoadICKind(kind()) || IsKeyedStoreICKind(kind()) ||
1042 IsStoreOwnICKind(kind()) || IsStoreDataPropertyInLiteralKind(kind()) ||
1043 IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
1044
1045 MaybeObject feedback = GetFeedback();
1046 Isolate* isolate = GetIsolate();
1047 int count = 0;
1048 bool is_named_feedback = IsPropertyNameFeedback(feedback);
1049 HeapObject heap_object;
1050 if ((feedback->GetHeapObjectIfStrong(&heap_object) &&
1051 heap_object->IsWeakFixedArray()) ||
1052 is_named_feedback) {
1053 WeakFixedArray array;
1054 if (is_named_feedback) {
1055 array =
1056 WeakFixedArray::cast(GetFeedbackExtra()->GetHeapObjectAssumeStrong());
1057 } else {
1058 array = WeakFixedArray::cast(heap_object);
1059 }
1060 const int increment = 2;
1061 HeapObject heap_object;
1062 for (int i = 0; i < array->length(); i += increment) {
1063 // Be sure to skip handlers whose maps have been cleared.
1064 DCHECK(array->Get(i)->IsWeakOrCleared());
1065 if (array->Get(i)->GetHeapObjectIfWeak(&heap_object) &&
1066 !array->Get(i + increment - 1)->IsCleared()) {
1067 MaybeObject handler = array->Get(i + increment - 1);
1068 DCHECK(IC::IsHandler(handler));
1069 code_list->push_back(handle(handler, isolate));
1070 count++;
1071 }
1072 }
1073 } else if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1074 MaybeObject extra = GetFeedbackExtra();
1075 if (!extra->IsCleared()) {
1076 DCHECK(IC::IsHandler(extra));
1077 code_list->push_back(handle(extra, isolate));
1078 count++;
1079 }
1080 }
1081 return count == length;
1082}
1083
1084Name FeedbackNexus::GetName() const {
1085 if (IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1086 IsKeyedHasICKind(kind())) {
1087 MaybeObject feedback = GetFeedback();
1088 if (IsPropertyNameFeedback(feedback)) {
1089 return Name::cast(feedback->GetHeapObjectAssumeStrong());
1090 }
1091 }
1092 return Name();
1093}
1094
1095KeyedAccessLoadMode FeedbackNexus::GetKeyedAccessLoadMode() const {
1096 DCHECK(IsKeyedLoadICKind(kind()) || IsKeyedHasICKind(kind()));
1097 MapHandles maps;
1098 MaybeObjectHandles handlers;
1099
1100 if (GetKeyType() == PROPERTY) return STANDARD_LOAD;
1101
1102 ExtractMaps(&maps);
1103 FindHandlers(&handlers, static_cast<int>(maps.size()));
1104 for (MaybeObjectHandle const& handler : handlers) {
1105 KeyedAccessLoadMode mode = LoadHandler::GetKeyedAccessLoadMode(*handler);
1106 if (mode != STANDARD_LOAD) return mode;
1107 }
1108
1109 return STANDARD_LOAD;
1110}
1111
1112namespace {
1113
1114bool BuiltinHasKeyedAccessStoreMode(int builtin_index) {
1115 DCHECK(Builtins::IsBuiltinId(builtin_index));
1116 switch (builtin_index) {
1117 case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1118 case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1119 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1120 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1121 case Builtins::kStoreFastElementIC_Standard:
1122 case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1123 case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1124 case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1125 case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1126 case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1127 case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1128 case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1129 case Builtins::kKeyedStoreIC_Slow_Standard:
1130 case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1131 case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1132 case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1133 case Builtins::kElementsTransitionAndStore_Standard:
1134 case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1135 case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1136 case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1137 return true;
1138 default:
1139 return false;
1140 }
1141 UNREACHABLE();
1142}
1143
1144KeyedAccessStoreMode KeyedAccessStoreModeForBuiltin(int builtin_index) {
1145 DCHECK(BuiltinHasKeyedAccessStoreMode(builtin_index));
1146 switch (builtin_index) {
1147 case Builtins::kKeyedStoreIC_SloppyArguments_Standard:
1148 case Builtins::kStoreInArrayLiteralIC_Slow_Standard:
1149 case Builtins::kKeyedStoreIC_Slow_Standard:
1150 case Builtins::kStoreFastElementIC_Standard:
1151 case Builtins::kElementsTransitionAndStore_Standard:
1152 return STANDARD_STORE;
1153 case Builtins::kKeyedStoreIC_SloppyArguments_GrowNoTransitionHandleCOW:
1154 case Builtins::kStoreInArrayLiteralIC_Slow_GrowNoTransitionHandleCOW:
1155 case Builtins::kKeyedStoreIC_Slow_GrowNoTransitionHandleCOW:
1156 case Builtins::kStoreFastElementIC_GrowNoTransitionHandleCOW:
1157 case Builtins::kElementsTransitionAndStore_GrowNoTransitionHandleCOW:
1158 return STORE_AND_GROW_NO_TRANSITION_HANDLE_COW;
1159 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionIgnoreOOB:
1160 case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionIgnoreOOB:
1161 case Builtins::kKeyedStoreIC_Slow_NoTransitionIgnoreOOB:
1162 case Builtins::kStoreFastElementIC_NoTransitionIgnoreOOB:
1163 case Builtins::kElementsTransitionAndStore_NoTransitionIgnoreOOB:
1164 return STORE_NO_TRANSITION_IGNORE_OUT_OF_BOUNDS;
1165 case Builtins::kKeyedStoreIC_SloppyArguments_NoTransitionHandleCOW:
1166 case Builtins::kStoreInArrayLiteralIC_Slow_NoTransitionHandleCOW:
1167 case Builtins::kKeyedStoreIC_Slow_NoTransitionHandleCOW:
1168 case Builtins::kStoreFastElementIC_NoTransitionHandleCOW:
1169 case Builtins::kElementsTransitionAndStore_NoTransitionHandleCOW:
1170 return STORE_NO_TRANSITION_HANDLE_COW;
1171 default:
1172 UNREACHABLE();
1173 }
1174}
1175
1176} // namespace
1177
1178KeyedAccessStoreMode FeedbackNexus::GetKeyedAccessStoreMode() const {
1179 DCHECK(IsKeyedStoreICKind(kind()) || IsStoreInArrayLiteralICKind(kind()));
1180 KeyedAccessStoreMode mode = STANDARD_STORE;
1181 MapHandles maps;
1182 MaybeObjectHandles handlers;
1183
1184 if (GetKeyType() == PROPERTY) return mode;
1185
1186 ExtractMaps(&maps);
1187 FindHandlers(&handlers, static_cast<int>(maps.size()));
1188 for (const MaybeObjectHandle& maybe_code_handler : handlers) {
1189 // The first handler that isn't the slow handler will have the bits we need.
1190 Handle<Code> handler;
1191 if (maybe_code_handler.object()->IsStoreHandler()) {
1192 Handle<StoreHandler> data_handler =
1193 Handle<StoreHandler>::cast(maybe_code_handler.object());
1194 handler = handle(Code::cast(data_handler->smi_handler()),
1195 vector()->GetIsolate());
1196 } else if (maybe_code_handler.object()->IsSmi()) {
1197 // Skip proxy handlers.
1198 DCHECK_EQ(*(maybe_code_handler.object()),
1199 *StoreHandler::StoreProxy(GetIsolate()));
1200 continue;
1201 } else {
1202 // Element store without prototype chain check.
1203 handler = Handle<Code>::cast(maybe_code_handler.object());
1204 }
1205
1206 if (handler->is_builtin()) {
1207 const int builtin_index = handler->builtin_index();
1208 if (!BuiltinHasKeyedAccessStoreMode(builtin_index)) continue;
1209
1210 mode = KeyedAccessStoreModeForBuiltin(builtin_index);
1211 break;
1212 }
1213 }
1214
1215 return mode;
1216}
1217
1218IcCheckType FeedbackNexus::GetKeyType() const {
1219 DCHECK(IsKeyedStoreICKind(kind()) || IsKeyedLoadICKind(kind()) ||
1220 IsStoreInArrayLiteralICKind(kind()) || IsKeyedHasICKind(kind()));
1221 MaybeObject feedback = GetFeedback();
1222 if (feedback == MaybeObject::FromObject(
1223 *FeedbackVector::MegamorphicSentinel(GetIsolate()))) {
1224 return static_cast<IcCheckType>(
1225 Smi::ToInt(GetFeedbackExtra()->cast<Object>()));
1226 }
1227 return IsPropertyNameFeedback(feedback) ? PROPERTY : ELEMENT;
1228}
1229
1230BinaryOperationHint FeedbackNexus::GetBinaryOperationFeedback() const {
1231 DCHECK_EQ(kind(), FeedbackSlotKind::kBinaryOp);
1232 int feedback = GetFeedback().ToSmi().value();
1233 return BinaryOperationHintFromFeedback(feedback);
1234}
1235
1236CompareOperationHint FeedbackNexus::GetCompareOperationFeedback() const {
1237 DCHECK_EQ(kind(), FeedbackSlotKind::kCompareOp);
1238 int feedback = GetFeedback().ToSmi().value();
1239 return CompareOperationHintFromFeedback(feedback);
1240}
1241
1242ForInHint FeedbackNexus::GetForInFeedback() const {
1243 DCHECK_EQ(kind(), FeedbackSlotKind::kForIn);
1244 int feedback = GetFeedback().ToSmi().value();
1245 return ForInHintFromFeedback(feedback);
1246}
1247
1248MaybeHandle<JSObject> FeedbackNexus::GetConstructorFeedback() const {
1249 DCHECK_EQ(kind(), FeedbackSlotKind::kInstanceOf);
1250 Isolate* isolate = GetIsolate();
1251 MaybeObject feedback = GetFeedback();
1252 HeapObject heap_object;
1253 if (feedback->GetHeapObjectIfWeak(&heap_object)) {
1254 return handle(JSObject::cast(heap_object), isolate);
1255 }
1256 return MaybeHandle<JSObject>();
1257}
1258
1259namespace {
1260
1261bool InList(Handle<ArrayList> types, Handle<String> type) {
1262 for (int i = 0; i < types->Length(); i++) {
1263 Object obj = types->Get(i);
1264 if (String::cast(obj)->Equals(*type)) {
1265 return true;
1266 }
1267 }
1268 return false;
1269}
1270} // anonymous namespace
1271
1272void FeedbackNexus::Collect(Handle<String> type, int position) {
1273 DCHECK(IsTypeProfileKind(kind()));
1274 DCHECK_GE(position, 0);
1275 Isolate* isolate = GetIsolate();
1276
1277 MaybeObject const feedback = GetFeedback();
1278
1279 // Map source position to collection of types
1280 Handle<SimpleNumberDictionary> types;
1281
1282 if (feedback == MaybeObject::FromObject(
1283 *FeedbackVector::UninitializedSentinel(isolate))) {
1284 types = SimpleNumberDictionary::New(isolate, 1);
1285 } else {
1286 types = handle(
1287 SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1288 isolate);
1289 }
1290
1291 Handle<ArrayList> position_specific_types;
1292
1293 int entry = types->FindEntry(isolate, position);
1294 if (entry == SimpleNumberDictionary::kNotFound) {
1295 position_specific_types = ArrayList::New(isolate, 1);
1296 types = SimpleNumberDictionary::Set(
1297 isolate, types, position,
1298 ArrayList::Add(isolate, position_specific_types, type));
1299 } else {
1300 DCHECK(types->ValueAt(entry)->IsArrayList());
1301 position_specific_types =
1302 handle(ArrayList::cast(types->ValueAt(entry)), isolate);
1303 if (!InList(position_specific_types, type)) { // Add type
1304 types = SimpleNumberDictionary::Set(
1305 isolate, types, position,
1306 ArrayList::Add(isolate, position_specific_types, type));
1307 }
1308 }
1309 SetFeedback(*types);
1310}
1311
1312std::vector<int> FeedbackNexus::GetSourcePositions() const {
1313 DCHECK(IsTypeProfileKind(kind()));
1314 std::vector<int> source_positions;
1315 Isolate* isolate = GetIsolate();
1316
1317 MaybeObject const feedback = GetFeedback();
1318
1319 if (feedback == MaybeObject::FromObject(
1320 *FeedbackVector::UninitializedSentinel(isolate))) {
1321 return source_positions;
1322 }
1323
1324 Handle<SimpleNumberDictionary> types(
1325 SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1326 isolate);
1327
1328 for (int index = SimpleNumberDictionary::kElementsStartIndex;
1329 index < types->length(); index += SimpleNumberDictionary::kEntrySize) {
1330 int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1331 Object key = types->get(key_index);
1332 if (key->IsSmi()) {
1333 int position = Smi::cast(key)->value();
1334 source_positions.push_back(position);
1335 }
1336 }
1337 return source_positions;
1338}
1339
1340std::vector<Handle<String>> FeedbackNexus::GetTypesForSourcePositions(
1341 uint32_t position) const {
1342 DCHECK(IsTypeProfileKind(kind()));
1343 Isolate* isolate = GetIsolate();
1344
1345 MaybeObject const feedback = GetFeedback();
1346 std::vector<Handle<String>> types_for_position;
1347 if (feedback == MaybeObject::FromObject(
1348 *FeedbackVector::UninitializedSentinel(isolate))) {
1349 return types_for_position;
1350 }
1351
1352 Handle<SimpleNumberDictionary> types(
1353 SimpleNumberDictionary::cast(feedback->GetHeapObjectAssumeStrong()),
1354 isolate);
1355
1356 int entry = types->FindEntry(isolate, position);
1357 if (entry == SimpleNumberDictionary::kNotFound) {
1358 return types_for_position;
1359 }
1360 DCHECK(types->ValueAt(entry)->IsArrayList());
1361 Handle<ArrayList> position_specific_types =
1362 Handle<ArrayList>(ArrayList::cast(types->ValueAt(entry)), isolate);
1363 for (int i = 0; i < position_specific_types->Length(); i++) {
1364 Object t = position_specific_types->Get(i);
1365 types_for_position.push_back(Handle<String>(String::cast(t), isolate));
1366 }
1367
1368 return types_for_position;
1369}
1370
1371namespace {
1372
1373Handle<JSObject> ConvertToJSObject(Isolate* isolate,
1374 Handle<SimpleNumberDictionary> feedback) {
1375 Handle<JSObject> type_profile =
1376 isolate->factory()->NewJSObject(isolate->object_function());
1377
1378 for (int index = SimpleNumberDictionary::kElementsStartIndex;
1379 index < feedback->length();
1380 index += SimpleNumberDictionary::kEntrySize) {
1381 int key_index = index + SimpleNumberDictionary::kEntryKeyIndex;
1382 Object key = feedback->get(key_index);
1383 if (key->IsSmi()) {
1384 int value_index = index + SimpleNumberDictionary::kEntryValueIndex;
1385
1386 Handle<ArrayList> position_specific_types(
1387 ArrayList::cast(feedback->get(value_index)), isolate);
1388
1389 int position = Smi::ToInt(key);
1390 JSObject::AddDataElement(
1391 type_profile, position,
1392 isolate->factory()->NewJSArrayWithElements(
1393 ArrayList::Elements(isolate, position_specific_types)),
1394 PropertyAttributes::NONE);
1395 }
1396 }
1397 return type_profile;
1398}
1399} // namespace
1400
1401JSObject FeedbackNexus::GetTypeProfile() const {
1402 DCHECK(IsTypeProfileKind(kind()));
1403 Isolate* isolate = GetIsolate();
1404
1405 MaybeObject const feedback = GetFeedback();
1406
1407 if (feedback == MaybeObject::FromObject(
1408 *FeedbackVector::UninitializedSentinel(isolate))) {
1409 return *isolate->factory()->NewJSObject(isolate->object_function());
1410 }
1411
1412 return *ConvertToJSObject(isolate,
1413 handle(SimpleNumberDictionary::cast(
1414 feedback->GetHeapObjectAssumeStrong()),
1415 isolate));
1416}
1417
1418void FeedbackNexus::ResetTypeProfile() {
1419 DCHECK(IsTypeProfileKind(kind()));
1420 SetFeedback(*FeedbackVector::UninitializedSentinel(GetIsolate()));
1421}
1422
1423} // namespace internal
1424} // namespace v8
1425