1// Copyright 2018 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_OBJECTS_ALLOCATION_SITE_H_
6#define V8_OBJECTS_ALLOCATION_SITE_H_
7
8#include "src/objects/objects.h"
9#include "src/objects/struct.h"
10
11// Has to be the last include (doesn't have include guards):
12#include "src/objects/object-macros.h"
13
14namespace v8 {
15namespace internal {
16
17enum InstanceType : uint16_t;
18
19#include "torque-generated/src/objects/allocation-site-tq.inc"
20
21class AllocationSite : public Struct {
22 public:
23  NEVER_READ_ONLY_SPACE
24  static const uint32_t kMaximumArrayBytesToPretransition = 8 * 1024;
25  static const double kPretenureRatio;
26  static const int kPretenureMinimumCreated = 100;
27
28  // Values for pretenure decision field.
29  enum PretenureDecision {
30    kUndecided = 0,
31    kDontTenure = 1,
32    kMaybeTenure = 2,
33    kTenure = 3,
34    kZombie = 4,  // See comment to IsZombie() for documentation.
35    kLastPretenureDecisionValue = kZombie
36  };
37
38  const char* PretenureDecisionName(PretenureDecision decision);
39
40  // Contains either a Smi-encoded bitfield or a boilerplate. If it's a Smi the
41  // AllocationSite is for a constructed Array.
42  DECL_ACCESSORS(transition_info_or_boilerplate, Object)
43  DECL_RELEASE_ACQUIRE_ACCESSORS(transition_info_or_boilerplate, Object)
44  DECL_GETTER(boilerplate, JSObject)
45  DECL_RELEASE_ACQUIRE_ACCESSORS(boilerplate, JSObject)
46  DECL_INT_ACCESSORS(transition_info)
47
48  // nested_site threads a list of sites that represent nested literals
49  // walked in a particular order. So [[1, 2], 1, 2] will have one
50  // nested_site, but [[1, 2], 3, [4]] will have a list of two.
51  DECL_ACCESSORS(nested_site, Object)
52
53  // Bitfield containing pretenuring information.
54  DECL_RELAXED_INT32_ACCESSORS(pretenure_data)
55
56  DECL_INT32_ACCESSORS(pretenure_create_count)
57  DECL_ACCESSORS(dependent_code, DependentCode)
58
59  // heap->allocation_site_list() points to the last AllocationSite which form
60  // a linked list through the weak_next property. The GC might remove elements
61  // from the list by updateing weak_next.
62  DECL_ACCESSORS(weak_next, Object)
63
64  inline void Initialize();
65
66  // Checks if the allocation site contain weak_next field;
67  inline bool HasWeakNext() const;
68
69  // This method is expensive, it should only be called for reporting.
70  bool IsNested();
71
72  // transition_info bitfields, for constructed array transition info.
73  using ElementsKindBits = base::BitField<ElementsKind, 0, 6>;
74  using DoNotInlineBit = base::BitField<bool, 6, 1>;
75  // Unused bits 7-30.
76
77  // Bitfields for pretenure_data
78  using MementoFoundCountBits = base::BitField<int, 0, 26>;
79  using PretenureDecisionBits = base::BitField<PretenureDecision, 26, 3>;
80  using DeoptDependentCodeBit = base::BitField<bool, 29, 1>;
81  STATIC_ASSERT(PretenureDecisionBits::kMax >= kLastPretenureDecisionValue);
82
83  // Increments the mementos found counter and returns true when the first
84  // memento was found for a given allocation site.
85  inline bool IncrementMementoFoundCount(int increment = 1);
86
87  inline void IncrementMementoCreateCount();
88
89  AllocationType GetAllocationType() const;
90
91  void ResetPretenureDecision();
92
93  inline PretenureDecision pretenure_decision() const;
94  inline void set_pretenure_decision(PretenureDecision decision);
95
96  inline bool deopt_dependent_code() const;
97  inline void set_deopt_dependent_code(bool deopt);
98
99  inline int memento_found_count() const;
100  inline void set_memento_found_count(int count);
101
102  inline int memento_create_count() const;
103  inline void set_memento_create_count(int count);
104
105  // A "zombie" AllocationSite is one which has no more strong roots to
106  // it, and yet must be maintained until the next GC. The reason is that
107  // it may be that in new space there are AllocationMementos hanging around
108  // which point to the AllocationSite. If we scavenge these AllocationSites
109  // too soon, those AllocationMementos will end up pointing to garbage
110  // addresses. The garbage collector marks such AllocationSites as zombies
111  // when it discovers there are no roots, allowing the subsequent collection
112  // pass to recognize zombies and discard them later.
113  inline bool IsZombie() const;
114
115  inline bool IsMaybeTenure() const;
116
117  inline void MarkZombie();
118
119  inline bool MakePretenureDecision(PretenureDecision current_decision,
120                                    double ratio, bool maximum_size_scavenge);
121
122  inline bool DigestPretenuringFeedback(bool maximum_size_scavenge);
123
124  inline ElementsKind GetElementsKind() const;
125  inline void SetElementsKind(ElementsKind kind);
126
127  inline bool CanInlineCall() const;
128  inline void SetDoNotInlineCall();
129
130  inline bool PointsToLiteral() const;
131
132  template <AllocationSiteUpdateMode update_or_check =
133                AllocationSiteUpdateMode::kUpdate>
134  static bool DigestTransitionFeedback(Handle<AllocationSite> site,
135                                       ElementsKind to_kind);
136
137  DECL_PRINTER(AllocationSite)
138  DECL_VERIFIER(AllocationSite)
139
140  DECL_CAST(AllocationSite)
141  static inline bool ShouldTrack(ElementsKind boilerplate_elements_kind);
142  static bool ShouldTrack(ElementsKind from, ElementsKind to);
143  static inline bool CanTrack(InstanceType type);
144
145  // Layout description.
146  // AllocationSite has to start with TransitionInfoOrboilerPlateOffset
147  // and end with WeakNext field.
148  #define ALLOCATION_SITE_FIELDS(V)                     \
149    V(kStartOffset, 0)                                  \
150    V(kTransitionInfoOrBoilerplateOffset, kTaggedSize)  \
151    V(kNestedSiteOffset, kTaggedSize)                   \
152    V(kDependentCodeOffset, kTaggedSize)                \
153    V(kCommonPointerFieldEndOffset, 0)                  \
154    V(kPretenureDataOffset, kInt32Size)                 \
155    V(kPretenureCreateCountOffset, kInt32Size)          \
156    /* Size of AllocationSite without WeakNext field */ \
157    V(kSizeWithoutWeakNext, 0)                          \
158    V(kWeakNextOffset, kTaggedSize)                     \
159    /* Size of AllocationSite with WeakNext field */    \
160    V(kSizeWithWeakNext, 0)
161
162  DEFINE_FIELD_OFFSET_CONSTANTS(HeapObject::kHeaderSize, ALLOCATION_SITE_FIELDS)
163  #undef ALLOCATION_SITE_FIELDS
164
165  class BodyDescriptor;
166
167 private:
168  inline bool PretenuringDecisionMade() const;
169
170  OBJECT_CONSTRUCTORS(AllocationSite, Struct);
171};
172
173class AllocationMemento
174    : public TorqueGeneratedAllocationMemento<AllocationMemento, Struct> {
175 public:
176  DECL_ACCESSORS(allocation_site, Object)
177
178  inline bool IsValid() const;
179  inline AllocationSite GetAllocationSite() const;
180  inline Address GetAllocationSiteUnchecked() const;
181
182  DECL_PRINTER(AllocationMemento)
183
184  using BodyDescriptor = StructBodyDescriptor;
185
186  TQ_OBJECT_CONSTRUCTORS(AllocationMemento)
187};
188
189}  // namespace internal
190}  // namespace v8
191
192#include "src/objects/object-macros-undef.h"
193
194#endif  // V8_OBJECTS_ALLOCATION_SITE_H_
195