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