1 // Copyright 2011 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/heap/objects-visiting.h" 6 7 #include "src/heap/heap-inl.h" 8 #include "src/heap/mark-compact-inl.h" 9 #include "src/heap/objects-visiting-inl.h" 10 11 namespace v8 { 12 namespace internal { 13 14 15 StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(Map* map) { 16 return GetVisitorId(map->instance_type(), map->instance_size(), 17 FLAG_unbox_double_fields && !map->HasFastPointerLayout()); 18 } 19 20 21 StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId( 22 int instance_type, int instance_size, bool has_unboxed_fields) { 23 if (instance_type < FIRST_NONSTRING_TYPE) { 24 switch (instance_type & kStringRepresentationMask) { 25 case kSeqStringTag: 26 if ((instance_type & kStringEncodingMask) == kOneByteStringTag) { 27 return kVisitSeqOneByteString; 28 } else { 29 return kVisitSeqTwoByteString; 30 } 31 32 case kConsStringTag: 33 if (IsShortcutCandidate(instance_type)) { 34 return kVisitShortcutCandidate; 35 } else { 36 return kVisitConsString; 37 } 38 39 case kSlicedStringTag: 40 return kVisitSlicedString; 41 42 case kExternalStringTag: 43 return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric, 44 instance_size, has_unboxed_fields); 45 46 case kThinStringTag: 47 return kVisitThinString; 48 } 49 UNREACHABLE(); 50 } 51 52 switch (instance_type) { 53 case BYTE_ARRAY_TYPE: 54 return kVisitByteArray; 55 56 case BYTECODE_ARRAY_TYPE: 57 return kVisitBytecodeArray; 58 59 case FREE_SPACE_TYPE: 60 return kVisitFreeSpace; 61 62 case FIXED_ARRAY_TYPE: 63 return kVisitFixedArray; 64 65 case FIXED_DOUBLE_ARRAY_TYPE: 66 return kVisitFixedDoubleArray; 67 68 case ODDBALL_TYPE: 69 return kVisitOddball; 70 71 case MAP_TYPE: 72 return kVisitMap; 73 74 case CODE_TYPE: 75 return kVisitCode; 76 77 case CELL_TYPE: 78 return kVisitCell; 79 80 case PROPERTY_CELL_TYPE: 81 return kVisitPropertyCell; 82 83 case WEAK_CELL_TYPE: 84 return kVisitWeakCell; 85 86 case TRANSITION_ARRAY_TYPE: 87 return kVisitTransitionArray; 88 89 case JS_WEAK_MAP_TYPE: 90 case JS_WEAK_SET_TYPE: 91 return kVisitJSWeakCollection; 92 93 case JS_REGEXP_TYPE: 94 return kVisitJSRegExp; 95 96 case SHARED_FUNCTION_INFO_TYPE: 97 return kVisitSharedFunctionInfo; 98 99 case JS_PROXY_TYPE: 100 return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric, 101 instance_size, has_unboxed_fields); 102 103 case SYMBOL_TYPE: 104 return kVisitSymbol; 105 106 case JS_ARRAY_BUFFER_TYPE: 107 return kVisitJSArrayBuffer; 108 109 case JS_OBJECT_TYPE: 110 case JS_ERROR_TYPE: 111 case JS_ARGUMENTS_TYPE: 112 case JS_ASYNC_FROM_SYNC_ITERATOR_TYPE: 113 case JS_CONTEXT_EXTENSION_OBJECT_TYPE: 114 case JS_GENERATOR_OBJECT_TYPE: 115 case JS_MODULE_NAMESPACE_TYPE: 116 case JS_VALUE_TYPE: 117 case JS_DATE_TYPE: 118 case JS_ARRAY_TYPE: 119 case JS_GLOBAL_PROXY_TYPE: 120 case JS_GLOBAL_OBJECT_TYPE: 121 case JS_MESSAGE_OBJECT_TYPE: 122 case JS_TYPED_ARRAY_TYPE: 123 case JS_DATA_VIEW_TYPE: 124 case JS_SET_TYPE: 125 case JS_MAP_TYPE: 126 case JS_SET_ITERATOR_TYPE: 127 case JS_MAP_ITERATOR_TYPE: 128 case JS_STRING_ITERATOR_TYPE: 129 130 case JS_TYPED_ARRAY_KEY_ITERATOR_TYPE: 131 case JS_FAST_ARRAY_KEY_ITERATOR_TYPE: 132 case JS_GENERIC_ARRAY_KEY_ITERATOR_TYPE: 133 case JS_UINT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: 134 case JS_INT8_ARRAY_KEY_VALUE_ITERATOR_TYPE: 135 case JS_UINT16_ARRAY_KEY_VALUE_ITERATOR_TYPE: 136 case JS_INT16_ARRAY_KEY_VALUE_ITERATOR_TYPE: 137 case JS_UINT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: 138 case JS_INT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: 139 case JS_FLOAT32_ARRAY_KEY_VALUE_ITERATOR_TYPE: 140 case JS_FLOAT64_ARRAY_KEY_VALUE_ITERATOR_TYPE: 141 case JS_UINT8_CLAMPED_ARRAY_KEY_VALUE_ITERATOR_TYPE: 142 case JS_FAST_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: 143 case JS_FAST_HOLEY_SMI_ARRAY_KEY_VALUE_ITERATOR_TYPE: 144 case JS_FAST_ARRAY_KEY_VALUE_ITERATOR_TYPE: 145 case JS_FAST_HOLEY_ARRAY_KEY_VALUE_ITERATOR_TYPE: 146 case JS_FAST_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: 147 case JS_FAST_HOLEY_DOUBLE_ARRAY_KEY_VALUE_ITERATOR_TYPE: 148 case JS_GENERIC_ARRAY_KEY_VALUE_ITERATOR_TYPE: 149 case JS_UINT8_ARRAY_VALUE_ITERATOR_TYPE: 150 case JS_INT8_ARRAY_VALUE_ITERATOR_TYPE: 151 case JS_UINT16_ARRAY_VALUE_ITERATOR_TYPE: 152 case JS_INT16_ARRAY_VALUE_ITERATOR_TYPE: 153 case JS_UINT32_ARRAY_VALUE_ITERATOR_TYPE: 154 case JS_INT32_ARRAY_VALUE_ITERATOR_TYPE: 155 case JS_FLOAT32_ARRAY_VALUE_ITERATOR_TYPE: 156 case JS_FLOAT64_ARRAY_VALUE_ITERATOR_TYPE: 157 case JS_UINT8_CLAMPED_ARRAY_VALUE_ITERATOR_TYPE: 158 case JS_FAST_SMI_ARRAY_VALUE_ITERATOR_TYPE: 159 case JS_FAST_HOLEY_SMI_ARRAY_VALUE_ITERATOR_TYPE: 160 case JS_FAST_ARRAY_VALUE_ITERATOR_TYPE: 161 case JS_FAST_HOLEY_ARRAY_VALUE_ITERATOR_TYPE: 162 case JS_FAST_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: 163 case JS_FAST_HOLEY_DOUBLE_ARRAY_VALUE_ITERATOR_TYPE: 164 case JS_GENERIC_ARRAY_VALUE_ITERATOR_TYPE: 165 166 case JS_PROMISE_CAPABILITY_TYPE: 167 case JS_PROMISE_TYPE: 168 case JS_BOUND_FUNCTION_TYPE: 169 return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric, 170 instance_size, has_unboxed_fields); 171 case JS_API_OBJECT_TYPE: 172 case JS_SPECIAL_API_OBJECT_TYPE: 173 return GetVisitorIdForSize(kVisitJSApiObject, kVisitJSApiObjectGeneric, 174 instance_size, has_unboxed_fields); 175 176 case JS_FUNCTION_TYPE: 177 return kVisitJSFunction; 178 179 case FILLER_TYPE: 180 if (instance_size == kPointerSize) return kVisitDataObjectGeneric; 181 // Fall through. 182 case FOREIGN_TYPE: 183 case HEAP_NUMBER_TYPE: 184 case MUTABLE_HEAP_NUMBER_TYPE: 185 return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric, 186 instance_size, has_unboxed_fields); 187 188 case FIXED_UINT8_ARRAY_TYPE: 189 case FIXED_INT8_ARRAY_TYPE: 190 case FIXED_UINT16_ARRAY_TYPE: 191 case FIXED_INT16_ARRAY_TYPE: 192 case FIXED_UINT32_ARRAY_TYPE: 193 case FIXED_INT32_ARRAY_TYPE: 194 case FIXED_FLOAT32_ARRAY_TYPE: 195 case FIXED_UINT8_CLAMPED_ARRAY_TYPE: 196 return kVisitFixedTypedArray; 197 198 case FIXED_FLOAT64_ARRAY_TYPE: 199 return kVisitFixedFloat64Array; 200 201 #define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE: 202 STRUCT_LIST(MAKE_STRUCT_CASE) 203 #undef MAKE_STRUCT_CASE 204 if (instance_type == ALLOCATION_SITE_TYPE) { 205 return kVisitAllocationSite; 206 } 207 208 return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric, 209 instance_size, has_unboxed_fields); 210 211 default: 212 UNREACHABLE(); 213 return kVisitorIdCount; 214 } 215 } 216 217 218 // We don't record weak slots during marking or scavenges. Instead we do it 219 // once when we complete mark-compact cycle. Note that write barrier has no 220 // effect if we are already in the middle of compacting mark-sweep cycle and we 221 // have to record slots manually. 222 static bool MustRecordSlots(Heap* heap) { 223 return heap->gc_state() == Heap::MARK_COMPACT && 224 heap->mark_compact_collector()->is_compacting(); 225 } 226 227 228 template <class T> 229 struct WeakListVisitor; 230 231 232 template <class T> 233 Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) { 234 Object* undefined = heap->undefined_value(); 235 Object* head = undefined; 236 T* tail = NULL; 237 MarkCompactCollector* collector = heap->mark_compact_collector(); 238 bool record_slots = MustRecordSlots(heap); 239 240 while (list != undefined) { 241 // Check whether to keep the candidate in the list. 242 T* candidate = reinterpret_cast<T*>(list); 243 244 Object* retained = retainer->RetainAs(list); 245 if (retained != NULL) { 246 if (head == undefined) { 247 // First element in the list. 248 head = retained; 249 } else { 250 // Subsequent elements in the list. 251 DCHECK(tail != NULL); 252 WeakListVisitor<T>::SetWeakNext(tail, retained); 253 if (record_slots) { 254 Object** next_slot = 255 HeapObject::RawField(tail, WeakListVisitor<T>::WeakNextOffset()); 256 collector->RecordSlot(tail, next_slot, retained); 257 } 258 } 259 // Retained object is new tail. 260 DCHECK(!retained->IsUndefined(heap->isolate())); 261 candidate = reinterpret_cast<T*>(retained); 262 tail = candidate; 263 264 // tail is a live object, visit it. 265 WeakListVisitor<T>::VisitLiveObject(heap, tail, retainer); 266 267 } else { 268 WeakListVisitor<T>::VisitPhantomObject(heap, candidate); 269 } 270 271 // Move to next element in the list. 272 list = WeakListVisitor<T>::WeakNext(candidate); 273 } 274 275 // Terminate the list if there is one or more elements. 276 if (tail != NULL) WeakListVisitor<T>::SetWeakNext(tail, undefined); 277 return head; 278 } 279 280 281 template <class T> 282 static void ClearWeakList(Heap* heap, Object* list) { 283 Object* undefined = heap->undefined_value(); 284 while (list != undefined) { 285 T* candidate = reinterpret_cast<T*>(list); 286 list = WeakListVisitor<T>::WeakNext(candidate); 287 WeakListVisitor<T>::SetWeakNext(candidate, undefined); 288 } 289 } 290 291 292 template <> 293 struct WeakListVisitor<JSFunction> { 294 static void SetWeakNext(JSFunction* function, Object* next) { 295 function->set_next_function_link(next, UPDATE_WEAK_WRITE_BARRIER); 296 } 297 298 static Object* WeakNext(JSFunction* function) { 299 return function->next_function_link(); 300 } 301 302 static int WeakNextOffset() { return JSFunction::kNextFunctionLinkOffset; } 303 304 static void VisitLiveObject(Heap*, JSFunction*, WeakObjectRetainer*) {} 305 306 static void VisitPhantomObject(Heap*, JSFunction*) {} 307 }; 308 309 310 template <> 311 struct WeakListVisitor<Code> { 312 static void SetWeakNext(Code* code, Object* next) { 313 code->set_next_code_link(next, UPDATE_WEAK_WRITE_BARRIER); 314 } 315 316 static Object* WeakNext(Code* code) { return code->next_code_link(); } 317 318 static int WeakNextOffset() { return Code::kNextCodeLinkOffset; } 319 320 static void VisitLiveObject(Heap*, Code*, WeakObjectRetainer*) {} 321 322 static void VisitPhantomObject(Heap*, Code*) {} 323 }; 324 325 326 template <> 327 struct WeakListVisitor<Context> { 328 static void SetWeakNext(Context* context, Object* next) { 329 context->set(Context::NEXT_CONTEXT_LINK, next, UPDATE_WEAK_WRITE_BARRIER); 330 } 331 332 static Object* WeakNext(Context* context) { 333 return context->next_context_link(); 334 } 335 336 static int WeakNextOffset() { 337 return FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK); 338 } 339 340 static void VisitLiveObject(Heap* heap, Context* context, 341 WeakObjectRetainer* retainer) { 342 // Process the three weak lists linked off the context. 343 DoWeakList<JSFunction>(heap, context, retainer, 344 Context::OPTIMIZED_FUNCTIONS_LIST); 345 346 if (heap->gc_state() == Heap::MARK_COMPACT) { 347 // Record the slots of the weak entries in the native context. 348 MarkCompactCollector* collector = heap->mark_compact_collector(); 349 for (int idx = Context::FIRST_WEAK_SLOT; 350 idx < Context::NATIVE_CONTEXT_SLOTS; ++idx) { 351 Object** slot = Context::cast(context)->RawFieldOfElementAt(idx); 352 collector->RecordSlot(context, slot, *slot); 353 } 354 // Code objects are always allocated in Code space, we do not have to 355 // visit 356 // them during scavenges. 357 DoWeakList<Code>(heap, context, retainer, Context::OPTIMIZED_CODE_LIST); 358 DoWeakList<Code>(heap, context, retainer, Context::DEOPTIMIZED_CODE_LIST); 359 } 360 } 361 362 template <class T> 363 static void DoWeakList(Heap* heap, Context* context, 364 WeakObjectRetainer* retainer, int index) { 365 // Visit the weak list, removing dead intermediate elements. 366 Object* list_head = VisitWeakList<T>(heap, context->get(index), retainer); 367 368 // Update the list head. 369 context->set(index, list_head, UPDATE_WRITE_BARRIER); 370 371 if (MustRecordSlots(heap)) { 372 // Record the updated slot if necessary. 373 Object** head_slot = 374 HeapObject::RawField(context, FixedArray::SizeFor(index)); 375 heap->mark_compact_collector()->RecordSlot(context, head_slot, list_head); 376 } 377 } 378 379 static void VisitPhantomObject(Heap* heap, Context* context) { 380 ClearWeakList<JSFunction>(heap, 381 context->get(Context::OPTIMIZED_FUNCTIONS_LIST)); 382 ClearWeakList<Code>(heap, context->get(Context::OPTIMIZED_CODE_LIST)); 383 ClearWeakList<Code>(heap, context->get(Context::DEOPTIMIZED_CODE_LIST)); 384 } 385 }; 386 387 388 template <> 389 struct WeakListVisitor<AllocationSite> { 390 static void SetWeakNext(AllocationSite* obj, Object* next) { 391 obj->set_weak_next(next, UPDATE_WEAK_WRITE_BARRIER); 392 } 393 394 static Object* WeakNext(AllocationSite* obj) { return obj->weak_next(); } 395 396 static int WeakNextOffset() { return AllocationSite::kWeakNextOffset; } 397 398 static void VisitLiveObject(Heap*, AllocationSite*, WeakObjectRetainer*) {} 399 400 static void VisitPhantomObject(Heap*, AllocationSite*) {} 401 }; 402 403 404 template Object* VisitWeakList<Context>(Heap* heap, Object* list, 405 WeakObjectRetainer* retainer); 406 407 template Object* VisitWeakList<AllocationSite>(Heap* heap, Object* list, 408 WeakObjectRetainer* retainer); 409 } // namespace internal 410 } // namespace v8 411