1 // Copyright 2015 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 #ifndef V8_OBJECTS_BODY_DESCRIPTORS_INL_H_ 6 #define V8_OBJECTS_BODY_DESCRIPTORS_INL_H_ 7 8 #include "src/objects-body-descriptors.h" 9 10 namespace v8 { 11 namespace internal { 12 13 template <int start_offset> 14 int FlexibleBodyDescriptor<start_offset>::SizeOf(Map* map, HeapObject* object) { 15 return object->SizeFromMap(map); 16 } 17 18 19 bool BodyDescriptorBase::IsValidSlotImpl(HeapObject* obj, int offset) { 20 if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { 21 return true; 22 } else { 23 DCHECK(FLAG_unbox_double_fields); 24 DCHECK(IsAligned(offset, kPointerSize)); 25 26 LayoutDescriptorHelper helper(obj->map()); 27 DCHECK(!helper.all_fields_tagged()); 28 return helper.IsTagged(offset); 29 } 30 } 31 32 template <typename ObjectVisitor> 33 void BodyDescriptorBase::IterateBodyImpl(HeapObject* obj, int start_offset, 34 int end_offset, ObjectVisitor* v) { 35 if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { 36 IteratePointers(obj, start_offset, end_offset, v); 37 } else { 38 DCHECK(FLAG_unbox_double_fields); 39 DCHECK(IsAligned(start_offset, kPointerSize) && 40 IsAligned(end_offset, kPointerSize)); 41 42 LayoutDescriptorHelper helper(obj->map()); 43 DCHECK(!helper.all_fields_tagged()); 44 for (int offset = start_offset; offset < end_offset;) { 45 int end_of_region_offset; 46 if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) { 47 IteratePointers(obj, offset, end_of_region_offset, v); 48 } 49 offset = end_of_region_offset; 50 } 51 } 52 } 53 54 55 template <typename StaticVisitor> 56 void BodyDescriptorBase::IterateBodyImpl(Heap* heap, HeapObject* obj, 57 int start_offset, int end_offset) { 58 if (!FLAG_unbox_double_fields || obj->map()->HasFastPointerLayout()) { 59 IteratePointers<StaticVisitor>(heap, obj, start_offset, end_offset); 60 } else { 61 DCHECK(FLAG_unbox_double_fields); 62 DCHECK(IsAligned(start_offset, kPointerSize) && 63 IsAligned(end_offset, kPointerSize)); 64 65 LayoutDescriptorHelper helper(obj->map()); 66 DCHECK(!helper.all_fields_tagged()); 67 for (int offset = start_offset; offset < end_offset;) { 68 int end_of_region_offset; 69 if (helper.IsTagged(offset, end_offset, &end_of_region_offset)) { 70 IteratePointers<StaticVisitor>(heap, obj, offset, end_of_region_offset); 71 } 72 offset = end_of_region_offset; 73 } 74 } 75 } 76 77 78 template <typename ObjectVisitor> 79 void BodyDescriptorBase::IteratePointers(HeapObject* obj, int start_offset, 80 int end_offset, ObjectVisitor* v) { 81 v->VisitPointers(HeapObject::RawField(obj, start_offset), 82 HeapObject::RawField(obj, end_offset)); 83 } 84 85 86 template <typename StaticVisitor> 87 void BodyDescriptorBase::IteratePointers(Heap* heap, HeapObject* obj, 88 int start_offset, int end_offset) { 89 StaticVisitor::VisitPointers(heap, obj, 90 HeapObject::RawField(obj, start_offset), 91 HeapObject::RawField(obj, end_offset)); 92 } 93 94 95 template <typename ObjectVisitor> 96 void BodyDescriptorBase::IteratePointer(HeapObject* obj, int offset, 97 ObjectVisitor* v) { 98 v->VisitPointer(HeapObject::RawField(obj, offset)); 99 } 100 101 102 template <typename StaticVisitor> 103 void BodyDescriptorBase::IteratePointer(Heap* heap, HeapObject* obj, 104 int offset) { 105 StaticVisitor::VisitPointer(heap, obj, HeapObject::RawField(obj, offset)); 106 } 107 108 109 // Iterates the function object according to the visiting policy. 110 template <JSFunction::BodyVisitingPolicy body_visiting_policy> 111 class JSFunction::BodyDescriptorImpl final : public BodyDescriptorBase { 112 public: 113 STATIC_ASSERT(kNonWeakFieldsEndOffset == kCodeEntryOffset); 114 STATIC_ASSERT(kCodeEntryOffset + kPointerSize == kNextFunctionLinkOffset); 115 STATIC_ASSERT(kNextFunctionLinkOffset + kPointerSize == kSize); 116 117 static bool IsValidSlot(HeapObject* obj, int offset) { 118 if (offset < kSize) return true; 119 return IsValidSlotImpl(obj, offset); 120 } 121 122 template <typename ObjectVisitor> 123 static inline void IterateBody(HeapObject* obj, int object_size, 124 ObjectVisitor* v) { 125 IteratePointers(obj, kPropertiesOffset, kNonWeakFieldsEndOffset, v); 126 127 if (body_visiting_policy & kVisitCodeEntry) { 128 v->VisitCodeEntry(obj->address() + kCodeEntryOffset); 129 } 130 131 if (body_visiting_policy & kVisitNextFunction) { 132 IteratePointers(obj, kNextFunctionLinkOffset, kSize, v); 133 } 134 IterateBodyImpl(obj, kSize, object_size, v); 135 } 136 137 template <typename StaticVisitor> 138 static inline void IterateBody(HeapObject* obj, int object_size) { 139 Heap* heap = obj->GetHeap(); 140 IteratePointers<StaticVisitor>(heap, obj, kPropertiesOffset, 141 kNonWeakFieldsEndOffset); 142 143 if (body_visiting_policy & kVisitCodeEntry) { 144 StaticVisitor::VisitCodeEntry(heap, obj, 145 obj->address() + kCodeEntryOffset); 146 } 147 148 if (body_visiting_policy & kVisitNextFunction) { 149 IteratePointers<StaticVisitor>(heap, obj, kNextFunctionLinkOffset, kSize); 150 } 151 IterateBodyImpl<StaticVisitor>(heap, obj, kSize, object_size); 152 } 153 154 static inline int SizeOf(Map* map, HeapObject* object) { 155 return map->instance_size(); 156 } 157 }; 158 159 160 class JSArrayBuffer::BodyDescriptor final : public BodyDescriptorBase { 161 public: 162 STATIC_ASSERT(kByteLengthOffset + kPointerSize == kBackingStoreOffset); 163 STATIC_ASSERT(kBackingStoreOffset + kPointerSize == kBitFieldSlot); 164 STATIC_ASSERT(kBitFieldSlot + kPointerSize == kSize); 165 166 static bool IsValidSlot(HeapObject* obj, int offset) { 167 if (offset < kBackingStoreOffset) return true; 168 if (offset < kSize) return false; 169 return IsValidSlotImpl(obj, offset); 170 } 171 172 template <typename ObjectVisitor> 173 static inline void IterateBody(HeapObject* obj, int object_size, 174 ObjectVisitor* v) { 175 IteratePointers(obj, kPropertiesOffset, kBackingStoreOffset, v); 176 IterateBodyImpl(obj, kSize, object_size, v); 177 } 178 179 template <typename StaticVisitor> 180 static inline void IterateBody(HeapObject* obj, int object_size) { 181 Heap* heap = obj->GetHeap(); 182 IteratePointers<StaticVisitor>(heap, obj, kPropertiesOffset, 183 kBackingStoreOffset); 184 IterateBodyImpl<StaticVisitor>(heap, obj, kSize, object_size); 185 } 186 187 static inline int SizeOf(Map* map, HeapObject* object) { 188 return map->instance_size(); 189 } 190 }; 191 192 193 class BytecodeArray::BodyDescriptor final : public BodyDescriptorBase { 194 public: 195 static bool IsValidSlot(HeapObject* obj, int offset) { 196 return offset >= kConstantPoolOffset && 197 offset <= kSourcePositionTableOffset; 198 } 199 200 template <typename ObjectVisitor> 201 static inline void IterateBody(HeapObject* obj, int object_size, 202 ObjectVisitor* v) { 203 IteratePointer(obj, kConstantPoolOffset, v); 204 IteratePointer(obj, kHandlerTableOffset, v); 205 IteratePointer(obj, kSourcePositionTableOffset, v); 206 } 207 208 template <typename StaticVisitor> 209 static inline void IterateBody(HeapObject* obj, int object_size) { 210 Heap* heap = obj->GetHeap(); 211 IteratePointer<StaticVisitor>(heap, obj, kConstantPoolOffset); 212 IteratePointer<StaticVisitor>(heap, obj, kHandlerTableOffset); 213 IteratePointer<StaticVisitor>(heap, obj, kSourcePositionTableOffset); 214 } 215 216 static inline int SizeOf(Map* map, HeapObject* obj) { 217 return reinterpret_cast<BytecodeArray*>(obj)->BytecodeArraySize(); 218 } 219 }; 220 221 222 class FixedTypedArrayBase::BodyDescriptor final : public BodyDescriptorBase { 223 public: 224 static bool IsValidSlot(HeapObject* obj, int offset) { 225 return offset == kBasePointerOffset; 226 } 227 228 template <typename ObjectVisitor> 229 static inline void IterateBody(HeapObject* obj, int object_size, 230 ObjectVisitor* v) { 231 IteratePointer(obj, kBasePointerOffset, v); 232 } 233 234 template <typename StaticVisitor> 235 static inline void IterateBody(HeapObject* obj, int object_size) { 236 Heap* heap = obj->GetHeap(); 237 IteratePointer<StaticVisitor>(heap, obj, kBasePointerOffset); 238 } 239 240 static inline int SizeOf(Map* map, HeapObject* object) { 241 return reinterpret_cast<FixedTypedArrayBase*>(object)->size(); 242 } 243 }; 244 245 246 template <JSWeakCollection::BodyVisitingPolicy body_visiting_policy> 247 class JSWeakCollection::BodyDescriptorImpl final : public BodyDescriptorBase { 248 public: 249 STATIC_ASSERT(kTableOffset + kPointerSize == kNextOffset); 250 STATIC_ASSERT(kNextOffset + kPointerSize == kSize); 251 252 static bool IsValidSlot(HeapObject* obj, int offset) { 253 return IsValidSlotImpl(obj, offset); 254 } 255 256 template <typename ObjectVisitor> 257 static inline void IterateBody(HeapObject* obj, int object_size, 258 ObjectVisitor* v) { 259 if (body_visiting_policy == kVisitStrong) { 260 IterateBodyImpl(obj, kPropertiesOffset, object_size, v); 261 } else { 262 IteratePointers(obj, kPropertiesOffset, kTableOffset, v); 263 IterateBodyImpl(obj, kSize, object_size, v); 264 } 265 } 266 267 template <typename StaticVisitor> 268 static inline void IterateBody(HeapObject* obj, int object_size) { 269 Heap* heap = obj->GetHeap(); 270 if (body_visiting_policy == kVisitStrong) { 271 IterateBodyImpl<StaticVisitor>(heap, obj, kPropertiesOffset, object_size); 272 } else { 273 IteratePointers<StaticVisitor>(heap, obj, kPropertiesOffset, 274 kTableOffset); 275 IterateBodyImpl<StaticVisitor>(heap, obj, kSize, object_size); 276 } 277 } 278 279 static inline int SizeOf(Map* map, HeapObject* object) { 280 return map->instance_size(); 281 } 282 }; 283 284 285 class Foreign::BodyDescriptor final : public BodyDescriptorBase { 286 public: 287 static bool IsValidSlot(HeapObject* obj, int offset) { return false; } 288 289 template <typename ObjectVisitor> 290 static inline void IterateBody(HeapObject* obj, int object_size, 291 ObjectVisitor* v) { 292 v->VisitExternalReference(reinterpret_cast<Address*>( 293 HeapObject::RawField(obj, kForeignAddressOffset))); 294 } 295 296 template <typename StaticVisitor> 297 static inline void IterateBody(HeapObject* obj, int object_size) { 298 StaticVisitor::VisitExternalReference(reinterpret_cast<Address*>( 299 HeapObject::RawField(obj, kForeignAddressOffset))); 300 } 301 302 static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } 303 }; 304 305 306 class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase { 307 public: 308 static bool IsValidSlot(HeapObject* obj, int offset) { return false; } 309 310 template <typename ObjectVisitor> 311 static inline void IterateBody(HeapObject* obj, int object_size, 312 ObjectVisitor* v) { 313 typedef v8::String::ExternalOneByteStringResource Resource; 314 v->VisitExternalOneByteString(reinterpret_cast<Resource**>( 315 HeapObject::RawField(obj, kResourceOffset))); 316 } 317 318 template <typename StaticVisitor> 319 static inline void IterateBody(HeapObject* obj, int object_size) { 320 typedef v8::String::ExternalOneByteStringResource Resource; 321 StaticVisitor::VisitExternalOneByteString(reinterpret_cast<Resource**>( 322 HeapObject::RawField(obj, kResourceOffset))); 323 } 324 325 static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } 326 }; 327 328 329 class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase { 330 public: 331 static bool IsValidSlot(HeapObject* obj, int offset) { return false; } 332 333 template <typename ObjectVisitor> 334 static inline void IterateBody(HeapObject* obj, int object_size, 335 ObjectVisitor* v) { 336 typedef v8::String::ExternalStringResource Resource; 337 v->VisitExternalTwoByteString(reinterpret_cast<Resource**>( 338 HeapObject::RawField(obj, kResourceOffset))); 339 } 340 341 template <typename StaticVisitor> 342 static inline void IterateBody(HeapObject* obj, int object_size) { 343 typedef v8::String::ExternalStringResource Resource; 344 StaticVisitor::VisitExternalTwoByteString(reinterpret_cast<Resource**>( 345 HeapObject::RawField(obj, kResourceOffset))); 346 } 347 348 static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } 349 }; 350 351 352 class Code::BodyDescriptor final : public BodyDescriptorBase { 353 public: 354 STATIC_ASSERT(kRelocationInfoOffset + kPointerSize == kHandlerTableOffset); 355 STATIC_ASSERT(kHandlerTableOffset + kPointerSize == 356 kDeoptimizationDataOffset); 357 STATIC_ASSERT(kDeoptimizationDataOffset + kPointerSize == 358 kTypeFeedbackInfoOffset); 359 STATIC_ASSERT(kTypeFeedbackInfoOffset + kPointerSize == kNextCodeLinkOffset); 360 361 static bool IsValidSlot(HeapObject* obj, int offset) { 362 // Slots in code can't be invalid because we never trim code objects. 363 return true; 364 } 365 366 template <typename ObjectVisitor> 367 static inline void IterateBody(HeapObject* obj, ObjectVisitor* v) { 368 int mode_mask = RelocInfo::kCodeTargetMask | 369 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 370 RelocInfo::ModeMask(RelocInfo::CELL) | 371 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | 372 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 373 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | 374 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 375 RelocInfo::kDebugBreakSlotMask; 376 377 IteratePointers(obj, kRelocationInfoOffset, kNextCodeLinkOffset, v); 378 v->VisitNextCodeLink(HeapObject::RawField(obj, kNextCodeLinkOffset)); 379 380 RelocIterator it(reinterpret_cast<Code*>(obj), mode_mask); 381 Isolate* isolate = obj->GetIsolate(); 382 for (; !it.done(); it.next()) { 383 it.rinfo()->Visit(isolate, v); 384 } 385 } 386 387 template <typename ObjectVisitor> 388 static inline void IterateBody(HeapObject* obj, int object_size, 389 ObjectVisitor* v) { 390 IterateBody(obj, v); 391 } 392 393 template <typename StaticVisitor> 394 static inline void IterateBody(HeapObject* obj) { 395 int mode_mask = RelocInfo::kCodeTargetMask | 396 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 397 RelocInfo::ModeMask(RelocInfo::CELL) | 398 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | 399 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 400 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | 401 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 402 RelocInfo::kDebugBreakSlotMask; 403 404 Heap* heap = obj->GetHeap(); 405 IteratePointers<StaticVisitor>(heap, obj, kRelocationInfoOffset, 406 kNextCodeLinkOffset); 407 StaticVisitor::VisitNextCodeLink( 408 heap, HeapObject::RawField(obj, kNextCodeLinkOffset)); 409 410 RelocIterator it(reinterpret_cast<Code*>(obj), mode_mask); 411 for (; !it.done(); it.next()) { 412 it.rinfo()->template Visit<StaticVisitor>(heap); 413 } 414 } 415 416 template <typename StaticVisitor> 417 static inline void IterateBody(HeapObject* obj, int object_size) { 418 IterateBody<StaticVisitor>(obj); 419 } 420 421 static inline int SizeOf(Map* map, HeapObject* object) { 422 return reinterpret_cast<Code*>(object)->CodeSize(); 423 } 424 }; 425 426 427 template <typename Op, typename ReturnType, typename T1, typename T2, 428 typename T3> 429 ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) { 430 if (type < FIRST_NONSTRING_TYPE) { 431 switch (type & kStringRepresentationMask) { 432 case kSeqStringTag: 433 return ReturnType(); 434 case kConsStringTag: 435 return Op::template apply<ConsString::BodyDescriptor>(p1, p2, p3); 436 case kSlicedStringTag: 437 return Op::template apply<SlicedString::BodyDescriptor>(p1, p2, p3); 438 case kExternalStringTag: 439 if ((type & kStringEncodingMask) == kOneByteStringTag) { 440 return Op::template apply<ExternalOneByteString::BodyDescriptor>( 441 p1, p2, p3); 442 } else { 443 return Op::template apply<ExternalTwoByteString::BodyDescriptor>( 444 p1, p2, p3); 445 } 446 } 447 UNREACHABLE(); 448 return ReturnType(); 449 } 450 451 switch (type) { 452 case FIXED_ARRAY_TYPE: 453 return Op::template apply<FixedArray::BodyDescriptor>(p1, p2, p3); 454 case FIXED_DOUBLE_ARRAY_TYPE: 455 return ReturnType(); 456 case TRANSITION_ARRAY_TYPE: 457 return Op::template apply<TransitionArray::BodyDescriptor>(p1, p2, p3); 458 case JS_OBJECT_TYPE: 459 case JS_ERROR_TYPE: 460 case JS_ARGUMENTS_TYPE: 461 case JS_PROMISE_TYPE: 462 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 463 case JS_GENERATOR_OBJECT_TYPE: 464 case JS_MODULE_TYPE: 465 case JS_VALUE_TYPE: 466 case JS_DATE_TYPE: 467 case JS_ARRAY_TYPE: 468 case JS_TYPED_ARRAY_TYPE: 469 case JS_DATA_VIEW_TYPE: 470 case JS_SET_TYPE: 471 case JS_MAP_TYPE: 472 case JS_SET_ITERATOR_TYPE: 473 case JS_MAP_ITERATOR_TYPE: 474 case JS_REGEXP_TYPE: 475 case JS_GLOBAL_PROXY_TYPE: 476 case JS_GLOBAL_OBJECT_TYPE: 477 case JS_API_OBJECT_TYPE: 478 case JS_SPECIAL_API_OBJECT_TYPE: 479 case JS_MESSAGE_OBJECT_TYPE: 480 case JS_BOUND_FUNCTION_TYPE: 481 return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3); 482 case JS_WEAK_MAP_TYPE: 483 case JS_WEAK_SET_TYPE: 484 return Op::template apply<JSWeakCollection::BodyDescriptor>(p1, p2, p3); 485 case JS_ARRAY_BUFFER_TYPE: 486 return Op::template apply<JSArrayBuffer::BodyDescriptor>(p1, p2, p3); 487 case JS_FUNCTION_TYPE: 488 return Op::template apply<JSFunction::BodyDescriptor>(p1, p2, p3); 489 case ODDBALL_TYPE: 490 return Op::template apply<Oddball::BodyDescriptor>(p1, p2, p3); 491 case JS_PROXY_TYPE: 492 return Op::template apply<JSProxy::BodyDescriptor>(p1, p2, p3); 493 case FOREIGN_TYPE: 494 return Op::template apply<Foreign::BodyDescriptor>(p1, p2, p3); 495 case MAP_TYPE: 496 return Op::template apply<Map::BodyDescriptor>(p1, p2, p3); 497 case CODE_TYPE: 498 return Op::template apply<Code::BodyDescriptor>(p1, p2, p3); 499 case CELL_TYPE: 500 return Op::template apply<Cell::BodyDescriptor>(p1, p2, p3); 501 case PROPERTY_CELL_TYPE: 502 return Op::template apply<PropertyCell::BodyDescriptor>(p1, p2, p3); 503 case WEAK_CELL_TYPE: 504 return Op::template apply<WeakCell::BodyDescriptor>(p1, p2, p3); 505 case SYMBOL_TYPE: 506 return Op::template apply<Symbol::BodyDescriptor>(p1, p2, p3); 507 case BYTECODE_ARRAY_TYPE: 508 return Op::template apply<BytecodeArray::BodyDescriptor>(p1, p2, p3); 509 510 case HEAP_NUMBER_TYPE: 511 case MUTABLE_HEAP_NUMBER_TYPE: 512 case SIMD128_VALUE_TYPE: 513 case FILLER_TYPE: 514 case BYTE_ARRAY_TYPE: 515 case FREE_SPACE_TYPE: 516 return ReturnType(); 517 518 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 519 case FIXED_##TYPE##_ARRAY_TYPE: \ 520 return Op::template apply<FixedTypedArrayBase::BodyDescriptor>(p1, p2, p3); 521 TYPED_ARRAYS(TYPED_ARRAY_CASE) 522 #undef TYPED_ARRAY_CASE 523 524 case SHARED_FUNCTION_INFO_TYPE: { 525 return Op::template apply<SharedFunctionInfo::BodyDescriptor>(p1, p2, p3); 526 } 527 528 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 529 STRUCT_LIST(MAKE_STRUCT_CASE) 530 #undef MAKE_STRUCT_CASE 531 if (type == ALLOCATION_SITE_TYPE) { 532 return Op::template apply<AllocationSite::BodyDescriptor>(p1, p2, p3); 533 } else { 534 return Op::template apply<StructBodyDescriptor>(p1, p2, p3); 535 } 536 default: 537 PrintF("Unknown type: %d\n", type); 538 UNREACHABLE(); 539 return ReturnType(); 540 } 541 } 542 543 544 template <typename ObjectVisitor> 545 void HeapObject::IterateFast(ObjectVisitor* v) { 546 BodyDescriptorBase::IteratePointer(this, kMapOffset, v); 547 IterateBodyFast(v); 548 } 549 550 551 template <typename ObjectVisitor> 552 void HeapObject::IterateBodyFast(ObjectVisitor* v) { 553 Map* m = map(); 554 IterateBodyFast(m->instance_type(), SizeFromMap(m), v); 555 } 556 557 558 struct CallIterateBody { 559 template <typename BodyDescriptor, typename ObjectVisitor> 560 static void apply(HeapObject* obj, int object_size, ObjectVisitor* v) { 561 BodyDescriptor::IterateBody(obj, object_size, v); 562 } 563 }; 564 565 template <typename ObjectVisitor> 566 void HeapObject::IterateBodyFast(InstanceType type, int object_size, 567 ObjectVisitor* v) { 568 BodyDescriptorApply<CallIterateBody, void>(type, this, object_size, v); 569 } 570 } // namespace internal 571 } // namespace v8 572 573 #endif // V8_OBJECTS_BODY_DESCRIPTORS_INL_H_ 574