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