// Copyright 2020 the V8 project authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "src/heap/weak-object-worklists.h" #include "src/heap/heap-inl.h" #include "src/heap/heap.h" #include "src/objects/hash-table.h" #include "src/objects/heap-object.h" #include "src/objects/js-function.h" #include "src/objects/js-weak-refs-inl.h" #include "src/objects/js-weak-refs.h" #include "src/objects/shared-function-info.h" #include "src/objects/transitions.h" namespace v8 { namespace internal { WeakObjects::Local::Local(WeakObjects* weak_objects) : WeakObjects::UnusedBase() #define INIT_LOCAL_WORKLIST(_, name, __) , name##_local(&weak_objects->name) WEAK_OBJECT_WORKLISTS(INIT_LOCAL_WORKLIST) #undef INIT_LOCAL_WORKLIST { } void WeakObjects::Local::Publish() { #define INVOKE_PUBLISH(_, name, __) name##_local.Publish(); WEAK_OBJECT_WORKLISTS(INVOKE_PUBLISH) #undef INVOKE_PUBLISH } void WeakObjects::UpdateAfterScavenge() { #define INVOKE_UPDATE(_, name, Name) Update##Name(name); WEAK_OBJECT_WORKLISTS(INVOKE_UPDATE) #undef INVOKE_UPDATE } void WeakObjects::Clear() { #define INVOKE_CLEAR(_, name, __) name.Clear(); WEAK_OBJECT_WORKLISTS(INVOKE_CLEAR) #undef INVOKE_CLEAR } // static void WeakObjects::UpdateTransitionArrays( WeakObjectWorklist<TransitionArray>& transition_arrays) { DCHECK(!ContainsYoungObjects(transition_arrays)); } // static void WeakObjects::UpdateEphemeronHashTables( WeakObjectWorklist<EphemeronHashTable>& ephemeron_hash_tables) { ephemeron_hash_tables.Update( [](EphemeronHashTable slot_in, EphemeronHashTable* slot_out) -> bool { EphemeronHashTable forwarded = ForwardingAddress(slot_in); if (!forwarded.is_null()) { *slot_out = forwarded; return true; } return false; }); } namespace { bool EphemeronUpdater(Ephemeron slot_in, Ephemeron* slot_out) { HeapObject key = slot_in.key; HeapObject value = slot_in.value; HeapObject forwarded_key = ForwardingAddress(key); HeapObject forwarded_value = ForwardingAddress(value); if (!forwarded_key.is_null() && !forwarded_value.is_null()) { *slot_out = Ephemeron{forwarded_key, forwarded_value}; return true; } return false; } } // anonymous namespace // static void WeakObjects::UpdateCurrentEphemerons( WeakObjectWorklist<Ephemeron>& current_ephemerons) { current_ephemerons.Update(EphemeronUpdater); } // static void WeakObjects::UpdateNextEphemerons( WeakObjectWorklist<Ephemeron>& next_ephemerons) { next_ephemerons.Update(EphemeronUpdater); } // static void WeakObjects::UpdateDiscoveredEphemerons( WeakObjectWorklist<Ephemeron>& discovered_ephemerons) { discovered_ephemerons.Update(EphemeronUpdater); } // static void WeakObjects::UpdateWeakReferences( WeakObjectWorklist<HeapObjectAndSlot>& weak_references) { weak_references.Update( [](HeapObjectAndSlot slot_in, HeapObjectAndSlot* slot_out) -> bool { HeapObject heap_obj = slot_in.first; HeapObject forwarded = ForwardingAddress(heap_obj); if (!forwarded.is_null()) { ptrdiff_t distance_to_slot = slot_in.second.address() - slot_in.first.ptr(); Address new_slot = forwarded.ptr() + distance_to_slot; slot_out->first = forwarded; slot_out->second = HeapObjectSlot(new_slot); return true; } return false; }); } // static void WeakObjects::UpdateWeakObjectsInCode( WeakObjectWorklist<HeapObjectAndCode>& weak_objects_in_code) { weak_objects_in_code.Update( [](HeapObjectAndCode slot_in, HeapObjectAndCode* slot_out) -> bool { HeapObject heap_obj = slot_in.first; HeapObject forwarded = ForwardingAddress(heap_obj); if (!forwarded.is_null()) { slot_out->first = forwarded; slot_out->second = slot_in.second; return true; } return false; }); } // static void WeakObjects::UpdateJSWeakRefs( WeakObjectWorklist<JSWeakRef>& js_weak_refs) { js_weak_refs.Update( [](JSWeakRef js_weak_ref_in, JSWeakRef* js_weak_ref_out) -> bool { JSWeakRef forwarded = ForwardingAddress(js_weak_ref_in); if (!forwarded.is_null()) { *js_weak_ref_out = forwarded; return true; } return false; }); } // static void WeakObjects::UpdateWeakCells(WeakObjectWorklist<WeakCell>& weak_cells) { // TODO(syg, marja): Support WeakCells in the young generation. DCHECK(!ContainsYoungObjects(weak_cells)); } // static void WeakObjects::UpdateCodeFlushingCandidates( WeakObjectWorklist<SharedFunctionInfo>& code_flushing_candidates) { DCHECK(!ContainsYoungObjects(code_flushing_candidates)); } // static void WeakObjects::UpdateFlushedJSFunctions( WeakObjectWorklist<JSFunction>& flushed_js_functions) { flushed_js_functions.Update( [](JSFunction slot_in, JSFunction* slot_out) -> bool { JSFunction forwarded = ForwardingAddress(slot_in); if (!forwarded.is_null()) { *slot_out = forwarded; return true; } return false; }); } // static void WeakObjects::UpdateBaselineFlushingCandidates( WeakObjectWorklist<JSFunction>& baseline_flush_candidates) { baseline_flush_candidates.Update( [](JSFunction slot_in, JSFunction* slot_out) -> bool { JSFunction forwarded = ForwardingAddress(slot_in); if (!forwarded.is_null()) { *slot_out = forwarded; return true; } return false; }); } #ifdef DEBUG // static template <typename Type> bool WeakObjects::ContainsYoungObjects(WeakObjectWorklist<Type>& worklist) { bool result = false; worklist.Iterate([&result](Type candidate) { if (Heap::InYoungGeneration(candidate)) { result = true; } }); return result; } #endif } // namespace internal } // namespace v8