products/sources/formale Sprachen/Java/openjdk-20-36_src/src/hotspot/share/gc/z image not shown  

Quellcode-Bibliothek

© Kompilation durch diese Firma

[Weder Korrektheit noch Funktionsfähigkeit der Software werden zugesichert.]

Datei: zRelocate.cpp   Sprache: C

/*
 * Copyright (c) 2015, 2021, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */


#include "precompiled.hpp"
#include "gc/shared/gc_globals.hpp"
#include "gc/z/zAbort.inline.hpp"
#include "gc/z/zAddress.inline.hpp"
#include "gc/z/zBarrier.inline.hpp"
#include "gc/z/zForwarding.inline.hpp"
#include "gc/z/zHeap.inline.hpp"
#include "gc/z/zPage.inline.hpp"
#include "gc/z/zRelocate.hpp"
#include "gc/z/zRelocationSet.inline.hpp"
#include "gc/z/zStat.hpp"
#include "gc/z/zTask.hpp"
#include "gc/z/zThread.inline.hpp"
#include "gc/z/zWorkers.hpp"
#include "prims/jvmtiTagMap.hpp"
#include "runtime/atomic.hpp"
#include "utilities/debug.hpp"

ZRelocate::ZRelocate(ZWorkers* workers) :
    _workers(workers) {}

static uintptr_t forwarding_index(ZForwarding* forwarding, uintptr_t from_addr) {
  const uintptr_t from_offset = ZAddress::offset(from_addr);
  return (from_offset - forwarding->start()) >> forwarding->object_alignment_shift();
}

static uintptr_t forwarding_find(ZForwarding* forwarding, uintptr_t from_addr, ZForwardingCursor* cursor) {
  const uintptr_t from_index = forwarding_index(forwarding, from_addr);
  const ZForwardingEntry entry = forwarding->find(from_index, cursor);
  return entry.populated() ? ZAddress::good(entry.to_offset()) : 0;
}

static uintptr_t forwarding_insert(ZForwarding* forwarding, uintptr_t from_addr, uintptr_t to_addr, ZForwardingCursor* cursor) {
  const uintptr_t from_index = forwarding_index(forwarding, from_addr);
  const uintptr_t to_offset = ZAddress::offset(to_addr);
  const uintptr_t to_offset_final = forwarding->insert(from_index, to_offset, cursor);
  return ZAddress::good(to_offset_final);
}

static uintptr_t relocate_object_inner(ZForwarding* forwarding, uintptr_t from_addr, ZForwardingCursor* cursor) {
  assert(ZHeap::heap()->is_object_live(from_addr), "Should be live");

  // Allocate object
  const size_t size = ZUtils::object_size(from_addr);
  const uintptr_t to_addr = ZHeap::heap()->alloc_object_for_relocation(size);
  if (to_addr == 0) {
    // Allocation failed
    return 0;
  }

  // Copy object
  ZUtils::object_copy_disjoint(from_addr, to_addr, size);

  // Insert forwarding
  const uintptr_t to_addr_final = forwarding_insert(forwarding, from_addr, to_addr, cursor);
  if (to_addr_final != to_addr) {
    // Already relocated, try undo allocation
    ZHeap::heap()->undo_alloc_object_for_relocation(to_addr, size);
  }

  return to_addr_final;
}

uintptr_t ZRelocate::relocate_object(ZForwarding* forwarding, uintptr_t from_addr) const {
  ZForwardingCursor cursor;

  // Lookup forwarding
  uintptr_t to_addr = forwarding_find(forwarding, from_addr, &cursor);
  if (to_addr != 0) {
    // Already relocated
    return to_addr;
  }

  // Relocate object
  if (forwarding->retain_page()) {
    to_addr = relocate_object_inner(forwarding, from_addr, &cursor);
    forwarding->release_page();

    if (to_addr != 0) {
      // Success
      return to_addr;
    }

    // Failed to relocate object. Wait for a worker thread to complete
    // relocation of this page, and then forward the object. If the GC
    // aborts the relocation phase before the page has been relocated,
    // then wait return false and we just forward the object in-place.
    if (!forwarding->wait_page_released()) {
      // Forward object in-place
      return forwarding_insert(forwarding, from_addr, from_addr, &cursor);
    }
  }

  // Forward object
  return forward_object(forwarding, from_addr);
}

uintptr_t ZRelocate::forward_object(ZForwarding* forwarding, uintptr_t from_addr) const {
  ZForwardingCursor cursor;
  const uintptr_t to_addr = forwarding_find(forwarding, from_addr, &cursor);
  assert(to_addr != 0, "Should be forwarded");
  return to_addr;
}

static ZPage* alloc_page(const ZForwarding* forwarding) {
  if (ZStressRelocateInPlace) {
    // Simulate failure to allocate a new page. This will
    // cause the page being relocated to be relocated in-place.
    return NULL;
  }

  ZAllocationFlags flags;
  flags.set_non_blocking();
  flags.set_worker_relocation();
  return ZHeap::heap()->alloc_page(forwarding->type(), forwarding->size(), flags);
}

static void free_page(ZPage* page) {
  ZHeap::heap()->free_page(page, true /* reclaimed */);
}

static bool should_free_target_page(ZPage* page) {
  // Free target page if it is empty. We can end up with an empty target
  // page if we allocated a new target page, and then lost the race to
  // relocate the remaining objects, leaving the target page empty when
  // relocation completed.
  return page != NULL && page->top() == page->start();
}

class ZRelocateSmallAllocator {
private:
  volatile size_t _in_place_count;

public:
  ZRelocateSmallAllocator() :
      _in_place_count(0) {}

  ZPage* alloc_target_page(ZForwarding* forwarding, ZPage* target) {
    ZPage* const page = alloc_page(forwarding);
    if (page == NULL) {
      Atomic::inc(&_in_place_count);
    }

    return page;
  }

  void share_target_page(ZPage* page) {
    // Does nothing
  }

  void free_target_page(ZPage* page) {
    if (should_free_target_page(page)) {
      free_page(page);
    }
  }

  void free_relocated_page(ZPage* page) {
    free_page(page);
  }

  uintptr_t alloc_object(ZPage* page, size_t size) const {
    return (page != NULL) ? page->alloc_object(size) : 0;
  }

  void undo_alloc_object(ZPage* page, uintptr_t addr, size_t size) const {
    page->undo_alloc_object(addr, size);
  }

  const size_t in_place_count() const {
    return _in_place_count;
  }
};

class ZRelocateMediumAllocator {
private:
  ZConditionLock      _lock;
  ZPage*              _shared;
  bool                _in_place;
  volatile size_t     _in_place_count;

public:
  ZRelocateMediumAllocator() :
      _lock(),
      _shared(NULL),
      _in_place(false),
      _in_place_count(0) {}

  ~ZRelocateMediumAllocator() {
    if (should_free_target_page(_shared)) {
      free_page(_shared);
    }
  }

  ZPage* alloc_target_page(ZForwarding* forwarding, ZPage* target) {
    ZLocker<ZConditionLock> locker(&_lock);

    // Wait for any ongoing in-place relocation to complete
    while (_in_place) {
      _lock.wait();
    }

    // Allocate a new page only if the shared page is the same as the
    // current target page. The shared page will be different from the
    // current target page if another thread shared a page, or allocated
    // a new page.
    if (_shared == target) {
      _shared = alloc_page(forwarding);
      if (_shared == NULL) {
        Atomic::inc(&_in_place_count);
        _in_place = true;
      }
    }

    return _shared;
  }

  void share_target_page(ZPage* page) {
    ZLocker<ZConditionLock> locker(&_lock);

    assert(_in_place, "Invalid state");
    assert(_shared == NULL, "Invalid state");
    assert(page != NULL, "Invalid page");

    _shared = page;
    _in_place = false;

    _lock.notify_all();
  }

  void free_target_page(ZPage* page) {
    // Does nothing
  }

  void free_relocated_page(ZPage* page) {
    free_page(page);
  }

  uintptr_t alloc_object(ZPage* page, size_t size) const {
    return (page != NULL) ? page->alloc_object_atomic(size) : 0;
  }

  void undo_alloc_object(ZPage* page, uintptr_t addr, size_t size) const {
    page->undo_alloc_object_atomic(addr, size);
  }

  const size_t in_place_count() const {
    return _in_place_count;
  }
};

template <typename Allocator>
class ZRelocateClosure : public ObjectClosure {
private:
  Allocator* const _allocator;
  ZForwarding*     _forwarding;
  ZPage*           _target;

  bool relocate_object(uintptr_t from_addr) const {
    ZForwardingCursor cursor;

    // Lookup forwarding
    if (forwarding_find(_forwarding, from_addr, &cursor) != 0) {
      // Already relocated
      return true;
    }

    // Allocate object
    const size_t size = ZUtils::object_size(from_addr);
    const uintptr_t to_addr = _allocator->alloc_object(_target, size);
    if (to_addr == 0) {
      // Allocation failed
      return false;
    }

    // Copy object. Use conjoint copying if we are relocating
    // in-place and the new object overlapps with the old object.
    if (_forwarding->in_place() && to_addr + size > from_addr) {
      ZUtils::object_copy_conjoint(from_addr, to_addr, size);
    } else {
      ZUtils::object_copy_disjoint(from_addr, to_addr, size);
    }

    // Insert forwarding
    if (forwarding_insert(_forwarding, from_addr, to_addr, &cursor) != to_addr) {
      // Already relocated, undo allocation
      _allocator->undo_alloc_object(_target, to_addr, size);
    }

    return true;
  }

  virtual void do_object(oop obj) {
    const uintptr_t addr = ZOop::to_address(obj);
    assert(ZHeap::heap()->is_object_live(addr), "Should be live");

    while (!relocate_object(addr)) {
      // Allocate a new target page, or if that fails, use the page being
      // relocated as the new target, which will cause it to be relocated
      // in-place.
      _target = _allocator->alloc_target_page(_forwarding, _target);
      if (_target != NULL) {
        continue;
      }

      // Claim the page being relocated to block other threads from accessing
      // it, or its forwarding table, until it has been released (relocation
      // completed).
      _target = _forwarding->claim_page();
      _target->reset_for_in_place_relocation();
      _forwarding->set_in_place();
    }
  }

public:
  ZRelocateClosure(Allocator* allocator) :
      _allocator(allocator),
      _forwarding(NULL),
      _target(NULL) {}

  ~ZRelocateClosure() {
    _allocator->free_target_page(_target);
  }

  void do_forwarding(ZForwarding* forwarding) {
    _forwarding = forwarding;

    // Check if we should abort
    if (ZAbort::should_abort()) {
      _forwarding->abort_page();
      return;
    }

    // Relocate objects
    _forwarding->object_iterate(this);

    // Verify
    if (ZVerifyForwarding) {
      _forwarding->verify();
    }

    // Release relocated page
    _forwarding->release_page();

    if (_forwarding->in_place()) {
      // The relocated page has been relocated in-place and should not
      // be freed. Keep it as target page until it is full, and offer to
      // share it with other worker threads.
      _allocator->share_target_page(_target);
    } else {
      // Detach and free relocated page
      ZPage* const page = _forwarding->detach_page();
      _allocator->free_relocated_page(page);
    }
  }
};

class ZRelocateTask : public ZTask {
private:
  ZRelocationSetParallelIterator _iter;
  ZRelocateSmallAllocator        _small_allocator;
  ZRelocateMediumAllocator       _medium_allocator;

  static bool is_small(ZForwarding* forwarding) {
    return forwarding->type() == ZPageTypeSmall;
  }

public:
  ZRelocateTask(ZRelocationSet* relocation_set) :
      ZTask("ZRelocateTask"),
      _iter(relocation_set),
      _small_allocator(),
      _medium_allocator() {}

  ~ZRelocateTask() {
    ZStatRelocation::set_at_relocate_end(_small_allocator.in_place_count(),
                                         _medium_allocator.in_place_count());
  }

  virtual void work() {
    ZRelocateClosure<ZRelocateSmallAllocator> small(&_small_allocator);
    ZRelocateClosure<ZRelocateMediumAllocator> medium(&_medium_allocator);

    for (ZForwarding* forwarding; _iter.next(&forwarding);) {
      if (is_small(forwarding)) {
        small.do_forwarding(forwarding);
      } else {
        medium.do_forwarding(forwarding);
      }
    }
  }
};

void ZRelocate::relocate(ZRelocationSet* relocation_set) {
  ZRelocateTask task(relocation_set);
  _workers->run(&task);
}

¤ Dauer der Verarbeitung: 0.2 Sekunden  (vorverarbeitet)  ¤





Download des
Quellennavigators
Download des
sprechenden Kalenders

in der Quellcodebibliothek suchen




Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.


Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.


Bot Zugriff