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 #ifndef V8_TYPE_FEEDBACK_VECTOR_H_
6 #define V8_TYPE_FEEDBACK_VECTOR_H_
7 
8 #include <vector>
9 
10 #include "src/base/logging.h"
11 #include "src/elements-kind.h"
12 #include "src/objects.h"
13 #include "src/zone-containers.h"
14 
15 namespace v8 {
16 namespace internal {
17 
18 
19 enum class FeedbackVectorSlotKind {
20   // This kind means that the slot points to the middle of other slot
21   // which occupies more than one feedback vector element.
22   // There must be no such slots in the system.
23   INVALID,
24 
25   CALL_IC,
26   LOAD_IC,
27   KEYED_LOAD_IC,
28   STORE_IC,
29   KEYED_STORE_IC,
30 
31   // This is a general purpose slot that occupies one feedback vector element.
32   GENERAL,
33 
34   KINDS_NUMBER  // Last value indicating number of kinds.
35 };
36 
37 
38 std::ostream& operator<<(std::ostream& os, FeedbackVectorSlotKind kind);
39 
40 
41 template <typename Derived>
42 class FeedbackVectorSpecBase {
43  public:
44   inline FeedbackVectorSlot AddSlot(FeedbackVectorSlotKind kind);
45 
AddCallICSlot()46   FeedbackVectorSlot AddCallICSlot() {
47     return AddSlot(FeedbackVectorSlotKind::CALL_IC);
48   }
49 
AddLoadICSlot()50   FeedbackVectorSlot AddLoadICSlot() {
51     return AddSlot(FeedbackVectorSlotKind::LOAD_IC);
52   }
53 
AddKeyedLoadICSlot()54   FeedbackVectorSlot AddKeyedLoadICSlot() {
55     return AddSlot(FeedbackVectorSlotKind::KEYED_LOAD_IC);
56   }
57 
AddStoreICSlot()58   FeedbackVectorSlot AddStoreICSlot() {
59     return AddSlot(FeedbackVectorSlotKind::STORE_IC);
60   }
61 
AddKeyedStoreICSlot()62   FeedbackVectorSlot AddKeyedStoreICSlot() {
63     return AddSlot(FeedbackVectorSlotKind::KEYED_STORE_IC);
64   }
65 
AddGeneralSlot()66   FeedbackVectorSlot AddGeneralSlot() {
67     return AddSlot(FeedbackVectorSlotKind::GENERAL);
68   }
69 };
70 
71 
72 class StaticFeedbackVectorSpec
73     : public FeedbackVectorSpecBase<StaticFeedbackVectorSpec> {
74  public:
StaticFeedbackVectorSpec()75   StaticFeedbackVectorSpec() : slots_(0) {}
76 
slots()77   int slots() const { return slots_; }
78 
GetKind(int slot)79   FeedbackVectorSlotKind GetKind(int slot) const {
80     DCHECK(slot >= 0 && slot < slots_);
81     return kinds_[slot];
82   }
83 
84  private:
85   friend class FeedbackVectorSpecBase<StaticFeedbackVectorSpec>;
86 
append(FeedbackVectorSlotKind kind)87   void append(FeedbackVectorSlotKind kind) {
88     DCHECK(slots_ < kMaxLength);
89     kinds_[slots_++] = kind;
90   }
91 
92   static const int kMaxLength = 12;
93 
94   int slots_;
95   FeedbackVectorSlotKind kinds_[kMaxLength];
96 };
97 
98 
99 class FeedbackVectorSpec : public FeedbackVectorSpecBase<FeedbackVectorSpec> {
100  public:
FeedbackVectorSpec(Zone * zone)101   explicit FeedbackVectorSpec(Zone* zone) : slot_kinds_(zone) {
102     slot_kinds_.reserve(16);
103   }
104 
slots()105   int slots() const { return static_cast<int>(slot_kinds_.size()); }
106 
GetKind(int slot)107   FeedbackVectorSlotKind GetKind(int slot) const {
108     return static_cast<FeedbackVectorSlotKind>(slot_kinds_.at(slot));
109   }
110 
111  private:
112   friend class FeedbackVectorSpecBase<FeedbackVectorSpec>;
113 
append(FeedbackVectorSlotKind kind)114   void append(FeedbackVectorSlotKind kind) {
115     slot_kinds_.push_back(static_cast<unsigned char>(kind));
116   }
117 
118   ZoneVector<unsigned char> slot_kinds_;
119 };
120 
121 
122 // The shape of the TypeFeedbackMetadata is an array with:
123 // 0: slot_count
124 // 1..N: slot kinds packed into a bit vector
125 //
126 class TypeFeedbackMetadata : public FixedArray {
127  public:
128   // Casting.
129   static inline TypeFeedbackMetadata* cast(Object* obj);
130 
131   static const int kSlotsCountIndex = 0;
132   static const int kReservedIndexCount = 1;
133 
134   // Returns number of feedback vector elements used by given slot kind.
135   static inline int GetSlotSize(FeedbackVectorSlotKind kind);
136 
137   bool SpecDiffersFrom(const FeedbackVectorSpec* other_spec) const;
138 
139   // Returns number of slots in the vector.
140   inline int slot_count() const;
141 
142   // Returns slot kind for given slot.
143   FeedbackVectorSlotKind GetKind(FeedbackVectorSlot slot) const;
144 
145   template <typename Spec>
146   static Handle<TypeFeedbackMetadata> New(Isolate* isolate, const Spec* spec);
147 
148 #ifdef OBJECT_PRINT
149   // For gdb debugging.
150   void Print();
151 #endif  // OBJECT_PRINT
152 
153   DECLARE_PRINTER(TypeFeedbackMetadata)
154 
155   static const char* Kind2String(FeedbackVectorSlotKind kind);
156 
157  private:
158   static const int kFeedbackVectorSlotKindBits = 3;
159   STATIC_ASSERT(static_cast<int>(FeedbackVectorSlotKind::KINDS_NUMBER) <
160                 (1 << kFeedbackVectorSlotKindBits));
161 
162   void SetKind(FeedbackVectorSlot slot, FeedbackVectorSlotKind kind);
163 
164   typedef BitSetComputer<FeedbackVectorSlotKind, kFeedbackVectorSlotKindBits,
165                          kSmiValueSize, uint32_t> VectorICComputer;
166 
167   DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackMetadata);
168 };
169 
170 
171 // The shape of the TypeFeedbackVector is an array with:
172 // 0: feedback metadata
173 // 1: ics_with_types
174 // 2: ics_with_generic_info
175 // 3: feedback slot #0 (N >= 3)
176 // ...
177 // N + slot_count - 1: feedback slot #(slot_count-1)
178 //
179 class TypeFeedbackVector : public FixedArray {
180  public:
181   // Casting.
182   static inline TypeFeedbackVector* cast(Object* obj);
183 
184   static const int kMetadataIndex = 0;
185   static const int kReservedIndexCount = 1;
186 
187   inline void ComputeCounts(int* with_type_info, int* generic);
188 
189   inline bool is_empty() const;
190 
191   // Returns number of slots in the vector.
192   inline int slot_count() const;
193 
194   inline TypeFeedbackMetadata* metadata() const;
195 
196   // Conversion from a slot to an integer index to the underlying array.
197   inline int GetIndex(FeedbackVectorSlot slot) const;
198   static int GetIndexFromSpec(const FeedbackVectorSpec* spec,
199                               FeedbackVectorSlot slot);
200 
201   // Conversion from an integer index to the underlying array to a slot.
202   inline FeedbackVectorSlot ToSlot(int index) const;
203   inline Object* Get(FeedbackVectorSlot slot) const;
204   inline void Set(FeedbackVectorSlot slot, Object* value,
205                   WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
206 
207   // Returns slot kind for given slot.
208   inline FeedbackVectorSlotKind GetKind(FeedbackVectorSlot slot) const;
209 
210   static Handle<TypeFeedbackVector> New(Isolate* isolate,
211                                         Handle<TypeFeedbackMetadata> metadata);
212 
213   static Handle<TypeFeedbackVector> Copy(Isolate* isolate,
214                                          Handle<TypeFeedbackVector> vector);
215 
216 #ifdef OBJECT_PRINT
217   // For gdb debugging.
218   void Print();
219 #endif  // OBJECT_PRINT
220 
DECLARE_PRINTER(TypeFeedbackVector)221   DECLARE_PRINTER(TypeFeedbackVector)
222 
223   // Clears the vector slots.
224   void ClearSlots(SharedFunctionInfo* shared) { ClearSlotsImpl(shared, true); }
225 
ClearSlotsAtGCTime(SharedFunctionInfo * shared)226   void ClearSlotsAtGCTime(SharedFunctionInfo* shared) {
227     ClearSlotsImpl(shared, false);
228   }
229 
230   static void ClearAllKeyedStoreICs(Isolate* isolate);
231   void ClearKeyedStoreICs(SharedFunctionInfo* shared);
232 
233   // The object that indicates an uninitialized cache.
234   static inline Handle<Object> UninitializedSentinel(Isolate* isolate);
235 
236   // The object that indicates a megamorphic state.
237   static inline Handle<Object> MegamorphicSentinel(Isolate* isolate);
238 
239   // The object that indicates a premonomorphic state.
240   static inline Handle<Object> PremonomorphicSentinel(Isolate* isolate);
241 
242   // A raw version of the uninitialized sentinel that's safe to read during
243   // garbage collection (e.g., for patching the cache).
244   static inline Object* RawUninitializedSentinel(Isolate* isolate);
245 
246   static const int kDummyLoadICSlot = 0;
247   static const int kDummyKeyedLoadICSlot = 2;
248   static const int kDummyStoreICSlot = 4;
249   static const int kDummyKeyedStoreICSlot = 6;
250 
251   static Handle<TypeFeedbackVector> DummyVector(Isolate* isolate);
DummySlot(int dummyIndex)252   static FeedbackVectorSlot DummySlot(int dummyIndex) {
253     DCHECK(dummyIndex >= 0 && dummyIndex <= kDummyKeyedStoreICSlot);
254     return FeedbackVectorSlot(dummyIndex);
255   }
256 
257  private:
258   void ClearSlotsImpl(SharedFunctionInfo* shared, bool force_clear);
259 
260   DISALLOW_IMPLICIT_CONSTRUCTORS(TypeFeedbackVector);
261 };
262 
263 
264 // The following asserts protect an optimization in type feedback vector
265 // code that looks into the contents of a slot assuming to find a String,
266 // a Symbol, an AllocationSite, a WeakCell, or a FixedArray.
267 STATIC_ASSERT(WeakCell::kSize >= 2 * kPointerSize);
268 STATIC_ASSERT(WeakCell::kValueOffset == AllocationSite::kTransitionInfoOffset);
269 STATIC_ASSERT(WeakCell::kValueOffset == FixedArray::kLengthOffset);
270 STATIC_ASSERT(WeakCell::kValueOffset == Name::kHashFieldSlot);
271 // Verify that an empty hash field looks like a tagged object, but can't
272 // possibly be confused with a pointer.
273 STATIC_ASSERT((Name::kEmptyHashField & kHeapObjectTag) == kHeapObjectTag);
274 STATIC_ASSERT(Name::kEmptyHashField == 0x3);
275 // Verify that a set hash field will not look like a tagged object.
276 STATIC_ASSERT(Name::kHashNotComputedMask == kHeapObjectTag);
277 
278 
279 class TypeFeedbackMetadataIterator {
280  public:
TypeFeedbackMetadataIterator(Handle<TypeFeedbackMetadata> metadata)281   explicit TypeFeedbackMetadataIterator(Handle<TypeFeedbackMetadata> metadata)
282       : metadata_handle_(metadata),
283         slot_(FeedbackVectorSlot(0)),
284         slot_kind_(FeedbackVectorSlotKind::INVALID) {}
285 
TypeFeedbackMetadataIterator(TypeFeedbackMetadata * metadata)286   explicit TypeFeedbackMetadataIterator(TypeFeedbackMetadata* metadata)
287       : metadata_(metadata),
288         slot_(FeedbackVectorSlot(0)),
289         slot_kind_(FeedbackVectorSlotKind::INVALID) {}
290 
HasNext()291   bool HasNext() const { return slot_.ToInt() < metadata()->slot_count(); }
292 
Next()293   FeedbackVectorSlot Next() {
294     DCHECK(HasNext());
295     FeedbackVectorSlot slot = slot_;
296     slot_kind_ = metadata()->GetKind(slot);
297     slot_ = FeedbackVectorSlot(slot_.ToInt() + entry_size());
298     return slot;
299   }
300 
301   // Returns slot kind of the last slot returned by Next().
kind()302   FeedbackVectorSlotKind kind() const {
303     DCHECK_NE(FeedbackVectorSlotKind::INVALID, slot_kind_);
304     DCHECK_NE(FeedbackVectorSlotKind::KINDS_NUMBER, slot_kind_);
305     return slot_kind_;
306   }
307 
308   // Returns entry size of the last slot returned by Next().
entry_size()309   int entry_size() const { return TypeFeedbackMetadata::GetSlotSize(kind()); }
310 
311  private:
metadata()312   TypeFeedbackMetadata* metadata() const {
313     return !metadata_handle_.is_null() ? *metadata_handle_ : metadata_;
314   }
315 
316   // The reason for having a handle and a raw pointer to the meta data is
317   // to have a single iterator implementation for both "handlified" and raw
318   // pointer use cases.
319   Handle<TypeFeedbackMetadata> metadata_handle_;
320   TypeFeedbackMetadata* metadata_;
321   FeedbackVectorSlot slot_;
322   FeedbackVectorSlotKind slot_kind_;
323 };
324 
325 
326 // A FeedbackNexus is the combination of a TypeFeedbackVector and a slot.
327 // Derived classes customize the update and retrieval of feedback.
328 class FeedbackNexus {
329  public:
FeedbackNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)330   FeedbackNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
331       : vector_handle_(vector), vector_(NULL), slot_(slot) {}
FeedbackNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)332   FeedbackNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
333       : vector_(vector), slot_(slot) {}
~FeedbackNexus()334   virtual ~FeedbackNexus() {}
335 
vector_handle()336   Handle<TypeFeedbackVector> vector_handle() const {
337     DCHECK(vector_ == NULL);
338     return vector_handle_;
339   }
vector()340   TypeFeedbackVector* vector() const {
341     return vector_handle_.is_null() ? vector_ : *vector_handle_;
342   }
slot()343   FeedbackVectorSlot slot() const { return slot_; }
344 
ic_state()345   InlineCacheState ic_state() const { return StateFromFeedback(); }
FindFirstMap()346   Map* FindFirstMap() const {
347     MapHandleList maps;
348     ExtractMaps(&maps);
349     if (maps.length() > 0) return *maps.at(0);
350     return NULL;
351   }
352 
353   // TODO(mvstanton): remove FindAllMaps, it didn't survive a code review.
FindAllMaps(MapHandleList * maps)354   void FindAllMaps(MapHandleList* maps) const { ExtractMaps(maps); }
355 
356   virtual InlineCacheState StateFromFeedback() const = 0;
357   virtual int ExtractMaps(MapHandleList* maps) const;
358   virtual MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const;
359   virtual bool FindHandlers(CodeHandleList* code_list, int length = -1) const;
FindFirstName()360   virtual Name* FindFirstName() const { return NULL; }
361 
362   virtual void ConfigureUninitialized();
363   virtual void ConfigurePremonomorphic();
364   virtual void ConfigureMegamorphic();
365 
366   inline Object* GetFeedback() const;
367   inline Object* GetFeedbackExtra() const;
368 
369   inline Isolate* GetIsolate() const;
370 
371  protected:
372   inline void SetFeedback(Object* feedback,
373                           WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
374   inline void SetFeedbackExtra(Object* feedback_extra,
375                                WriteBarrierMode mode = UPDATE_WRITE_BARRIER);
376 
377   Handle<FixedArray> EnsureArrayOfSize(int length);
378   Handle<FixedArray> EnsureExtraArrayOfSize(int length);
379   void InstallHandlers(Handle<FixedArray> array, MapHandleList* maps,
380                        CodeHandleList* handlers);
381 
382  private:
383   // The reason for having a vector handle and a raw pointer is that we can and
384   // should use handles during IC miss, but not during GC when we clear ICs. If
385   // you have a handle to the vector that is better because more operations can
386   // be done, like allocation.
387   Handle<TypeFeedbackVector> vector_handle_;
388   TypeFeedbackVector* vector_;
389   FeedbackVectorSlot slot_;
390 };
391 
392 
393 class CallICNexus final : public FeedbackNexus {
394  public:
395   // Monomorphic call ics store call counts. Platform code needs to increment
396   // the count appropriately (ie, by 2).
397   static const int kCallCountIncrement = 2;
398 
CallICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)399   CallICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
400       : FeedbackNexus(vector, slot) {
401     DCHECK_EQ(FeedbackVectorSlotKind::CALL_IC, vector->GetKind(slot));
402   }
CallICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)403   CallICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
404       : FeedbackNexus(vector, slot) {
405     DCHECK_EQ(FeedbackVectorSlotKind::CALL_IC, vector->GetKind(slot));
406   }
407 
408   void Clear(Code* host);
409 
410   void ConfigureMonomorphicArray();
411   void ConfigureMonomorphic(Handle<JSFunction> function);
412   void ConfigureMegamorphic() final;
413   void ConfigureMegamorphic(int call_count);
414 
415   InlineCacheState StateFromFeedback() const final;
416 
ExtractMaps(MapHandleList * maps)417   int ExtractMaps(MapHandleList* maps) const final {
418     // CallICs don't record map feedback.
419     return 0;
420   }
FindHandlerForMap(Handle<Map> map)421   MaybeHandle<Code> FindHandlerForMap(Handle<Map> map) const final {
422     return MaybeHandle<Code>();
423   }
424   bool FindHandlers(CodeHandleList* code_list, int length = -1) const final {
425     return length == 0;
426   }
427 
428   int ExtractCallCount();
429 };
430 
431 
432 class LoadICNexus : public FeedbackNexus {
433  public:
LoadICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)434   LoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
435       : FeedbackNexus(vector, slot) {
436     DCHECK_EQ(FeedbackVectorSlotKind::LOAD_IC, vector->GetKind(slot));
437   }
LoadICNexus(Isolate * isolate)438   explicit LoadICNexus(Isolate* isolate)
439       : FeedbackNexus(
440             TypeFeedbackVector::DummyVector(isolate),
441             FeedbackVectorSlot(TypeFeedbackVector::kDummyLoadICSlot)) {}
LoadICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)442   LoadICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
443       : FeedbackNexus(vector, slot) {
444     DCHECK_EQ(FeedbackVectorSlotKind::LOAD_IC, vector->GetKind(slot));
445   }
446 
447   void Clear(Code* host);
448 
449   void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Code> handler);
450 
451   void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
452 
453   InlineCacheState StateFromFeedback() const override;
454 };
455 
456 
457 class KeyedLoadICNexus : public FeedbackNexus {
458  public:
KeyedLoadICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)459   KeyedLoadICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
460       : FeedbackNexus(vector, slot) {
461     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector->GetKind(slot));
462   }
KeyedLoadICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)463   KeyedLoadICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
464       : FeedbackNexus(vector, slot) {
465     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_LOAD_IC, vector->GetKind(slot));
466   }
467 
468   void Clear(Code* host);
469 
470   // name can be a null handle for element loads.
471   void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
472                             Handle<Code> handler);
473   // name can be null.
474   void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
475                             CodeHandleList* handlers);
476 
477   InlineCacheState StateFromFeedback() const override;
478   Name* FindFirstName() const override;
479 };
480 
481 
482 class StoreICNexus : public FeedbackNexus {
483  public:
StoreICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)484   StoreICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
485       : FeedbackNexus(vector, slot) {
486     DCHECK_EQ(FeedbackVectorSlotKind::STORE_IC, vector->GetKind(slot));
487   }
StoreICNexus(Isolate * isolate)488   explicit StoreICNexus(Isolate* isolate)
489       : FeedbackNexus(
490             TypeFeedbackVector::DummyVector(isolate),
491             FeedbackVectorSlot(TypeFeedbackVector::kDummyStoreICSlot)) {}
StoreICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)492   StoreICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
493       : FeedbackNexus(vector, slot) {
494     DCHECK_EQ(FeedbackVectorSlotKind::STORE_IC, vector->GetKind(slot));
495   }
496 
497   void Clear(Code* host);
498 
499   void ConfigureMonomorphic(Handle<Map> receiver_map, Handle<Code> handler);
500 
501   void ConfigurePolymorphic(MapHandleList* maps, CodeHandleList* handlers);
502 
503   InlineCacheState StateFromFeedback() const override;
504 };
505 
506 
507 class KeyedStoreICNexus : public FeedbackNexus {
508  public:
KeyedStoreICNexus(Handle<TypeFeedbackVector> vector,FeedbackVectorSlot slot)509   KeyedStoreICNexus(Handle<TypeFeedbackVector> vector, FeedbackVectorSlot slot)
510       : FeedbackNexus(vector, slot) {
511     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, vector->GetKind(slot));
512   }
KeyedStoreICNexus(Isolate * isolate)513   explicit KeyedStoreICNexus(Isolate* isolate)
514       : FeedbackNexus(
515             TypeFeedbackVector::DummyVector(isolate),
516             FeedbackVectorSlot(TypeFeedbackVector::kDummyKeyedStoreICSlot)) {}
KeyedStoreICNexus(TypeFeedbackVector * vector,FeedbackVectorSlot slot)517   KeyedStoreICNexus(TypeFeedbackVector* vector, FeedbackVectorSlot slot)
518       : FeedbackNexus(vector, slot) {
519     DCHECK_EQ(FeedbackVectorSlotKind::KEYED_STORE_IC, vector->GetKind(slot));
520   }
521 
522   void Clear(Code* host);
523 
524   // name can be a null handle for element loads.
525   void ConfigureMonomorphic(Handle<Name> name, Handle<Map> receiver_map,
526                             Handle<Code> handler);
527   // name can be null.
528   void ConfigurePolymorphic(Handle<Name> name, MapHandleList* maps,
529                             CodeHandleList* handlers);
530   void ConfigurePolymorphic(MapHandleList* maps,
531                             MapHandleList* transitioned_maps,
532                             CodeHandleList* handlers);
533 
534   KeyedAccessStoreMode GetKeyedAccessStoreMode() const;
535   IcCheckType GetKeyType() const;
536 
537   InlineCacheState StateFromFeedback() const override;
538   Name* FindFirstName() const override;
539 };
540 }  // namespace internal
541 }  // namespace v8
542 
543 #endif  // V8_TRANSITIONS_H_
544