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 } 198 199 template <typename ObjectVisitor> 200 static inline void IterateBody(HeapObject* obj, int object_size, 201 ObjectVisitor* v) { 202 IteratePointer(obj, kConstantPoolOffset, v); 203 } 204 205 template <typename StaticVisitor> 206 static inline void IterateBody(HeapObject* obj, int object_size) { 207 Heap* heap = obj->GetHeap(); 208 IteratePointer<StaticVisitor>(heap, obj, kConstantPoolOffset); 209 } 210 211 static inline int SizeOf(Map* map, HeapObject* obj) { 212 return reinterpret_cast<BytecodeArray*>(obj)->BytecodeArraySize(); 213 } 214 }; 215 216 217 class FixedTypedArrayBase::BodyDescriptor final : public BodyDescriptorBase { 218 public: 219 static bool IsValidSlot(HeapObject* obj, int offset) { 220 return offset == kBasePointerOffset; 221 } 222 223 template <typename ObjectVisitor> 224 static inline void IterateBody(HeapObject* obj, int object_size, 225 ObjectVisitor* v) { 226 IteratePointer(obj, kBasePointerOffset, v); 227 } 228 229 template <typename StaticVisitor> 230 static inline void IterateBody(HeapObject* obj, int object_size) { 231 Heap* heap = obj->GetHeap(); 232 IteratePointer<StaticVisitor>(heap, obj, kBasePointerOffset); 233 } 234 235 static inline int SizeOf(Map* map, HeapObject* object) { 236 return reinterpret_cast<FixedTypedArrayBase*>(object)->size(); 237 } 238 }; 239 240 241 template <JSWeakCollection::BodyVisitingPolicy body_visiting_policy> 242 class JSWeakCollection::BodyDescriptorImpl final : public BodyDescriptorBase { 243 public: 244 STATIC_ASSERT(kTableOffset + kPointerSize == kNextOffset); 245 STATIC_ASSERT(kNextOffset + kPointerSize == kSize); 246 247 static bool IsValidSlot(HeapObject* obj, int offset) { 248 return IsValidSlotImpl(obj, offset); 249 } 250 251 template <typename ObjectVisitor> 252 static inline void IterateBody(HeapObject* obj, int object_size, 253 ObjectVisitor* v) { 254 if (body_visiting_policy == kVisitStrong) { 255 IterateBodyImpl(obj, kPropertiesOffset, object_size, v); 256 } else { 257 IteratePointers(obj, kPropertiesOffset, kTableOffset, v); 258 IterateBodyImpl(obj, kSize, object_size, v); 259 } 260 } 261 262 template <typename StaticVisitor> 263 static inline void IterateBody(HeapObject* obj, int object_size) { 264 Heap* heap = obj->GetHeap(); 265 if (body_visiting_policy == kVisitStrong) { 266 IterateBodyImpl<StaticVisitor>(heap, obj, kPropertiesOffset, object_size); 267 } else { 268 IteratePointers<StaticVisitor>(heap, obj, kPropertiesOffset, 269 kTableOffset); 270 IterateBodyImpl<StaticVisitor>(heap, obj, kSize, object_size); 271 } 272 } 273 274 static inline int SizeOf(Map* map, HeapObject* object) { 275 return map->instance_size(); 276 } 277 }; 278 279 280 class Foreign::BodyDescriptor final : public BodyDescriptorBase { 281 public: 282 static bool IsValidSlot(HeapObject* obj, int offset) { return false; } 283 284 template <typename ObjectVisitor> 285 static inline void IterateBody(HeapObject* obj, int object_size, 286 ObjectVisitor* v) { 287 v->VisitExternalReference(reinterpret_cast<Address*>( 288 HeapObject::RawField(obj, kForeignAddressOffset))); 289 } 290 291 template <typename StaticVisitor> 292 static inline void IterateBody(HeapObject* obj, int object_size) { 293 StaticVisitor::VisitExternalReference(reinterpret_cast<Address*>( 294 HeapObject::RawField(obj, kForeignAddressOffset))); 295 } 296 297 static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } 298 }; 299 300 301 class ExternalOneByteString::BodyDescriptor final : public BodyDescriptorBase { 302 public: 303 static bool IsValidSlot(HeapObject* obj, int offset) { return false; } 304 305 template <typename ObjectVisitor> 306 static inline void IterateBody(HeapObject* obj, int object_size, 307 ObjectVisitor* v) { 308 typedef v8::String::ExternalOneByteStringResource Resource; 309 v->VisitExternalOneByteString(reinterpret_cast<Resource**>( 310 HeapObject::RawField(obj, kResourceOffset))); 311 } 312 313 template <typename StaticVisitor> 314 static inline void IterateBody(HeapObject* obj, int object_size) { 315 typedef v8::String::ExternalOneByteStringResource Resource; 316 StaticVisitor::VisitExternalOneByteString(reinterpret_cast<Resource**>( 317 HeapObject::RawField(obj, kResourceOffset))); 318 } 319 320 static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } 321 }; 322 323 324 class ExternalTwoByteString::BodyDescriptor final : public BodyDescriptorBase { 325 public: 326 static bool IsValidSlot(HeapObject* obj, int offset) { return false; } 327 328 template <typename ObjectVisitor> 329 static inline void IterateBody(HeapObject* obj, int object_size, 330 ObjectVisitor* v) { 331 typedef v8::String::ExternalStringResource Resource; 332 v->VisitExternalTwoByteString(reinterpret_cast<Resource**>( 333 HeapObject::RawField(obj, kResourceOffset))); 334 } 335 336 template <typename StaticVisitor> 337 static inline void IterateBody(HeapObject* obj, int object_size) { 338 typedef v8::String::ExternalStringResource Resource; 339 StaticVisitor::VisitExternalTwoByteString(reinterpret_cast<Resource**>( 340 HeapObject::RawField(obj, kResourceOffset))); 341 } 342 343 static inline int SizeOf(Map* map, HeapObject* object) { return kSize; } 344 }; 345 346 347 class Code::BodyDescriptor final : public BodyDescriptorBase { 348 public: 349 STATIC_ASSERT(kRelocationInfoOffset + kPointerSize == kHandlerTableOffset); 350 STATIC_ASSERT(kHandlerTableOffset + kPointerSize == 351 kDeoptimizationDataOffset); 352 STATIC_ASSERT(kDeoptimizationDataOffset + kPointerSize == 353 kTypeFeedbackInfoOffset); 354 STATIC_ASSERT(kTypeFeedbackInfoOffset + kPointerSize == kNextCodeLinkOffset); 355 356 static bool IsValidSlot(HeapObject* obj, int offset) { 357 // Slots in code can't be invalid because we never trim code objects. 358 return true; 359 } 360 361 template <typename ObjectVisitor> 362 static inline void IterateBody(HeapObject* obj, ObjectVisitor* v) { 363 int mode_mask = RelocInfo::kCodeTargetMask | 364 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 365 RelocInfo::ModeMask(RelocInfo::CELL) | 366 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | 367 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 368 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | 369 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 370 RelocInfo::kDebugBreakSlotMask; 371 372 IteratePointers(obj, kRelocationInfoOffset, kNextCodeLinkOffset, v); 373 v->VisitNextCodeLink(HeapObject::RawField(obj, kNextCodeLinkOffset)); 374 375 RelocIterator it(reinterpret_cast<Code*>(obj), mode_mask); 376 Isolate* isolate = obj->GetIsolate(); 377 for (; !it.done(); it.next()) { 378 it.rinfo()->Visit(isolate, v); 379 } 380 } 381 382 template <typename ObjectVisitor> 383 static inline void IterateBody(HeapObject* obj, int object_size, 384 ObjectVisitor* v) { 385 IterateBody(obj, v); 386 } 387 388 template <typename StaticVisitor> 389 static inline void IterateBody(HeapObject* obj) { 390 int mode_mask = RelocInfo::kCodeTargetMask | 391 RelocInfo::ModeMask(RelocInfo::EMBEDDED_OBJECT) | 392 RelocInfo::ModeMask(RelocInfo::CELL) | 393 RelocInfo::ModeMask(RelocInfo::EXTERNAL_REFERENCE) | 394 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE) | 395 RelocInfo::ModeMask(RelocInfo::INTERNAL_REFERENCE_ENCODED) | 396 RelocInfo::ModeMask(RelocInfo::RUNTIME_ENTRY) | 397 RelocInfo::kDebugBreakSlotMask; 398 399 Heap* heap = obj->GetHeap(); 400 IteratePointers<StaticVisitor>(heap, obj, kRelocationInfoOffset, 401 kNextCodeLinkOffset); 402 StaticVisitor::VisitNextCodeLink( 403 heap, HeapObject::RawField(obj, kNextCodeLinkOffset)); 404 405 RelocIterator it(reinterpret_cast<Code*>(obj), mode_mask); 406 for (; !it.done(); it.next()) { 407 it.rinfo()->template Visit<StaticVisitor>(heap); 408 } 409 } 410 411 template <typename StaticVisitor> 412 static inline void IterateBody(HeapObject* obj, int object_size) { 413 IterateBody<StaticVisitor>(obj); 414 } 415 416 static inline int SizeOf(Map* map, HeapObject* object) { 417 return reinterpret_cast<Code*>(object)->CodeSize(); 418 } 419 }; 420 421 422 template <typename Op, typename ReturnType, typename T1, typename T2, 423 typename T3> 424 ReturnType BodyDescriptorApply(InstanceType type, T1 p1, T2 p2, T3 p3) { 425 if (type < FIRST_NONSTRING_TYPE) { 426 switch (type & kStringRepresentationMask) { 427 case kSeqStringTag: 428 return ReturnType(); 429 case kConsStringTag: 430 return Op::template apply<ConsString::BodyDescriptor>(p1, p2, p3); 431 case kSlicedStringTag: 432 return Op::template apply<SlicedString::BodyDescriptor>(p1, p2, p3); 433 case kExternalStringTag: 434 if ((type & kStringEncodingMask) == kOneByteStringTag) { 435 return Op::template apply<ExternalOneByteString::BodyDescriptor>( 436 p1, p2, p3); 437 } else { 438 return Op::template apply<ExternalTwoByteString::BodyDescriptor>( 439 p1, p2, p3); 440 } 441 } 442 UNREACHABLE(); 443 return ReturnType(); 444 } 445 446 switch (type) { 447 case FIXED_ARRAY_TYPE: 448 return Op::template apply<FixedArray::BodyDescriptor>(p1, p2, p3); 449 case FIXED_DOUBLE_ARRAY_TYPE: 450 return ReturnType(); 451 case TRANSITION_ARRAY_TYPE: 452 return Op::template apply<TransitionArray::BodyDescriptor>(p1, p2, p3); 453 case JS_OBJECT_TYPE: 454 case JS_PROMISE_TYPE: 455 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 456 case JS_GENERATOR_OBJECT_TYPE: 457 case JS_MODULE_TYPE: 458 case JS_VALUE_TYPE: 459 case JS_DATE_TYPE: 460 case JS_ARRAY_TYPE: 461 case JS_TYPED_ARRAY_TYPE: 462 case JS_DATA_VIEW_TYPE: 463 case JS_SET_TYPE: 464 case JS_MAP_TYPE: 465 case JS_SET_ITERATOR_TYPE: 466 case JS_MAP_ITERATOR_TYPE: 467 case JS_ITERATOR_RESULT_TYPE: 468 case JS_REGEXP_TYPE: 469 case JS_GLOBAL_PROXY_TYPE: 470 case JS_GLOBAL_OBJECT_TYPE: 471 case JS_MESSAGE_OBJECT_TYPE: 472 case JS_BOUND_FUNCTION_TYPE: 473 return Op::template apply<JSObject::BodyDescriptor>(p1, p2, p3); 474 case JS_WEAK_MAP_TYPE: 475 case JS_WEAK_SET_TYPE: 476 return Op::template apply<JSWeakCollection::BodyDescriptor>(p1, p2, p3); 477 case JS_ARRAY_BUFFER_TYPE: 478 return Op::template apply<JSArrayBuffer::BodyDescriptor>(p1, p2, p3); 479 case JS_FUNCTION_TYPE: 480 return Op::template apply<JSFunction::BodyDescriptor>(p1, p2, p3); 481 case ODDBALL_TYPE: 482 return Op::template apply<Oddball::BodyDescriptor>(p1, p2, p3); 483 case JS_PROXY_TYPE: 484 return Op::template apply<JSProxy::BodyDescriptor>(p1, p2, p3); 485 case FOREIGN_TYPE: 486 return Op::template apply<Foreign::BodyDescriptor>(p1, p2, p3); 487 case MAP_TYPE: 488 return Op::template apply<Map::BodyDescriptor>(p1, p2, p3); 489 case CODE_TYPE: 490 return Op::template apply<Code::BodyDescriptor>(p1, p2, p3); 491 case CELL_TYPE: 492 return Op::template apply<Cell::BodyDescriptor>(p1, p2, p3); 493 case PROPERTY_CELL_TYPE: 494 return Op::template apply<PropertyCell::BodyDescriptor>(p1, p2, p3); 495 case WEAK_CELL_TYPE: 496 return Op::template apply<WeakCell::BodyDescriptor>(p1, p2, p3); 497 case SYMBOL_TYPE: 498 return Op::template apply<Symbol::BodyDescriptor>(p1, p2, p3); 499 case BYTECODE_ARRAY_TYPE: 500 return Op::template apply<BytecodeArray::BodyDescriptor>(p1, p2, p3); 501 502 case HEAP_NUMBER_TYPE: 503 case MUTABLE_HEAP_NUMBER_TYPE: 504 case SIMD128_VALUE_TYPE: 505 case FILLER_TYPE: 506 case BYTE_ARRAY_TYPE: 507 case FREE_SPACE_TYPE: 508 return ReturnType(); 509 510 #define TYPED_ARRAY_CASE(Type, type, TYPE, ctype, size) \ 511 case FIXED_##TYPE##_ARRAY_TYPE: \ 512 return Op::template apply<FixedTypedArrayBase::BodyDescriptor>(p1, p2, p3); 513 TYPED_ARRAYS(TYPED_ARRAY_CASE) 514 #undef TYPED_ARRAY_CASE 515 516 case SHARED_FUNCTION_INFO_TYPE: { 517 return Op::template apply<SharedFunctionInfo::BodyDescriptor>(p1, p2, p3); 518 } 519 520 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 521 STRUCT_LIST(MAKE_STRUCT_CASE) 522 #undef MAKE_STRUCT_CASE 523 if (type == ALLOCATION_SITE_TYPE) { 524 return Op::template apply<AllocationSite::BodyDescriptor>(p1, p2, p3); 525 } else { 526 return Op::template apply<StructBodyDescriptor>(p1, p2, p3); 527 } 528 default: 529 PrintF("Unknown type: %d\n", type); 530 UNREACHABLE(); 531 return ReturnType(); 532 } 533 } 534 535 536 template <typename ObjectVisitor> 537 void HeapObject::IterateFast(ObjectVisitor* v) { 538 BodyDescriptorBase::IteratePointer(this, kMapOffset, v); 539 IterateBodyFast(v); 540 } 541 542 543 template <typename ObjectVisitor> 544 void HeapObject::IterateBodyFast(ObjectVisitor* v) { 545 Map* m = map(); 546 IterateBodyFast(m->instance_type(), SizeFromMap(m), v); 547 } 548 549 550 struct CallIterateBody { 551 template <typename BodyDescriptor, typename ObjectVisitor> 552 static void apply(HeapObject* obj, int object_size, ObjectVisitor* v) { 553 BodyDescriptor::IterateBody(obj, object_size, v); 554 } 555 }; 556 557 template <typename ObjectVisitor> 558 void HeapObject::IterateBodyFast(InstanceType type, int object_size, 559 ObjectVisitor* v) { 560 BodyDescriptorApply<CallIterateBody, void>(type, this, object_size, v); 561 } 562 } // namespace internal 563 } // namespace v8 564 565 #endif // V8_OBJECTS_BODY_DESCRIPTORS_INL_H_ 566