v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
handler-configuration.cc
Go to the documentation of this file.
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
6
12
13namespace v8 {
14namespace internal {
15
16namespace {
17
18template <typename BitField>
19Tagged<Smi> SetBitFieldValue(Isolate* isolate, Tagged<Smi> smi_handler,
20 typename BitField::FieldType value) {
21 int config = smi_handler.value();
22 config = BitField::update(config, true);
23 return Smi::FromInt(config);
24}
25
26// TODO(ishell): Remove templatezation once we move common bits from
27// Load/StoreHandler to the base class.
28template <typename ICHandler, bool fill_handler = true>
29int InitPrototypeChecksImpl(Isolate* isolate, DirectHandle<ICHandler> handler,
30 Tagged<Smi>* smi_handler,
31 DirectHandle<Map> lookup_start_object_map,
32 MaybeObjectDirectHandle data1,
33 MaybeObjectDirectHandle maybe_data2) {
34 int data_size = 1;
35 // Holder-is-receiver case itself does not add entries unless there is an
36 // optional data2 value provided.
37
38 DCHECK_IMPLIES(IsJSGlobalObjectMap(*lookup_start_object_map),
39 lookup_start_object_map->is_prototype_map());
40
41 if (IsPrimitiveMap(*lookup_start_object_map) ||
42 lookup_start_object_map->is_access_check_needed()) {
43 DCHECK(!IsJSGlobalObjectMap(*lookup_start_object_map));
44 // The validity cell check for primitive and global proxy receivers does
45 // not guarantee that certain native context ever had access to other
46 // native context. However, a handler created for one native context could
47 // be used in other native context through the megamorphic stub cache.
48 // So we record the original native context to which this handler
49 // corresponds.
50 if (fill_handler) {
51 DirectHandle<Context> native_context = isolate->native_context();
52 handler->set_data2(MakeWeak(*native_context));
53 } else {
54 // Enable access checks on the lookup start object.
55 *smi_handler = SetBitFieldValue<
56 typename ICHandler::DoAccessCheckOnLookupStartObjectBits>(
57 isolate, *smi_handler, true);
58 }
59 data_size++;
60 } else if (lookup_start_object_map->is_dictionary_map() &&
61 !IsJSGlobalObjectMap(*lookup_start_object_map)) {
62 if (!fill_handler) {
63 // Enable lookup on lookup start object.
64 *smi_handler =
65 SetBitFieldValue<typename ICHandler::LookupOnLookupStartObjectBits>(
66 isolate, *smi_handler, true);
67 }
68 }
69 if (fill_handler) {
70 handler->set_data1(*data1);
71 }
72 if (!maybe_data2.is_null()) {
73 if (fill_handler) {
74 // This value will go either to data2 or data3 slot depending on whether
75 // data2 slot is already occupied by native context.
76 if (data_size == 1) {
77 handler->set_data2(*maybe_data2);
78 } else {
79 DCHECK_EQ(2, data_size);
80 handler->set_data3(*maybe_data2);
81 }
82 }
83 data_size++;
84 }
85 return data_size;
86}
87
88// Returns 0 if the validity cell check is enough to ensure that the
89// prototype chain from |lookup_start_object_map| till |holder| did not change.
90// If the |holder| is an empty handle then the full prototype chain is
91// checked.
92template <typename ICHandler>
93int GetHandlerDataSize(
94 Isolate* isolate, Tagged<Smi>* smi_handler,
95 DirectHandle<Map> lookup_start_object_map, MaybeObjectDirectHandle data1,
96 MaybeObjectDirectHandle maybe_data2 = MaybeObjectDirectHandle()) {
97 DCHECK_NOT_NULL(smi_handler);
98 return InitPrototypeChecksImpl<ICHandler, false>(
99 isolate, DirectHandle<ICHandler>(), smi_handler, lookup_start_object_map,
100 data1, maybe_data2);
101}
102
103template <typename ICHandler>
104void InitPrototypeChecks(
105 Isolate* isolate, DirectHandle<ICHandler> handler,
106 DirectHandle<Map> lookup_start_object_map, MaybeObjectDirectHandle data1,
107 MaybeObjectDirectHandle maybe_data2 = MaybeObjectDirectHandle()) {
108 InitPrototypeChecksImpl<ICHandler, true>(
109 isolate, handler, nullptr, lookup_start_object_map, data1, maybe_data2);
110}
111
112} // namespace
113
114// static
116 Isolate* isolate, DirectHandle<Map> lookup_start_object_map,
117 DirectHandle<JSReceiver> holder, Tagged<Smi> smi_handler,
118 MaybeObjectDirectHandle maybe_data1, MaybeObjectDirectHandle maybe_data2) {
120 if (maybe_data1.is_null()) {
122 } else {
123 data1 = maybe_data1;
124 }
125
126 int data_size = GetHandlerDataSize<LoadHandler>(
127 isolate, &smi_handler, lookup_start_object_map, data1, maybe_data2);
128
130 Map::GetOrCreatePrototypeChainValidityCell(lookup_start_object_map,
131 isolate);
132
133 Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
134
135 handler->set_smi_handler(smi_handler);
136 handler->set_validity_cell(*validity_cell);
137 InitPrototypeChecks(isolate, direct_handle(handler), lookup_start_object_map,
138 data1, maybe_data2);
139 return handler;
140}
141
142// static
144 Isolate* isolate, DirectHandle<Map> lookup_start_object_map,
145 const MaybeObjectDirectHandle& holder, Handle<Smi> smi_handler_handle) {
146 Tagged<Smi> smi_handler = *smi_handler_handle;
148 int data_size = GetHandlerDataSize<LoadHandler>(
149 isolate, &smi_handler, lookup_start_object_map, data1);
150
152 Map::GetOrCreatePrototypeChainValidityCell(lookup_start_object_map,
153 isolate);
154 if (IsSmi(*validity_cell)) {
155 DCHECK_EQ(1, data_size);
156 // Lookup on lookup start object isn't supported in case of a simple smi
157 // handler.
159 return smi_handler_handle;
160 }
161 }
162
163 Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
164
165 handler->set_smi_handler(smi_handler);
166 handler->set_validity_cell(*validity_cell);
167 InitPrototypeChecks(isolate, direct_handle(handler), lookup_start_object_map,
168 data1);
169 return handler;
170}
171
172// static
174 Tagged<MaybeObject> handler) {
176 if (IsSmi(handler)) {
177 int const raw_handler = handler.ToSmi().value();
178 Kind const kind = KindBits::decode(raw_handler);
180 bool handle_oob = AllowOutOfBoundsBits::decode(raw_handler);
181 bool handle_holes = AllowHandlingHole::decode(raw_handler);
182 return CreateKeyedAccessLoadMode(handle_oob, handle_holes);
183 }
184 }
186}
187
188// static
190 Tagged<MaybeObject> handler) {
192 if (IsSmi(handler)) {
193 int const raw_handler = handler.ToSmi().value();
194 Kind const kind = KindBits::decode(raw_handler);
195 // All the handlers except the Slow Handler that use tshe
196 // KeyedAccessStoreMode, compute it using KeyedAccessStoreModeForBuiltin
197 // method. Hence if any other Handler get to this path, just return
198 // KeyedAccessStoreMode::kInBounds.
199 if (kind != Kind::kSlow) {
201 }
202 KeyedAccessStoreMode store_mode =
204 return store_mode;
205 }
207}
208
209// static
211 Isolate* isolate, DirectHandle<Map> receiver_map,
212 DirectHandle<Map> transition, KeyedAccessStoreMode store_mode,
213 MaybeDirectHandle<UnionOf<Smi, Cell>> prev_validity_cell) {
214 DirectHandle<Code> code =
215 ElementsTransitionAndStoreBuiltin(isolate, store_mode);
217 if (!prev_validity_cell.ToHandle(&validity_cell)) {
219 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
220 }
221 Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
222 handler->set_smi_handler(*code);
223 handler->set_validity_cell(*validity_cell);
224 handler->set_data1(MakeWeak(*transition));
225 return handler;
226}
227
228// static
230 Handle<Map> transition_map) {
231 bool is_dictionary_map = transition_map->is_dictionary_map();
232#ifdef DEBUG
233 if (!is_dictionary_map) {
234 InternalIndex descriptor = transition_map->LastAdded();
236 transition_map->instance_descriptors(isolate), isolate);
237 PropertyDetails details = descriptors->GetDetails(descriptor);
238 if (descriptors->GetKey(descriptor)->IsPrivate()) {
239 DCHECK_EQ(DONT_ENUM, details.attributes());
240 } else {
241 DCHECK_EQ(NONE, details.attributes());
242 }
243 Representation representation = details.representation();
244 DCHECK(!representation.IsNone());
245 }
246#endif
247 // Declarative handlers don't support access checks.
248 DCHECK(!transition_map->is_access_check_needed());
249
250 // StoreOwnTransition does not involve any prototype checks.
251 if (is_dictionary_map) {
252 DCHECK(!IsJSGlobalObjectMap(*transition_map));
253 int config = KindBits::encode(Kind::kNormal);
254 return MaybeObjectHandle(Tagged<Object>(Smi::FromInt(config)), isolate);
255
256 } else {
257 return MaybeObjectHandle::Weak(transition_map);
258 }
259}
260
261// static
263 Handle<Map> transition_map) {
264 bool is_dictionary_map = transition_map->is_dictionary_map();
265#ifdef DEBUG
266 if (!is_dictionary_map) {
267 InternalIndex descriptor = transition_map->LastAdded();
269 transition_map->instance_descriptors(isolate), isolate);
270 // Private fields must be added via StoreOwnTransition handler.
271 DCHECK(!descriptors->GetKey(descriptor)->IsPrivateName());
272 PropertyDetails details = descriptors->GetDetails(descriptor);
273 if (descriptors->GetKey(descriptor)->IsPrivate()) {
274 DCHECK_EQ(DONT_ENUM, details.attributes());
275 } else {
276 DCHECK_EQ(NONE, details.attributes());
277 }
278 Representation representation = details.representation();
279 DCHECK(!representation.IsNone());
280 }
281#endif
282 // Declarative handlers don't support access checks.
283 DCHECK(!transition_map->is_access_check_needed());
284
285 // Get validity cell value if it is necessary for the handler.
287 if (is_dictionary_map || !transition_map->IsPrototypeValidityCellValid()) {
289 Map::GetOrCreatePrototypeChainValidityCell(transition_map, isolate);
290 }
291
292 if (is_dictionary_map) {
293 DCHECK(!IsJSGlobalObjectMap(*transition_map));
294 Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(0);
295 // Store normal with enabled lookup on receiver.
296 int config = KindBits::encode(Kind::kNormal) |
298 handler->set_smi_handler(Smi::FromInt(config));
299 handler->set_validity_cell(*validity_cell);
300 return MaybeObjectHandle(handler);
301
302 } else {
303 // Ensure the transition map contains a valid prototype validity cell.
304 if (!validity_cell.is_null()) {
305 transition_map->set_prototype_validity_cell(*validity_cell,
307 }
308 return MaybeObjectHandle::Weak(transition_map);
309 }
310}
311
312// static
314 Isolate* isolate, DirectHandle<Map> receiver_map,
315 DirectHandle<JSReceiver> holder, Tagged<Smi> smi_handler,
316 MaybeObjectDirectHandle maybe_data1, MaybeObjectDirectHandle maybe_data2) {
318 if (maybe_data1.is_null()) {
320 } else {
321 data1 = maybe_data1;
322 }
323
324 int data_size = GetHandlerDataSize<StoreHandler>(
325 isolate, &smi_handler, receiver_map, data1, maybe_data2);
326
328 Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
329
330 Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(data_size);
331
332 handler->set_smi_handler(smi_handler);
333 handler->set_validity_cell(*validity_cell);
334 InitPrototypeChecks(isolate, direct_handle(handler), receiver_map, data1,
335 maybe_data2);
336 return handler;
337}
338
339// static
343
344// static
346 DirectHandle<Map> receiver_map,
347 Handle<JSProxy> proxy,
350 if (receiver.is_identical_to(proxy)) return smi_handler;
351 return StoreThroughPrototype(isolate, receiver_map, proxy, *smi_handler,
353}
354
356 if (IsSmi(handler)) {
357 auto kind = LoadHandler::KindBits::decode(handler.ToSmi().value());
358 return kind == LoadHandler::Kind::kSlow ||
360 }
361 return IsLoadHandler(handler);
362}
363
364#if defined(OBJECT_PRINT)
365namespace {
366void PrintSmiLoadHandler(int raw_handler, std::ostream& os) {
368 os << "kind = ";
369 switch (kind) {
371 os << "kElement, ";
372 if (LoadHandler::IsWasmArrayBits::decode(raw_handler)) {
373 os << "WasmArray, "
375
376 } else {
377 os << "allow out of bounds = "
379 << ", is JSArray = "
381 << ", alow reading holes = "
383 << ", elements kind = "
386 }
387 break;
389 os << "kIndexedString, allow out of bounds = "
391 break;
393 os << "kNormal";
394 break;
396 os << "kGlobal";
397 break;
399 if (LoadHandler::IsWasmStructBits::decode(raw_handler)) {
400 os << "kField, WasmStruct, type = "
402 << ", field offset = "
404 } else {
405 os << "kField, is in object = "
407 << ", is double = " << LoadHandler::IsDoubleBits::decode(raw_handler)
408 << ", field index = "
410 }
411 break;
412 }
414 os << "kConstantFromPrototype";
415 break;
417 os << "kAccessorFromPrototype";
418 break;
420 os << "kNativeDataProperty, descriptor = "
422 break;
424 os << "kApiGetter";
425 break;
427 os << "kInterceptor";
428 break;
430 os << "kSlow";
431 break;
433 os << "kProxy";
434 break;
436 os << "kNonExistent";
437 break;
439 os << "kModuleExport, exports index = "
441 break;
442 default:
443 os << "<invalid value " << static_cast<int>(kind) << ">";
444 break;
445 }
446}
447
448void PrintSmiStoreHandler(int raw_handler, std::ostream& os) {
450 os << "kind = ";
451 switch (kind) {
454 os << "k";
456 os << "Const";
457 }
458 Representation representation = Representation::FromKind(
460 os << "Field, descriptor = "
462 << ", is in object = "
464 << ", representation = " << representation.Mnemonic()
465 << ", field index = "
467 break;
468 }
470 os << "kAccessorFromPrototype";
471 break;
473 os << "kNativeDataProperty, descriptor = "
475 break;
477 os << "kApiSetter";
478 break;
480 os << "kGlobalProxy";
481 break;
483 os << "kNormal";
484 break;
486 os << "kInterceptor";
487 break;
489 KeyedAccessStoreMode keyed_access_store_mode =
491 os << "kSlow, keyed access store mode = " << keyed_access_store_mode;
492 break;
493 }
495 os << "kProxy";
496 break;
498 os << "kSharedStructField";
499 break;
501 UNREACHABLE();
502 }
503}
504
505} // namespace
506
507// static
508void LoadHandler::PrintHandler(Tagged<Object> handler, std::ostream& os) {
510 if (IsSmi(handler)) {
511 int raw_handler = handler.ToSmi().value();
512 os << "LoadHandler(Smi)(";
513 PrintSmiLoadHandler(raw_handler, os);
514 os << ")";
515 } else if (IsCode(handler)) {
516 os << "LoadHandler(Code)("
517 << Builtins::name(Cast<Code>(handler)->builtin_id()) << ")";
518 } else if (IsSymbol(handler)) {
519 os << "LoadHandler(Symbol)(" << Brief(Cast<Symbol>(handler)) << ")";
520 } else if (IsLoadHandler(handler)) {
521 Tagged<LoadHandler> load_handler = Cast<LoadHandler>(handler);
522 int raw_handler = Cast<Smi>(load_handler->smi_handler()).value();
523 os << "LoadHandler(do access check on lookup start object = "
525 << ", lookup on lookup start object = "
526 << LookupOnLookupStartObjectBits::decode(raw_handler) << ", ";
527 PrintSmiLoadHandler(raw_handler, os);
528 if (load_handler->data_field_count() >= 1) {
529 os << ", data1 = ";
530 ShortPrint(load_handler->data1(), os);
531 }
532 if (load_handler->data_field_count() >= 2) {
533 os << ", data2 = ";
534 ShortPrint(load_handler->data2(), os);
535 }
536 if (load_handler->data_field_count() >= 3) {
537 os << ", data3 = ";
538 ShortPrint(load_handler->data3(), os);
539 }
540 os << ", validity cell = ";
541 ShortPrint(load_handler->validity_cell(), os);
542 os << ")";
543 } else {
544 os << "LoadHandler(<unexpected>)(" << Brief(handler) << ")";
545 }
546}
547
548void StoreHandler::PrintHandler(Tagged<Object> handler, std::ostream& os) {
550 if (IsSmi(handler)) {
551 int raw_handler = handler.ToSmi().value();
552 os << "StoreHandler(Smi)(";
553 PrintSmiStoreHandler(raw_handler, os);
554 os << ")" << std::endl;
555 } else if (IsStoreHandler(handler)) {
556 os << "StoreHandler(";
557 Tagged<StoreHandler> store_handler = Cast<StoreHandler>(handler);
558 if (IsCode(store_handler->smi_handler())) {
559 Tagged<Code> code = Cast<Code>(store_handler->smi_handler());
560 os << "builtin = ";
561 ShortPrint(code, os);
562 } else {
563 int raw_handler = Cast<Smi>(store_handler->smi_handler()).value();
564 os << "do access check on lookup start object = "
566 << ", lookup on lookup start object = "
567 << LookupOnLookupStartObjectBits::decode(raw_handler) << ", ";
568 PrintSmiStoreHandler(raw_handler, os);
569 }
570 if (store_handler->data_field_count() >= 1) {
571 os << ", data1 = ";
572 ShortPrint(store_handler->data1(), os);
573 }
574 if (store_handler->data_field_count() >= 2) {
575 os << ", data2 = ";
576 ShortPrint(store_handler->data2(), os);
577 }
578 if (store_handler->data_field_count() >= 3) {
579 os << ", data3 = ";
580 ShortPrint(store_handler->data3(), os);
581 }
582 os << ", validity cell = ";
583 ShortPrint(store_handler->validity_cell(), os);
584 os << ")" << std::endl;
585 } else if (IsMap(handler)) {
586 os << "StoreHandler(field transition to " << Brief(handler) << ")"
587 << std::endl;
588 } else if (IsCode(handler)) {
589 Tagged<Code> code = Cast<Code>(handler);
590 os << "StoreHandler(builtin = ";
591 ShortPrint(code, os);
592 os << ")" << std::endl;
593 } else {
594 os << "StoreHandler(<unexpected>)(" << Brief(handler) << ")" << std::endl;
595 }
596}
597
598std::ostream& operator<<(std::ostream& os, WasmValueType type) {
599 return os << WasmValueType2String(type);
600}
601
602#endif // defined(OBJECT_PRINT)
603
604} // namespace internal
605} // namespace v8
Builtins::Kind kind
Definition builtins.cc:40
static constexpr T decode(U value)
Definition bit-field.h:66
static constexpr U encode(T value)
Definition bit-field.h:55
static V8_EXPORT_PRIVATE const char * name(Builtin builtin)
Definition builtins.cc:226
Tagged< UnionOf< Smi, Cell > > validity_cell() const
Tagged< UnionOf< Smi, Code > > smi_handler() const
Tagged< MaybeObject > data1() const
static bool CanHandleHolderNotLookupStart(Tagged< Object > handler)
static KeyedAccessLoadMode GetKeyedAccessLoadMode(Tagged< MaybeObject > handler)
static Handle< Object > LoadFromPrototype(Isolate *isolate, DirectHandle< Map > receiver_map, DirectHandle< JSReceiver > holder, Tagged< Smi > smi_handler, MaybeObjectDirectHandle maybe_data1=MaybeObjectDirectHandle(), MaybeObjectDirectHandle maybe_data2=MaybeObjectDirectHandle())
static Handle< Object > LoadFullChain(Isolate *isolate, DirectHandle< Map > receiver_map, const MaybeObjectDirectHandle &holder, Handle< Smi > smi_handler)
static Handle< UnionOf< Smi, Cell > > GetOrCreatePrototypeChainValidityCell(DirectHandle< Map > map, Isolate *isolate)
Definition map.cc:2419
static MaybeObjectDirectHandle Weak(Tagged< Object > object, Isolate *isolate)
static MaybeObjectHandle Weak(Tagged< Object > object, Isolate *isolate)
PropertyAttributes attributes() const
Representation representation() const
constexpr bool IsNone() const
static constexpr Representation FromKind(Kind kind)
static constexpr Tagged< Smi > FromInt(int value)
Definition smi.h:38
static Handle< Object > StoreThroughPrototype(Isolate *isolate, DirectHandle< Map > receiver_map, DirectHandle< JSReceiver > holder, Tagged< Smi > smi_handler, MaybeObjectDirectHandle maybe_data1=MaybeObjectDirectHandle(), MaybeObjectDirectHandle maybe_data2=MaybeObjectDirectHandle())
static KeyedAccessStoreMode GetKeyedAccessStoreMode(Tagged< MaybeObject > handler)
static MaybeObjectHandle StoreGlobal(Handle< PropertyCell > cell)
static MaybeObjectHandle StoreTransition(Isolate *isolate, Handle< Map > transition_map)
static MaybeObjectHandle StoreOwnTransition(Isolate *isolate, Handle< Map > transition_map)
static Handle< Object > StoreElementTransition(Isolate *isolate, DirectHandle< Map > receiver_map, DirectHandle< Map > transition, KeyedAccessStoreMode store_mode, MaybeDirectHandle< UnionOf< Smi, Cell > > prev_validity_cell=kNullMaybeHandle)
static DirectHandle< Code > ElementsTransitionAndStoreBuiltin(Isolate *isolate, KeyedAccessStoreMode mode)
Isolate * isolate
TNode< Object > receiver
MovableLabel handler
bool IsPrimitiveMap(Tagged< Map > map)
Definition map-inl.h:754
PerThreadAssertScopeDebugOnly< false, SAFEPOINTS_ASSERT, HEAP_ALLOCATION_ASSERT > DisallowGarbageCollection
Tagged(T object) -> Tagged< T >
V8_INLINE constexpr bool IsSmi(TaggedImpl< kRefType, StorageType > obj)
Definition objects.h:665
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
const char * ElementsKindToString(ElementsKind kind)
std::ostream & operator<<(std::ostream &os, AtomicMemoryOrder order)
KeyedAccessLoadMode CreateKeyedAccessLoadMode(bool handle_oob, bool handle_holes)
Definition globals.h:2676
void ShortPrint(Tagged< Object > obj, FILE *out)
Definition objects.cc:1865
typename detail::FlattenUnionHelper< Union<>, Ts... >::type UnionOf
Definition union.h:123
Tagged< MaybeWeak< T > > MakeWeak(Tagged< T > value)
Definition tagged.h:893
const char * WasmValueType2String(WasmValueType type)
!IsContextMap !IsContextMap native_context
Definition map-inl.h:877
Tagged< To > Cast(Tagged< From > value, const v8::SourceLocation &loc=INIT_SOURCE_LOCATION_IN_DEBUG)
Definition casting.h:150
static constexpr RelaxedStoreTag kRelaxedStore
Definition globals.h:2911
#define DCHECK_NOT_NULL(val)
Definition logging.h:492
#define DCHECK_IMPLIES(v1, v2)
Definition logging.h:493
#define DCHECK(condition)
Definition logging.h:482
#define DCHECK_EQ(v1, v2)
Definition logging.h:485