V8 API Reference, 7.2.502.16 (for Deno 0.2.4)
handler-configuration.cc
1 // Copyright 2017 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/ic/handler-configuration.h"
6 
7 #include "src/code-factory.h"
8 #include "src/ic/handler-configuration-inl.h"
9 #include "src/objects/data-handler-inl.h"
10 #include "src/objects/maybe-object.h"
11 #include "src/transitions.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 namespace {
17 
18 template <typename BitField>
19 Handle<Smi> SetBitFieldValue(Isolate* isolate, Handle<Smi> smi_handler,
20  typename BitField::FieldType value) {
21  int config = smi_handler->value();
22  config = BitField::update(config, true);
23  return handle(Smi::FromInt(config), isolate);
24 }
25 
26 // TODO(ishell): Remove templatezation once we move common bits from
27 // Load/StoreHandler to the base class.
28 template <typename ICHandler, bool fill_handler = true>
29 int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
30  Handle<Smi>* smi_handler, Handle<Map> receiver_map,
31  Handle<JSReceiver> holder, MaybeObjectHandle data1,
32  MaybeObjectHandle maybe_data2) {
33  int checks_count = 0;
34  // Holder-is-receiver case itself does not add entries unless there is an
35  // optional data2 value provided.
36 
37  if (receiver_map->IsPrimitiveMap() ||
38  receiver_map->is_access_check_needed()) {
39  DCHECK(!receiver_map->IsJSGlobalObjectMap());
40  // The validity cell check for primitive and global proxy receivers does
41  // not guarantee that certain native context ever had access to other
42  // native context. However, a handler created for one native context could
43  // be used in other native context through the megamorphic stub cache.
44  // So we record the original native context to which this handler
45  // corresponds.
46  if (fill_handler) {
47  Handle<Context> native_context = isolate->native_context();
48  handler->set_data2(HeapObjectReference::Weak(*native_context));
49  } else {
50  // Enable access checks on receiver.
51  typedef typename ICHandler::DoAccessCheckOnReceiverBits Bit;
52  *smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true);
53  }
54  checks_count++;
55  } else if (receiver_map->is_dictionary_map() &&
56  !receiver_map->IsJSGlobalObjectMap()) {
57  if (!fill_handler) {
58  // Enable lookup on receiver.
59  typedef typename ICHandler::LookupOnReceiverBits Bit;
60  *smi_handler = SetBitFieldValue<Bit>(isolate, *smi_handler, true);
61  }
62  }
63  if (fill_handler) {
64  handler->set_data1(*data1);
65  }
66  if (!maybe_data2.is_null()) {
67  if (fill_handler) {
68  // This value will go either to data2 or data3 slot depending on whether
69  // data2 slot is already occupied by native context.
70  if (checks_count == 0) {
71  handler->set_data2(*maybe_data2);
72  } else {
73  DCHECK_EQ(1, checks_count);
74  handler->set_data3(*maybe_data2);
75  }
76  }
77  checks_count++;
78  }
79  return checks_count;
80 }
81 
82 // Returns 0 if the validity cell check is enough to ensure that the
83 // prototype chain from |receiver_map| till |holder| did not change.
84 // If the |holder| is an empty handle then the full prototype chain is
85 // checked.
86 // Returns -1 if the handler has to be compiled or the number of prototype
87 // checks otherwise.
88 template <typename ICHandler>
89 int GetPrototypeCheckCount(
90  Isolate* isolate, Handle<Smi>* smi_handler, Handle<Map> receiver_map,
91  Handle<JSReceiver> holder, MaybeObjectHandle data1,
92  MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
93  DCHECK_NOT_NULL(smi_handler);
94  return InitPrototypeChecksImpl<ICHandler, false>(isolate, Handle<ICHandler>(),
95  smi_handler, receiver_map,
96  holder, data1, maybe_data2);
97 }
98 
99 template <typename ICHandler>
100 void InitPrototypeChecks(Isolate* isolate, Handle<ICHandler> handler,
101  Handle<Map> receiver_map, Handle<JSReceiver> holder,
102  MaybeObjectHandle data1,
103  MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
104  InitPrototypeChecksImpl<ICHandler, true>(
105  isolate, handler, nullptr, receiver_map, holder, data1, maybe_data2);
106 }
107 
108 } // namespace
109 
110 // static
111 Handle<Object> LoadHandler::LoadFromPrototype(Isolate* isolate,
112  Handle<Map> receiver_map,
113  Handle<JSReceiver> holder,
114  Handle<Smi> smi_handler,
115  MaybeObjectHandle maybe_data1,
116  MaybeObjectHandle maybe_data2) {
117  MaybeObjectHandle data1;
118  if (maybe_data1.is_null()) {
119  data1 = MaybeObjectHandle::Weak(holder);
120  } else {
121  data1 = maybe_data1;
122  }
123 
124  int checks_count = GetPrototypeCheckCount<LoadHandler>(
125  isolate, &smi_handler, receiver_map, holder, data1, maybe_data2);
126 
127  Handle<Object> validity_cell =
128  Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
129 
130  int data_count = 1 + checks_count;
131  Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
132 
133  handler->set_smi_handler(*smi_handler);
134  handler->set_validity_cell(*validity_cell);
135  InitPrototypeChecks(isolate, handler, receiver_map, holder, data1,
136  maybe_data2);
137  return handler;
138 }
139 
140 // static
141 Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
142  Handle<Map> receiver_map,
143  const MaybeObjectHandle& holder,
144  Handle<Smi> smi_handler) {
145  Handle<JSReceiver> end; // null handle, means full prototype chain lookup.
146  MaybeObjectHandle data1 = holder;
147  int checks_count = GetPrototypeCheckCount<LoadHandler>(
148  isolate, &smi_handler, receiver_map, end, data1);
149 
150  Handle<Object> validity_cell =
151  Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
152  if (validity_cell->IsSmi()) {
153  DCHECK_EQ(0, checks_count);
154  // Lookup on receiver isn't supported in case of a simple smi handler.
155  if (!LookupOnReceiverBits::decode(smi_handler->value())) return smi_handler;
156  }
157 
158  int data_count = 1 + checks_count;
159  Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_count);
160 
161  handler->set_smi_handler(*smi_handler);
162  handler->set_validity_cell(*validity_cell);
163  InitPrototypeChecks(isolate, handler, receiver_map, end, data1);
164  return handler;
165 }
166 
167 // static
168 KeyedAccessLoadMode LoadHandler::GetKeyedAccessLoadMode(MaybeObject handler) {
169  DisallowHeapAllocation no_gc;
170  if (handler->IsSmi()) {
171  int const raw_handler = handler.ToSmi().value();
172  Kind const kind = KindBits::decode(raw_handler);
173  if ((kind == kElement || kind == kIndexedString) &&
174  AllowOutOfBoundsBits::decode(raw_handler)) {
175  return LOAD_IGNORE_OUT_OF_BOUNDS;
176  }
177  }
178  return STANDARD_LOAD;
179 }
180 
181 // static
182 Handle<Object> StoreHandler::StoreElementTransition(
183  Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition,
184  KeyedAccessStoreMode store_mode) {
185  Handle<Code> stub =
186  CodeFactory::ElementsTransitionAndStore(isolate, store_mode).code();
187  Handle<Object> validity_cell =
188  Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
189  Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
190  handler->set_smi_handler(*stub);
191  handler->set_validity_cell(*validity_cell);
192  handler->set_data1(HeapObjectReference::Weak(*transition));
193  return handler;
194 }
195 
196 MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
197  Handle<Map> transition_map) {
198  bool is_dictionary_map = transition_map->is_dictionary_map();
199 #ifdef DEBUG
200  if (!is_dictionary_map) {
201  int descriptor = transition_map->LastAdded();
202  Handle<DescriptorArray> descriptors(transition_map->instance_descriptors(),
203  isolate);
204  PropertyDetails details = descriptors->GetDetails(descriptor);
205  if (descriptors->GetKey(descriptor)->IsPrivate()) {
206  DCHECK_EQ(DONT_ENUM, details.attributes());
207  } else {
208  DCHECK_EQ(NONE, details.attributes());
209  }
210  Representation representation = details.representation();
211  DCHECK(!representation.IsNone());
212  }
213 #endif
214  // Declarative handlers don't support access checks.
215  DCHECK(!transition_map->is_access_check_needed());
216 
217  // Get validity cell value if it is necessary for the handler.
218  Handle<Object> validity_cell;
219  if (is_dictionary_map || !transition_map->IsPrototypeValidityCellValid()) {
220  validity_cell =
221  Map::GetOrCreatePrototypeChainValidityCell(transition_map, isolate);
222  }
223 
224  if (is_dictionary_map) {
225  DCHECK(!transition_map->IsJSGlobalObjectMap());
226  Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(0);
227  // Store normal with enabled lookup on receiver.
228  int config = KindBits::encode(kNormal) | LookupOnReceiverBits::encode(true);
229  handler->set_smi_handler(Smi::FromInt(config));
230  handler->set_validity_cell(*validity_cell);
231  return MaybeObjectHandle(handler);
232 
233  } else {
234  // Ensure the transition map contains a valid prototype validity cell.
235  if (!validity_cell.is_null()) {
236  transition_map->set_prototype_validity_cell(*validity_cell);
237  }
238  return MaybeObjectHandle::Weak(transition_map);
239  }
240 }
241 
242 // static
243 Handle<Object> StoreHandler::StoreThroughPrototype(
244  Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
245  Handle<Smi> smi_handler, MaybeObjectHandle maybe_data1,
246  MaybeObjectHandle maybe_data2) {
247  MaybeObjectHandle data1;
248  if (maybe_data1.is_null()) {
249  data1 = MaybeObjectHandle::Weak(holder);
250  } else {
251  data1 = maybe_data1;
252  }
253 
254  int checks_count = GetPrototypeCheckCount<StoreHandler>(
255  isolate, &smi_handler, receiver_map, holder, data1, maybe_data2);
256 
257  Handle<Object> validity_cell =
258  Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
259  DCHECK_IMPLIES(validity_cell->IsSmi(), checks_count == 0);
260 
261  int data_count = 1 + checks_count;
262  Handle<StoreHandler> handler =
263  isolate->factory()->NewStoreHandler(data_count);
264 
265  handler->set_smi_handler(*smi_handler);
266  handler->set_validity_cell(*validity_cell);
267  InitPrototypeChecks(isolate, handler, receiver_map, holder, data1,
268  maybe_data2);
269  return handler;
270 }
271 
272 // static
273 MaybeObjectHandle StoreHandler::StoreGlobal(Handle<PropertyCell> cell) {
274  return MaybeObjectHandle::Weak(cell);
275 }
276 
277 // static
278 Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
279  Handle<Map> receiver_map,
280  Handle<JSProxy> proxy,
281  Handle<JSReceiver> receiver) {
282  Handle<Smi> smi_handler = StoreProxy(isolate);
283  if (receiver.is_identical_to(proxy)) return smi_handler;
284  return StoreThroughPrototype(isolate, receiver_map, proxy, smi_handler,
285  MaybeObjectHandle::Weak(proxy));
286 }
287 
288 } // namespace internal
289 } // namespace v8
Definition: libplatform.h:13