• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/codegen/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/objects/transitions.h"
12 
13 namespace v8 {
14 namespace internal {
15 
16 namespace {
17 
18 template <typename BitField>
SetBitFieldValue(Isolate * isolate,Handle<Smi> smi_handler,typename BitField::FieldType value)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>
InitPrototypeChecksImpl(Isolate * isolate,Handle<ICHandler> handler,Handle<Smi> * smi_handler,Handle<Map> lookup_start_object_map,MaybeObjectHandle data1,MaybeObjectHandle maybe_data2)29 int InitPrototypeChecksImpl(Isolate* isolate, Handle<ICHandler> handler,
30                             Handle<Smi>* smi_handler,
31                             Handle<Map> lookup_start_object_map,
32                             MaybeObjectHandle data1,
33                             MaybeObjectHandle 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(lookup_start_object_map->IsJSGlobalObjectMap(),
39                  lookup_start_object_map->is_prototype_map());
40 
41   if (lookup_start_object_map->IsPrimitiveMap() ||
42       lookup_start_object_map->is_access_check_needed()) {
43     DCHECK(!lookup_start_object_map->IsJSGlobalObjectMap());
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       Handle<Context> native_context = isolate->native_context();
52       handler->set_data2(HeapObjectReference::Weak(*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              !lookup_start_object_map->IsJSGlobalObjectMap()) {
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.
92 template <typename ICHandler>
GetHandlerDataSize(Isolate * isolate,Handle<Smi> * smi_handler,Handle<Map> lookup_start_object_map,MaybeObjectHandle data1,MaybeObjectHandle maybe_data2=MaybeObjectHandle ())93 int GetHandlerDataSize(Isolate* isolate, Handle<Smi>* smi_handler,
94                        Handle<Map> lookup_start_object_map,
95                        MaybeObjectHandle data1,
96                        MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
97   DCHECK_NOT_NULL(smi_handler);
98   return InitPrototypeChecksImpl<ICHandler, false>(
99       isolate, Handle<ICHandler>(), smi_handler, lookup_start_object_map, data1,
100       maybe_data2);
101 }
102 
103 template <typename ICHandler>
InitPrototypeChecks(Isolate * isolate,Handle<ICHandler> handler,Handle<Map> lookup_start_object_map,MaybeObjectHandle data1,MaybeObjectHandle maybe_data2=MaybeObjectHandle ())104 void InitPrototypeChecks(Isolate* isolate, Handle<ICHandler> handler,
105                          Handle<Map> lookup_start_object_map,
106                          MaybeObjectHandle data1,
107                          MaybeObjectHandle maybe_data2 = MaybeObjectHandle()) {
108   InitPrototypeChecksImpl<ICHandler, true>(
109       isolate, handler, nullptr, lookup_start_object_map, data1, maybe_data2);
110 }
111 
112 }  // namespace
113 
114 // static
LoadFromPrototype(Isolate * isolate,Handle<Map> lookup_start_object_map,Handle<JSReceiver> holder,Handle<Smi> smi_handler,MaybeObjectHandle maybe_data1,MaybeObjectHandle maybe_data2)115 Handle<Object> LoadHandler::LoadFromPrototype(
116     Isolate* isolate, Handle<Map> lookup_start_object_map,
117     Handle<JSReceiver> holder, Handle<Smi> smi_handler,
118     MaybeObjectHandle maybe_data1, MaybeObjectHandle maybe_data2) {
119   MaybeObjectHandle data1;
120   if (maybe_data1.is_null()) {
121     data1 = MaybeObjectHandle::Weak(holder);
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 
129   Handle<Object> validity_cell = Map::GetOrCreatePrototypeChainValidityCell(
130       lookup_start_object_map, isolate);
131 
132   Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
133 
134   handler->set_smi_handler(*smi_handler);
135   handler->set_validity_cell(*validity_cell);
136   InitPrototypeChecks(isolate, handler, lookup_start_object_map, data1,
137                       maybe_data2);
138   return handler;
139 }
140 
141 // static
LoadFullChain(Isolate * isolate,Handle<Map> lookup_start_object_map,const MaybeObjectHandle & holder,Handle<Smi> smi_handler)142 Handle<Object> LoadHandler::LoadFullChain(Isolate* isolate,
143                                           Handle<Map> lookup_start_object_map,
144                                           const MaybeObjectHandle& holder,
145                                           Handle<Smi> smi_handler) {
146   MaybeObjectHandle data1 = holder;
147   int data_size = GetHandlerDataSize<LoadHandler>(
148       isolate, &smi_handler, lookup_start_object_map, data1);
149 
150   Handle<Object> validity_cell = Map::GetOrCreatePrototypeChainValidityCell(
151       lookup_start_object_map, isolate);
152   if (validity_cell->IsSmi()) {
153     DCHECK_EQ(1, data_size);
154     // Lookup on lookup start object isn't supported in case of a simple smi
155     // handler.
156     if (!LookupOnLookupStartObjectBits::decode(smi_handler->value())) {
157       return smi_handler;
158     }
159   }
160 
161   Handle<LoadHandler> handler = isolate->factory()->NewLoadHandler(data_size);
162 
163   handler->set_smi_handler(*smi_handler);
164   handler->set_validity_cell(*validity_cell);
165   InitPrototypeChecks(isolate, handler, lookup_start_object_map, data1);
166   return handler;
167 }
168 
169 // static
GetKeyedAccessLoadMode(MaybeObject handler)170 KeyedAccessLoadMode LoadHandler::GetKeyedAccessLoadMode(MaybeObject handler) {
171   DisallowGarbageCollection no_gc;
172   if (handler->IsSmi()) {
173     int const raw_handler = handler.ToSmi().value();
174     Kind const kind = KindBits::decode(raw_handler);
175     if ((kind == Kind::kElement || kind == Kind::kIndexedString) &&
176         AllowOutOfBoundsBits::decode(raw_handler)) {
177       return LOAD_IGNORE_OUT_OF_BOUNDS;
178     }
179   }
180   return STANDARD_LOAD;
181 }
182 
183 // static
GetKeyedAccessStoreMode(MaybeObject handler)184 KeyedAccessStoreMode StoreHandler::GetKeyedAccessStoreMode(
185     MaybeObject handler) {
186   DisallowGarbageCollection no_gc;
187   if (handler->IsSmi()) {
188     int const raw_handler = handler.ToSmi().value();
189     Kind const kind = KindBits::decode(raw_handler);
190     // All the handlers except the Slow Handler that use the
191     // KeyedAccessStoreMode, compute it using KeyedAccessStoreModeForBuiltin
192     // method. Hence if any other Handler get to this path, just return
193     // STANDARD_STORE.
194     if (kind != Kind::kSlow) {
195       return STANDARD_STORE;
196     }
197     KeyedAccessStoreMode store_mode =
198         KeyedAccessStoreModeBits::decode(raw_handler);
199     return store_mode;
200   }
201   return STANDARD_STORE;
202 }
203 
204 // static
StoreElementTransition(Isolate * isolate,Handle<Map> receiver_map,Handle<Map> transition,KeyedAccessStoreMode store_mode,MaybeHandle<Object> prev_validity_cell)205 Handle<Object> StoreHandler::StoreElementTransition(
206     Isolate* isolate, Handle<Map> receiver_map, Handle<Map> transition,
207     KeyedAccessStoreMode store_mode, MaybeHandle<Object> prev_validity_cell) {
208   Handle<Object> code =
209       MakeCodeHandler(isolate, ElementsTransitionAndStoreBuiltin(store_mode));
210   Handle<Object> validity_cell;
211   if (!prev_validity_cell.ToHandle(&validity_cell)) {
212     validity_cell =
213         Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
214   }
215   Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(1);
216   handler->set_smi_handler(*code);
217   handler->set_validity_cell(*validity_cell);
218   handler->set_data1(HeapObjectReference::Weak(*transition));
219   return handler;
220 }
221 
222 // static
StoreOwnTransition(Isolate * isolate,Handle<Map> transition_map)223 MaybeObjectHandle StoreHandler::StoreOwnTransition(Isolate* isolate,
224                                                    Handle<Map> transition_map) {
225   bool is_dictionary_map = transition_map->is_dictionary_map();
226 #ifdef DEBUG
227   if (!is_dictionary_map) {
228     InternalIndex descriptor = transition_map->LastAdded();
229     Handle<DescriptorArray> descriptors(
230         transition_map->instance_descriptors(isolate), isolate);
231     PropertyDetails details = descriptors->GetDetails(descriptor);
232     if (descriptors->GetKey(descriptor).IsPrivate()) {
233       DCHECK_EQ(DONT_ENUM, details.attributes());
234     } else {
235       DCHECK_EQ(NONE, details.attributes());
236     }
237     Representation representation = details.representation();
238     DCHECK(!representation.IsNone());
239   }
240 #endif
241   // Declarative handlers don't support access checks.
242   DCHECK(!transition_map->is_access_check_needed());
243 
244   // StoreOwnTransition does not involve any prototype checks.
245   if (is_dictionary_map) {
246     DCHECK(!transition_map->IsJSGlobalObjectMap());
247     int config = KindBits::encode(Kind::kNormal);
248     return MaybeObjectHandle(Smi::FromInt(config), isolate);
249 
250   } else {
251     return MaybeObjectHandle::Weak(transition_map);
252   }
253 }
254 
255 // static
StoreTransition(Isolate * isolate,Handle<Map> transition_map)256 MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
257                                                 Handle<Map> transition_map) {
258   bool is_dictionary_map = transition_map->is_dictionary_map();
259 #ifdef DEBUG
260   if (!is_dictionary_map) {
261     InternalIndex descriptor = transition_map->LastAdded();
262     Handle<DescriptorArray> descriptors(
263         transition_map->instance_descriptors(isolate), isolate);
264     // Private fields must be added via StoreOwnTransition handler.
265     DCHECK(!descriptors->GetKey(descriptor).IsPrivateName());
266     PropertyDetails details = descriptors->GetDetails(descriptor);
267     if (descriptors->GetKey(descriptor).IsPrivate()) {
268       DCHECK_EQ(DONT_ENUM, details.attributes());
269     } else {
270       DCHECK_EQ(NONE, details.attributes());
271     }
272     Representation representation = details.representation();
273     DCHECK(!representation.IsNone());
274   }
275 #endif
276   // Declarative handlers don't support access checks.
277   DCHECK(!transition_map->is_access_check_needed());
278 
279   // Get validity cell value if it is necessary for the handler.
280   Handle<Object> validity_cell;
281   if (is_dictionary_map || !transition_map->IsPrototypeValidityCellValid()) {
282     validity_cell =
283         Map::GetOrCreatePrototypeChainValidityCell(transition_map, isolate);
284   }
285 
286   if (is_dictionary_map) {
287     DCHECK(!transition_map->IsJSGlobalObjectMap());
288     Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(0);
289     // Store normal with enabled lookup on receiver.
290     int config = KindBits::encode(Kind::kNormal) |
291                  LookupOnLookupStartObjectBits::encode(true);
292     handler->set_smi_handler(Smi::FromInt(config));
293     handler->set_validity_cell(*validity_cell);
294     return MaybeObjectHandle(handler);
295 
296   } else {
297     // Ensure the transition map contains a valid prototype validity cell.
298     if (!validity_cell.is_null()) {
299       transition_map->set_prototype_validity_cell(*validity_cell);
300     }
301     return MaybeObjectHandle::Weak(transition_map);
302   }
303 }
304 
305 // static
StoreThroughPrototype(Isolate * isolate,Handle<Map> receiver_map,Handle<JSReceiver> holder,Handle<Smi> smi_handler,MaybeObjectHandle maybe_data1,MaybeObjectHandle maybe_data2)306 Handle<Object> StoreHandler::StoreThroughPrototype(
307     Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
308     Handle<Smi> smi_handler, MaybeObjectHandle maybe_data1,
309     MaybeObjectHandle maybe_data2) {
310   MaybeObjectHandle data1;
311   if (maybe_data1.is_null()) {
312     data1 = MaybeObjectHandle::Weak(holder);
313   } else {
314     data1 = maybe_data1;
315   }
316 
317   int data_size = GetHandlerDataSize<StoreHandler>(
318       isolate, &smi_handler, receiver_map, data1, maybe_data2);
319 
320   Handle<Object> validity_cell =
321       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
322 
323   Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(data_size);
324 
325   handler->set_smi_handler(*smi_handler);
326   handler->set_validity_cell(*validity_cell);
327   InitPrototypeChecks(isolate, handler, receiver_map, data1, maybe_data2);
328   return handler;
329 }
330 
331 // static
StoreGlobal(Handle<PropertyCell> cell)332 MaybeObjectHandle StoreHandler::StoreGlobal(Handle<PropertyCell> cell) {
333   return MaybeObjectHandle::Weak(cell);
334 }
335 
336 // static
StoreProxy(Isolate * isolate,Handle<Map> receiver_map,Handle<JSProxy> proxy,Handle<JSReceiver> receiver)337 Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
338                                         Handle<Map> receiver_map,
339                                         Handle<JSProxy> proxy,
340                                         Handle<JSReceiver> receiver) {
341   Handle<Smi> smi_handler = StoreProxy(isolate);
342   if (receiver.is_identical_to(proxy)) return smi_handler;
343   return StoreThroughPrototype(isolate, receiver_map, proxy, smi_handler,
344                                MaybeObjectHandle::Weak(proxy));
345 }
346 
347 #if defined(OBJECT_PRINT)
348 namespace {
PrintSmiLoadHandler(int raw_handler,std::ostream & os)349 void PrintSmiLoadHandler(int raw_handler, std::ostream& os) {
350   LoadHandler::Kind kind = LoadHandler::KindBits::decode(raw_handler);
351   os << "kind = ";
352   switch (kind) {
353     case LoadHandler::Kind::kElement:
354       os << "kElement, ";
355       if (LoadHandler::IsWasmArrayBits::decode(raw_handler)) {
356         os << "WasmArray, "
357            << LoadHandler::WasmArrayTypeBits::decode(raw_handler);
358 
359       } else {
360         os << "allow out of bounds = "
361            << LoadHandler::AllowOutOfBoundsBits::decode(raw_handler)
362            << ", is JSArray = "
363            << LoadHandler::IsJsArrayBits::decode(raw_handler)
364            << ", convert hole = "
365            << LoadHandler::ConvertHoleBits::decode(raw_handler)
366            << ", elements kind = "
367            << ElementsKindToString(
368                   LoadHandler::ElementsKindBits::decode(raw_handler));
369       }
370       break;
371     case LoadHandler::Kind::kIndexedString:
372       os << "kIndexedString, allow out of bounds = "
373          << LoadHandler::AllowOutOfBoundsBits::decode(raw_handler);
374       break;
375     case LoadHandler::Kind::kNormal:
376       os << "kNormal";
377       break;
378     case LoadHandler::Kind::kGlobal:
379       os << "kGlobal";
380       break;
381     case LoadHandler::Kind::kField: {
382       if (LoadHandler::IsWasmStructBits::decode(raw_handler)) {
383         os << "kField, WasmStruct, type = "
384            << LoadHandler::WasmFieldTypeBits::decode(raw_handler)
385            << ", field offset = "
386            << LoadHandler::WasmFieldOffsetBits::decode(raw_handler);
387       } else {
388         os << "kField, is in object = "
389            << LoadHandler::IsInobjectBits::decode(raw_handler)
390            << ", is double = " << LoadHandler::IsDoubleBits::decode(raw_handler)
391            << ", field index = "
392            << LoadHandler::FieldIndexBits::decode(raw_handler);
393       }
394       break;
395     }
396     case LoadHandler::Kind::kConstantFromPrototype: {
397       os << "kConstantFromPrototype ";
398       break;
399     }
400     case LoadHandler::Kind::kAccessor:
401       os << "kAccessor, descriptor = "
402          << LoadHandler::DescriptorBits::decode(raw_handler);
403       break;
404     case LoadHandler::Kind::kNativeDataProperty:
405       os << "kNativeDataProperty, descriptor = "
406          << LoadHandler::DescriptorBits::decode(raw_handler);
407       break;
408     case LoadHandler::Kind::kApiGetter:
409       os << "kApiGetter";
410       break;
411     case LoadHandler::Kind::kApiGetterHolderIsPrototype:
412       os << "kApiGetterHolderIsPrototype";
413       break;
414     case LoadHandler::Kind::kInterceptor:
415       os << "kInterceptor";
416       break;
417     case LoadHandler::Kind::kSlow:
418       os << "kSlow";
419       break;
420     case LoadHandler::Kind::kProxy:
421       os << "kProxy";
422       break;
423     case LoadHandler::Kind::kNonExistent:
424       os << "kNonExistent";
425       break;
426     case LoadHandler::Kind::kModuleExport:
427       os << "kModuleExport, exports index = "
428          << LoadHandler::ExportsIndexBits::decode(raw_handler);
429       break;
430     default:
431       UNREACHABLE();
432   }
433 }
434 
KeyedAccessStoreModeToString(KeyedAccessStoreMode mode)435 const char* KeyedAccessStoreModeToString(KeyedAccessStoreMode mode) {
436   switch (mode) {
437     case STANDARD_STORE:
438       return "STANDARD_STORE";
439     case STORE_AND_GROW_HANDLE_COW:
440       return "STORE_AND_GROW_HANDLE_COW";
441     case STORE_IGNORE_OUT_OF_BOUNDS:
442       return "STORE_IGNORE_OUT_OF_BOUNDS";
443     case STORE_HANDLE_COW:
444       return "STORE_HANDLE_COW";
445   }
446   UNREACHABLE();
447 }
448 
PrintSmiStoreHandler(int raw_handler,std::ostream & os)449 void PrintSmiStoreHandler(int raw_handler, std::ostream& os) {
450   StoreHandler::Kind kind = StoreHandler::KindBits::decode(raw_handler);
451   os << "kind = ";
452   switch (kind) {
453     case StoreHandler::Kind::kField:
454     case StoreHandler::Kind::kConstField: {
455       os << "k";
456       if (kind == StoreHandler::Kind::kConstField) {
457         os << "Const";
458       }
459       Representation representation = Representation::FromKind(
460           StoreHandler::RepresentationBits::decode(raw_handler));
461       os << "Field, descriptor = "
462          << StoreHandler::DescriptorBits::decode(raw_handler)
463          << ", is in object = "
464          << StoreHandler::IsInobjectBits::decode(raw_handler)
465          << ", representation = " << representation.Mnemonic()
466          << ", field index = "
467          << StoreHandler::FieldIndexBits::decode(raw_handler);
468       break;
469     }
470     case StoreHandler::Kind::kAccessor:
471       os << "kAccessor, descriptor = "
472          << StoreHandler::DescriptorBits::decode(raw_handler);
473       break;
474     case StoreHandler::Kind::kNativeDataProperty:
475       os << "kNativeDataProperty, descriptor = "
476          << StoreHandler::DescriptorBits::decode(raw_handler);
477       break;
478     case StoreHandler::Kind::kApiSetter:
479       os << "kApiSetter";
480       break;
481     case StoreHandler::Kind::kApiSetterHolderIsPrototype:
482       os << "kApiSetterHolderIsPrototype";
483       break;
484     case StoreHandler::Kind::kGlobalProxy:
485       os << "kGlobalProxy";
486       break;
487     case StoreHandler::Kind::kNormal:
488       os << "kNormal";
489       break;
490     case StoreHandler::Kind::kInterceptor:
491       os << "kInterceptor";
492       break;
493     case StoreHandler::Kind::kSlow: {
494       KeyedAccessStoreMode keyed_access_store_mode =
495           StoreHandler::KeyedAccessStoreModeBits::decode(raw_handler);
496       os << "kSlow, keyed access store mode = "
497          << KeyedAccessStoreModeToString(keyed_access_store_mode);
498       break;
499     }
500     case StoreHandler::Kind::kProxy:
501       os << "kProxy";
502       break;
503     default:
504       UNREACHABLE();
505   }
506 }
507 
508 }  // namespace
509 
510 // static
PrintHandler(Object handler,std::ostream & os)511 void LoadHandler::PrintHandler(Object handler, std::ostream& os) {
512   DisallowGarbageCollection no_gc;
513   if (handler.IsSmi()) {
514     int raw_handler = handler.ToSmi().value();
515     os << "LoadHandler(Smi)(";
516     PrintSmiLoadHandler(raw_handler, os);
517     os << ")" << std::endl;
518   } else {
519     LoadHandler load_handler = LoadHandler::cast(handler);
520     int raw_handler = load_handler.smi_handler().ToSmi().value();
521     os << "LoadHandler(do access check on lookup start object = "
522        << DoAccessCheckOnLookupStartObjectBits::decode(raw_handler)
523        << ", lookup on lookup start object = "
524        << LookupOnLookupStartObjectBits::decode(raw_handler) << ", ";
525     PrintSmiLoadHandler(raw_handler, os);
526     DCHECK_GE(load_handler.data_field_count(), 1);
527     os << ", data1 = ";
528     load_handler.data1().ShortPrint(os);
529     if (load_handler.data_field_count() >= 2) {
530       os << ", data2 = ";
531       load_handler.data2().ShortPrint(os);
532     }
533     if (load_handler.data_field_count() >= 3) {
534       os << ", data3 = ";
535       load_handler.data3().ShortPrint(os);
536     }
537     os << ", validity cell = ";
538     load_handler.validity_cell().ShortPrint(os);
539     os << ")" << std::endl;
540   }
541 }
542 
PrintHandler(Object handler,std::ostream & os)543 void StoreHandler::PrintHandler(Object handler, std::ostream& os) {
544   DisallowGarbageCollection no_gc;
545   if (handler.IsSmi()) {
546     int raw_handler = handler.ToSmi().value();
547     os << "StoreHandler(Smi)(";
548     PrintSmiStoreHandler(raw_handler, os);
549     os << ")" << std::endl;
550   } else {
551     os << "StoreHandler(";
552     StoreHandler store_handler = StoreHandler::cast(handler);
553     if (store_handler.smi_handler().IsCode()) {
554       Code code = Code::cast(store_handler.smi_handler());
555       os << "builtin = ";
556       code.ShortPrint(os);
557     } else {
558       int raw_handler = store_handler.smi_handler().ToSmi().value();
559       os << "do access check on lookup start object = "
560          << DoAccessCheckOnLookupStartObjectBits::decode(raw_handler)
561          << ", lookup on lookup start object = "
562          << LookupOnLookupStartObjectBits::decode(raw_handler) << ", ";
563       PrintSmiStoreHandler(raw_handler, os);
564     }
565     DCHECK_GE(store_handler.data_field_count(), 1);
566     os << ", data1 = ";
567     store_handler.data1().ShortPrint(os);
568     if (store_handler.data_field_count() >= 2) {
569       os << ", data2 = ";
570       store_handler.data2().ShortPrint(os);
571     }
572     if (store_handler.data_field_count() >= 3) {
573       os << ", data3 = ";
574       store_handler.data3().ShortPrint(os);
575     }
576     os << ", validity cell = ";
577     store_handler.validity_cell().ShortPrint(os);
578     os << ")" << std::endl;
579   }
580 }
581 
operator <<(std::ostream & os,WasmValueType type)582 std::ostream& operator<<(std::ostream& os, WasmValueType type) {
583   return os << WasmValueType2String(type);
584 }
585 
586 #endif  // defined(OBJECT_PRINT)
587 
588 }  // namespace internal
589 }  // namespace v8
590