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