• 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   DisallowHeapAllocation 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 == kElement || 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   DisallowHeapAllocation 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 != 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<Code> stub =
209       CodeFactory::ElementsTransitionAndStore(isolate, store_mode).code();
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(*stub);
217   handler->set_validity_cell(*validity_cell);
218   handler->set_data1(HeapObjectReference::Weak(*transition));
219   return handler;
220 }
221 
StoreTransition(Isolate * isolate,Handle<Map> transition_map)222 MaybeObjectHandle StoreHandler::StoreTransition(Isolate* isolate,
223                                                 Handle<Map> transition_map) {
224   bool is_dictionary_map = transition_map->is_dictionary_map();
225 #ifdef DEBUG
226   if (!is_dictionary_map) {
227     InternalIndex descriptor = transition_map->LastAdded();
228     Handle<DescriptorArray> descriptors(
229         transition_map->instance_descriptors(kRelaxedLoad), isolate);
230     PropertyDetails details = descriptors->GetDetails(descriptor);
231     if (descriptors->GetKey(descriptor).IsPrivate()) {
232       DCHECK_EQ(DONT_ENUM, details.attributes());
233     } else {
234       DCHECK_EQ(NONE, details.attributes());
235     }
236     Representation representation = details.representation();
237     DCHECK(!representation.IsNone());
238   }
239 #endif
240   // Declarative handlers don't support access checks.
241   DCHECK(!transition_map->is_access_check_needed());
242 
243   // Get validity cell value if it is necessary for the handler.
244   Handle<Object> validity_cell;
245   if (is_dictionary_map || !transition_map->IsPrototypeValidityCellValid()) {
246     validity_cell =
247         Map::GetOrCreatePrototypeChainValidityCell(transition_map, isolate);
248   }
249 
250   if (is_dictionary_map) {
251     DCHECK(!transition_map->IsJSGlobalObjectMap());
252     Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(0);
253     // Store normal with enabled lookup on receiver.
254     int config =
255         KindBits::encode(kNormal) | LookupOnLookupStartObjectBits::encode(true);
256     handler->set_smi_handler(Smi::FromInt(config));
257     handler->set_validity_cell(*validity_cell);
258     return MaybeObjectHandle(handler);
259 
260   } else {
261     // Ensure the transition map contains a valid prototype validity cell.
262     if (!validity_cell.is_null()) {
263       transition_map->set_prototype_validity_cell(*validity_cell);
264     }
265     return MaybeObjectHandle::Weak(transition_map);
266   }
267 }
268 
269 // static
StoreThroughPrototype(Isolate * isolate,Handle<Map> receiver_map,Handle<JSReceiver> holder,Handle<Smi> smi_handler,MaybeObjectHandle maybe_data1,MaybeObjectHandle maybe_data2)270 Handle<Object> StoreHandler::StoreThroughPrototype(
271     Isolate* isolate, Handle<Map> receiver_map, Handle<JSReceiver> holder,
272     Handle<Smi> smi_handler, MaybeObjectHandle maybe_data1,
273     MaybeObjectHandle maybe_data2) {
274   MaybeObjectHandle data1;
275   if (maybe_data1.is_null()) {
276     data1 = MaybeObjectHandle::Weak(holder);
277   } else {
278     data1 = maybe_data1;
279   }
280 
281   int data_size = GetHandlerDataSize<StoreHandler>(
282       isolate, &smi_handler, receiver_map, data1, maybe_data2);
283 
284   Handle<Object> validity_cell =
285       Map::GetOrCreatePrototypeChainValidityCell(receiver_map, isolate);
286 
287   Handle<StoreHandler> handler = isolate->factory()->NewStoreHandler(data_size);
288 
289   handler->set_smi_handler(*smi_handler);
290   handler->set_validity_cell(*validity_cell);
291   InitPrototypeChecks(isolate, handler, receiver_map, data1, maybe_data2);
292   return handler;
293 }
294 
295 // static
StoreGlobal(Handle<PropertyCell> cell)296 MaybeObjectHandle StoreHandler::StoreGlobal(Handle<PropertyCell> cell) {
297   return MaybeObjectHandle::Weak(cell);
298 }
299 
300 // static
StoreProxy(Isolate * isolate,Handle<Map> receiver_map,Handle<JSProxy> proxy,Handle<JSReceiver> receiver)301 Handle<Object> StoreHandler::StoreProxy(Isolate* isolate,
302                                         Handle<Map> receiver_map,
303                                         Handle<JSProxy> proxy,
304                                         Handle<JSReceiver> receiver) {
305   Handle<Smi> smi_handler = StoreProxy(isolate);
306   if (receiver.is_identical_to(proxy)) return smi_handler;
307   return StoreThroughPrototype(isolate, receiver_map, proxy, smi_handler,
308                                MaybeObjectHandle::Weak(proxy));
309 }
310 
311 #if defined(OBJECT_PRINT)
312 namespace {
PrintSmiLoadHandler(int raw_handler,std::ostream & os)313 void PrintSmiLoadHandler(int raw_handler, std::ostream& os) {
314   LoadHandler::Kind kind = LoadHandler::KindBits::decode(raw_handler);
315   os << "kind = ";
316   switch (kind) {
317     case LoadHandler::Kind::kElement:
318       os << "kElement, allow out of bounds = "
319          << LoadHandler::AllowOutOfBoundsBits::decode(raw_handler)
320          << ", is JSArray = " << LoadHandler::IsJsArrayBits::decode(raw_handler)
321          << ", convert hole = "
322          << LoadHandler::ConvertHoleBits::decode(raw_handler)
323          << ", elements kind = "
324          << ElementsKindToString(
325                 LoadHandler::ElementsKindBits::decode(raw_handler));
326       break;
327     case LoadHandler::Kind::kIndexedString:
328       os << "kIndexedString, allow out of bounds = "
329          << LoadHandler::AllowOutOfBoundsBits::decode(raw_handler);
330       break;
331     case LoadHandler::Kind::kNormal:
332       os << "kNormal";
333       break;
334     case LoadHandler::Kind::kGlobal:
335       os << "kGlobal";
336       break;
337     case LoadHandler::Kind::kField: {
338       CompactElementsKind compact_elements_kind =
339           LoadHandler::CompactElementsKindBits::decode(raw_handler);
340       os << "kField, is in object = "
341          << LoadHandler::IsInobjectBits::decode(raw_handler)
342          << ", is double = " << LoadHandler::IsDoubleBits::decode(raw_handler)
343          << ", field index = "
344          << LoadHandler::FieldIndexBits::decode(raw_handler)
345          << ", elements kind = "
346          << CompactElementsKindToString(compact_elements_kind);
347       break;
348     }
349     case LoadHandler::Kind::kConstantFromPrototype: {
350       CompactElementsKind compact_elements_kind =
351           LoadHandler::CompactElementsKindBits::decode(raw_handler);
352       os << "kConstantFromPrototype, elements kind = "
353          << CompactElementsKindToString(compact_elements_kind);
354       break;
355     }
356     case LoadHandler::Kind::kAccessor:
357       os << "kAccessor, descriptor = "
358          << LoadHandler::DescriptorBits::decode(raw_handler);
359       break;
360     case LoadHandler::Kind::kNativeDataProperty:
361       os << "kNativeDataProperty, descriptor = "
362          << LoadHandler::DescriptorBits::decode(raw_handler);
363       break;
364     case LoadHandler::Kind::kApiGetter:
365       os << "kApiGetter";
366       break;
367     case LoadHandler::Kind::kApiGetterHolderIsPrototype:
368       os << "kApiGetterHolderIsPrototype";
369       break;
370     case LoadHandler::Kind::kInterceptor:
371       os << "kInterceptor";
372       break;
373     case LoadHandler::Kind::kSlow:
374       os << "kSlow";
375       break;
376     case LoadHandler::Kind::kProxy:
377       os << "kProxy";
378       break;
379     case LoadHandler::Kind::kNonExistent:
380       os << "kNonExistent";
381       break;
382     case LoadHandler::Kind::kModuleExport:
383       os << "kModuleExport, exports index = "
384          << LoadHandler::ExportsIndexBits::decode(raw_handler);
385       break;
386     default:
387       UNREACHABLE();
388   }
389 }
390 
KeyedAccessStoreModeToString(KeyedAccessStoreMode mode)391 const char* KeyedAccessStoreModeToString(KeyedAccessStoreMode mode) {
392   switch (mode) {
393     case STANDARD_STORE:
394       return "STANDARD_STORE";
395     case STORE_AND_GROW_HANDLE_COW:
396       return "STORE_AND_GROW_HANDLE_COW";
397     case STORE_IGNORE_OUT_OF_BOUNDS:
398       return "STORE_IGNORE_OUT_OF_BOUNDS";
399     case STORE_HANDLE_COW:
400       return "STORE_HANDLE_COW";
401   }
402   UNREACHABLE();
403 }
404 
PrintSmiStoreHandler(int raw_handler,std::ostream & os)405 void PrintSmiStoreHandler(int raw_handler, std::ostream& os) {
406   StoreHandler::Kind kind = StoreHandler::KindBits::decode(raw_handler);
407   os << "kind = ";
408   switch (kind) {
409     case StoreHandler::Kind::kField:
410     case StoreHandler::Kind::kConstField: {
411       os << "k";
412       if (kind == StoreHandler::Kind::kConstField) {
413         os << "Const";
414       }
415       Representation representation = Representation::FromKind(
416           StoreHandler::RepresentationBits::decode(raw_handler));
417       os << "Field, descriptor = "
418          << StoreHandler::DescriptorBits::decode(raw_handler)
419          << ", is in object = "
420          << StoreHandler::IsInobjectBits::decode(raw_handler)
421          << ", representation = " << representation.Mnemonic()
422          << ", field index = "
423          << StoreHandler::FieldIndexBits::decode(raw_handler);
424       break;
425     }
426     case StoreHandler::Kind::kAccessor:
427       os << "kAccessor, descriptor = "
428          << StoreHandler::DescriptorBits::decode(raw_handler);
429       break;
430     case StoreHandler::Kind::kNativeDataProperty:
431       os << "kNativeDataProperty, descriptor = "
432          << StoreHandler::DescriptorBits::decode(raw_handler);
433       break;
434     case StoreHandler::Kind::kApiSetter:
435       os << "kApiSetter";
436       break;
437     case StoreHandler::Kind::kApiSetterHolderIsPrototype:
438       os << "kApiSetterHolderIsPrototype";
439       break;
440     case StoreHandler::Kind::kGlobalProxy:
441       os << "kGlobalProxy";
442       break;
443     case StoreHandler::Kind::kNormal:
444       os << "kNormal";
445       break;
446     case StoreHandler::Kind::kInterceptor:
447       os << "kInterceptor";
448       break;
449     case StoreHandler::Kind::kSlow: {
450       KeyedAccessStoreMode keyed_access_store_mode =
451           StoreHandler::KeyedAccessStoreModeBits::decode(raw_handler);
452       os << "kSlow, keyed access store mode = "
453          << KeyedAccessStoreModeToString(keyed_access_store_mode);
454       break;
455     }
456     case StoreHandler::Kind::kProxy:
457       os << "kProxy";
458       break;
459     default:
460       UNREACHABLE();
461   }
462 }
463 
464 }  // namespace
465 
466 // static
PrintHandler(Object handler,std::ostream & os)467 void LoadHandler::PrintHandler(Object handler, std::ostream& os) {
468   DisallowHeapAllocation no_gc;
469   if (handler.IsSmi()) {
470     int raw_handler = handler.ToSmi().value();
471     os << "LoadHandler(Smi)(";
472     PrintSmiLoadHandler(raw_handler, os);
473     os << ")" << std::endl;
474   } else {
475     LoadHandler load_handler = LoadHandler::cast(handler);
476     int raw_handler = load_handler.smi_handler().ToSmi().value();
477     os << "LoadHandler(do access check on lookup start object = "
478        << DoAccessCheckOnLookupStartObjectBits::decode(raw_handler)
479        << ", lookup on lookup start object = "
480        << LookupOnLookupStartObjectBits::decode(raw_handler) << ", ";
481     PrintSmiLoadHandler(raw_handler, os);
482     DCHECK_GE(load_handler.data_field_count(), 1);
483     os << ", data1 = ";
484     load_handler.data1().ShortPrint(os);
485     if (load_handler.data_field_count() >= 2) {
486       os << ", data2 = ";
487       load_handler.data2().ShortPrint(os);
488     }
489     if (load_handler.data_field_count() >= 3) {
490       os << ", data3 = ";
491       load_handler.data3().ShortPrint(os);
492     }
493     os << ", validity cell = ";
494     load_handler.validity_cell().ShortPrint(os);
495     os << ")" << std::endl;
496   }
497 }
498 
PrintHandler(Object handler,std::ostream & os)499 void StoreHandler::PrintHandler(Object handler, std::ostream& os) {
500   DisallowHeapAllocation no_gc;
501   if (handler.IsSmi()) {
502     int raw_handler = handler.ToSmi().value();
503     os << "StoreHandler(Smi)(";
504     PrintSmiStoreHandler(raw_handler, os);
505     os << ")" << std::endl;
506   } else {
507     os << "StoreHandler(";
508     StoreHandler store_handler = StoreHandler::cast(handler);
509     if (store_handler.smi_handler().IsCode()) {
510       Code code = Code::cast(store_handler.smi_handler());
511       os << "builtin = ";
512       code.ShortPrint(os);
513     } else {
514       int raw_handler = store_handler.smi_handler().ToSmi().value();
515       os << "do access check on lookup start object = "
516          << DoAccessCheckOnLookupStartObjectBits::decode(raw_handler)
517          << ", lookup on lookup start object = "
518          << LookupOnLookupStartObjectBits::decode(raw_handler) << ", ";
519       PrintSmiStoreHandler(raw_handler, os);
520     }
521     DCHECK_GE(store_handler.data_field_count(), 1);
522     os << ", data1 = ";
523     store_handler.data1().ShortPrint(os);
524     if (store_handler.data_field_count() >= 2) {
525       os << ", data2 = ";
526       store_handler.data2().ShortPrint(os);
527     }
528     if (store_handler.data_field_count() >= 3) {
529       os << ", data3 = ";
530       store_handler.data3().ShortPrint(os);
531     }
532     os << ", validity cell = ";
533     store_handler.validity_cell().ShortPrint(os);
534     os << ")" << std::endl;
535   }
536 }
537 #endif  // defined(OBJECT_PRINT)
538 
539 }  // namespace internal
540 }  // namespace v8
541