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