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