objects-visiting.cc 10.7 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5
#include "src/v8.h"
6

7
#include "src/heap/objects-visiting.h"
8

9 10 11 12 13
namespace v8 {
namespace internal {


StaticVisitorBase::VisitorId StaticVisitorBase::GetVisitorId(
14
    int instance_type, int instance_size, bool has_unboxed_fields) {
15 16 17
  if (instance_type < FIRST_NONSTRING_TYPE) {
    switch (instance_type & kStringRepresentationMask) {
      case kSeqStringTag:
18
        if ((instance_type & kStringEncodingMask) == kOneByteStringTag) {
19
          return kVisitSeqOneByteString;
20 21 22 23 24 25 26 27 28 29 30
        } else {
          return kVisitSeqTwoByteString;
        }

      case kConsStringTag:
        if (IsShortcutCandidate(instance_type)) {
          return kVisitShortcutCandidate;
        } else {
          return kVisitConsString;
        }

31 32 33
      case kSlicedStringTag:
        return kVisitSlicedString;

34
      case kExternalStringTag:
35
        return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
36
                                   instance_size, has_unboxed_fields);
37 38 39 40 41 42 43 44
    }
    UNREACHABLE();
  }

  switch (instance_type) {
    case BYTE_ARRAY_TYPE:
      return kVisitByteArray;

45 46 47
    case FREE_SPACE_TYPE:
      return kVisitFreeSpace;

48 49 50
    case FIXED_ARRAY_TYPE:
      return kVisitFixedArray;

51 52 53
    case FIXED_DOUBLE_ARRAY_TYPE:
      return kVisitFixedDoubleArray;

54 55 56
    case CONSTANT_POOL_ARRAY_TYPE:
      return kVisitConstantPoolArray;

57 58 59 60 61 62 63 64 65
    case ODDBALL_TYPE:
      return kVisitOddball;

    case MAP_TYPE:
      return kVisitMap;

    case CODE_TYPE:
      return kVisitCode;

66 67 68 69
    case CELL_TYPE:
      return kVisitCell;

    case PROPERTY_CELL_TYPE:
70 71
      return kVisitPropertyCell;

ulan@chromium.org's avatar
ulan@chromium.org committed
72 73 74
    case WEAK_CELL_TYPE:
      return kVisitWeakCell;

75
    case JS_SET_TYPE:
76
      return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
77
                                 JSSet::kSize, has_unboxed_fields);
78 79

    case JS_MAP_TYPE:
80
      return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
81
                                 JSMap::kSize, has_unboxed_fields);
82

83
    case JS_WEAK_MAP_TYPE:
84
    case JS_WEAK_SET_TYPE:
85
      return kVisitJSWeakCollection;
86

87 88 89
    case JS_REGEXP_TYPE:
      return kVisitJSRegExp;

90 91 92
    case SHARED_FUNCTION_INFO_TYPE:
      return kVisitSharedFunctionInfo;

93
    case JS_PROXY_TYPE:
94
      return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
95
                                 JSProxy::kSize, has_unboxed_fields);
96

97
    case JS_FUNCTION_PROXY_TYPE:
98
      return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
99
                                 JSFunctionProxy::kSize, has_unboxed_fields);
100

101
    case FOREIGN_TYPE:
102
      return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
103
                                 Foreign::kSize, has_unboxed_fields);
104

105
    case SYMBOL_TYPE:
106
      return kVisitSymbol;
107

108 109 110
    case FILLER_TYPE:
      return kVisitDataObjectGeneric;

111 112 113 114 115 116
    case JS_ARRAY_BUFFER_TYPE:
      return kVisitJSArrayBuffer;

    case JS_TYPED_ARRAY_TYPE:
      return kVisitJSTypedArray;

117 118 119
    case JS_DATA_VIEW_TYPE:
      return kVisitJSDataView;

120 121
    case JS_OBJECT_TYPE:
    case JS_CONTEXT_EXTENSION_OBJECT_TYPE:
122
    case JS_GENERATOR_OBJECT_TYPE:
123
    case JS_MODULE_TYPE:
124
    case JS_VALUE_TYPE:
125
    case JS_DATE_TYPE:
126 127 128 129
    case JS_ARRAY_TYPE:
    case JS_GLOBAL_PROXY_TYPE:
    case JS_GLOBAL_OBJECT_TYPE:
    case JS_BUILTINS_OBJECT_TYPE:
130
    case JS_MESSAGE_OBJECT_TYPE:
131 132
    case JS_SET_ITERATOR_TYPE:
    case JS_MAP_ITERATOR_TYPE:
133
      return GetVisitorIdForSize(kVisitJSObject, kVisitJSObjectGeneric,
134
                                 instance_size, has_unboxed_fields);
135

136 137 138
    case JS_FUNCTION_TYPE:
      return kVisitJSFunction;

139
    case HEAP_NUMBER_TYPE:
140
    case MUTABLE_HEAP_NUMBER_TYPE:
141 142
#define EXTERNAL_ARRAY_CASE(Type, type, TYPE, ctype, size) \
  case EXTERNAL_##TYPE##_ARRAY_TYPE:
143

144 145
      TYPED_ARRAYS(EXTERNAL_ARRAY_CASE)
      return GetVisitorIdForSize(kVisitDataObject, kVisitDataObjectGeneric,
146
                                 instance_size, has_unboxed_fields);
147
#undef EXTERNAL_ARRAY_CASE
148

149 150 151 152 153 154 155 156 157 158 159 160 161
    case FIXED_UINT8_ARRAY_TYPE:
    case FIXED_INT8_ARRAY_TYPE:
    case FIXED_UINT16_ARRAY_TYPE:
    case FIXED_INT16_ARRAY_TYPE:
    case FIXED_UINT32_ARRAY_TYPE:
    case FIXED_INT32_ARRAY_TYPE:
    case FIXED_FLOAT32_ARRAY_TYPE:
    case FIXED_UINT8_CLAMPED_ARRAY_TYPE:
      return kVisitFixedTypedArray;

    case FIXED_FLOAT64_ARRAY_TYPE:
      return kVisitFixedFloat64Array;

162
#define MAKE_STRUCT_CASE(NAME, Name, name) case NAME##_TYPE:
163 164
      STRUCT_LIST(MAKE_STRUCT_CASE)
#undef MAKE_STRUCT_CASE
165 166 167
      if (instance_type == ALLOCATION_SITE_TYPE) {
        return kVisitAllocationSite;
      }
168

169
      return GetVisitorIdForSize(kVisitStruct, kVisitStructGeneric,
170
                                 instance_size, has_unboxed_fields);
171 172 173 174 175 176 177

    default:
      UNREACHABLE();
      return kVisitorIdCount;
  }
}

178

179 180 181 182 183 184
// We don't record weak slots during marking or scavenges. Instead we do it
// once when we complete mark-compact cycle.  Note that write barrier has no
// effect if we are already in the middle of compacting mark-sweep cycle and we
// have to record slots manually.
static bool MustRecordSlots(Heap* heap) {
  return heap->gc_state() == Heap::MARK_COMPACT &&
185
         heap->mark_compact_collector()->is_compacting();
186 187 188
}


189 190 191 192 193
template <class T>
struct WeakListVisitor;


template <class T>
194
Object* VisitWeakList(Heap* heap, Object* list, WeakObjectRetainer* retainer) {
195 196 197 198
  Object* undefined = heap->undefined_value();
  Object* head = undefined;
  T* tail = NULL;
  MarkCompactCollector* collector = heap->mark_compact_collector();
199
  bool record_slots = MustRecordSlots(heap);
200

201 202 203
  while (list != undefined) {
    // Check whether to keep the candidate in the list.
    T* candidate = reinterpret_cast<T*>(list);
204

205 206 207 208 209 210 211
    Object* retained = retainer->RetainAs(list);
    if (retained != NULL) {
      if (head == undefined) {
        // First element in the list.
        head = retained;
      } else {
        // Subsequent elements in the list.
212
        DCHECK(tail != NULL);
213 214 215
        WeakListVisitor<T>::SetWeakNext(tail, retained);
        if (record_slots) {
          Object** next_slot =
216
              HeapObject::RawField(tail, WeakListVisitor<T>::WeakNextOffset());
217 218 219 220
          collector->RecordSlot(next_slot, next_slot, retained);
        }
      }
      // Retained object is new tail.
221
      DCHECK(!retained->IsUndefined());
222 223 224 225
      candidate = reinterpret_cast<T*>(retained);
      tail = candidate;

      // tail is a live object, visit it.
226
      WeakListVisitor<T>::VisitLiveObject(heap, tail, retainer);
227

228 229 230 231 232 233 234 235 236
    } else {
      WeakListVisitor<T>::VisitPhantomObject(heap, candidate);
    }

    // Move to next element in the list.
    list = WeakListVisitor<T>::WeakNext(candidate);
  }

  // Terminate the list if there is one or more elements.
237
  if (tail != NULL) WeakListVisitor<T>::SetWeakNext(tail, undefined);
238 239 240 241 242
  return head;
}


template <class T>
243
static void ClearWeakList(Heap* heap, Object* list) {
244 245 246 247 248 249 250 251 252
  Object* undefined = heap->undefined_value();
  while (list != undefined) {
    T* candidate = reinterpret_cast<T*>(list);
    list = WeakListVisitor<T>::WeakNext(candidate);
    WeakListVisitor<T>::SetWeakNext(candidate, undefined);
  }
}


253
template <>
254 255 256 257 258 259 260 261 262
struct WeakListVisitor<JSFunction> {
  static void SetWeakNext(JSFunction* function, Object* next) {
    function->set_next_function_link(next);
  }

  static Object* WeakNext(JSFunction* function) {
    return function->next_function_link();
  }

263
  static int WeakNextOffset() { return JSFunction::kNextFunctionLinkOffset; }
264

265
  static void VisitLiveObject(Heap*, JSFunction*, WeakObjectRetainer*) {}
266

267
  static void VisitPhantomObject(Heap*, JSFunction*) {}
268 269 270
};


271
template <>
272 273 274 275 276
struct WeakListVisitor<Code> {
  static void SetWeakNext(Code* code, Object* next) {
    code->set_next_code_link(next);
  }

277
  static Object* WeakNext(Code* code) { return code->next_code_link(); }
278

279
  static int WeakNextOffset() { return Code::kNextCodeLinkOffset; }
280

281
  static void VisitLiveObject(Heap*, Code*, WeakObjectRetainer*) {}
282

283
  static void VisitPhantomObject(Heap*, Code*) {}
284 285 286
};


287
template <>
288 289
struct WeakListVisitor<Context> {
  static void SetWeakNext(Context* context, Object* next) {
290
    context->set(Context::NEXT_CONTEXT_LINK, next, UPDATE_WRITE_BARRIER);
291 292 293 294 295 296
  }

  static Object* WeakNext(Context* context) {
    return context->get(Context::NEXT_CONTEXT_LINK);
  }

297 298 299 300
  static int WeakNextOffset() {
    return FixedArray::SizeFor(Context::NEXT_CONTEXT_LINK);
  }

301
  static void VisitLiveObject(Heap* heap, Context* context,
302
                              WeakObjectRetainer* retainer) {
303
    // Process the three weak lists linked off the context.
304
    DoWeakList<JSFunction>(heap, context, retainer,
305
                           Context::OPTIMIZED_FUNCTIONS_LIST);
306 307 308 309 310 311 312

    // Code objects are always allocated in Code space, we do not have to visit
    // them during scavenges.
    if (heap->gc_state() == Heap::MARK_COMPACT) {
      DoWeakList<Code>(heap, context, retainer, Context::OPTIMIZED_CODE_LIST);
      DoWeakList<Code>(heap, context, retainer, Context::DEOPTIMIZED_CODE_LIST);
    }
313 314
  }

315 316 317
  template <class T>
  static void DoWeakList(Heap* heap, Context* context,
                         WeakObjectRetainer* retainer, int index) {
318
    // Visit the weak list, removing dead intermediate elements.
319
    Object* list_head = VisitWeakList<T>(heap, context->get(index), retainer);
320 321 322 323

    // Update the list head.
    context->set(index, list_head, UPDATE_WRITE_BARRIER);

324
    if (MustRecordSlots(heap)) {
325
      // Record the updated slot if necessary.
326 327 328 329
      Object** head_slot =
          HeapObject::RawField(context, FixedArray::SizeFor(index));
      heap->mark_compact_collector()->RecordSlot(head_slot, head_slot,
                                                 list_head);
330 331 332 333 334
    }
  }

  static void VisitPhantomObject(Heap* heap, Context* context) {
    ClearWeakList<JSFunction>(heap,
335
                              context->get(Context::OPTIMIZED_FUNCTIONS_LIST));
336 337 338 339 340 341
    ClearWeakList<Code>(heap, context->get(Context::OPTIMIZED_CODE_LIST));
    ClearWeakList<Code>(heap, context->get(Context::DEOPTIMIZED_CODE_LIST));
  }
};


342
template <>
343 344 345 346 347
struct WeakListVisitor<AllocationSite> {
  static void SetWeakNext(AllocationSite* obj, Object* next) {
    obj->set_weak_next(next);
  }

348
  static Object* WeakNext(AllocationSite* obj) { return obj->weak_next(); }
349

350
  static int WeakNextOffset() { return AllocationSite::kWeakNextOffset; }
351 352 353 354

  static void VisitLiveObject(Heap*, AllocationSite*, WeakObjectRetainer*) {}

  static void VisitPhantomObject(Heap*, AllocationSite*) {}
355 356 357
};


358
template Object* VisitWeakList<Context>(Heap* heap, Object* list,
359
                                        WeakObjectRetainer* retainer);
360

361
template Object* VisitWeakList<AllocationSite>(Heap* heap, Object* list,
362
                                               WeakObjectRetainer* retainer);
363 364
}
}  // namespace v8::internal