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