Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openjdk/src/hotspot/share/services/   (Sun/Oracle ©)  Datei vom 13.11.2022 mit Größe 11 kB image not shown  

Quelle  finalizerService.cpp   Sprache: C

 
/*
 * Copyright (c) 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 "utilities/macros.hpp"
#if INCLUDE_MANAGEMENT
#include "classfile/classLoaderDataGraph.inline.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "memory/resourceArea.hpp"
#include "logging/log.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "runtime/atomic.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/javaThread.hpp"
#include "runtime/mutexLocker.hpp"
#include "runtime/synchronizer.hpp"
#include "services/finalizerService.hpp"
#include "utilities/concurrentHashTableTasks.inline.hpp"
#include "utilities/debug.hpp"

static const char* allocate(oop string) {
  char* str = nullptr;
  const typeArrayOop value = java_lang_String::value(string);
  if (value != nullptr) {
    const int length = java_lang_String::utf8_length(string, value);
    str = NEW_C_HEAP_ARRAY(char, length + 1, mtServiceability);
    java_lang_String::as_utf8_string(string, value, str, length + 1);
  }
  return str;
}

static int compute_field_offset(const Klass* klass, const char* field_name, const char* field_signature) {
  assert(klass != nullptr, "invariant");
  Symbol* const name = SymbolTable::new_symbol(field_name);
  assert(name != nullptr, "invariant");
  Symbol* const signature = SymbolTable::new_symbol(field_signature);
  assert(signature != nullptr, "invariant");
  assert(klass->is_instance_klass(), "invariant");
  fieldDescriptor fd;
  InstanceKlass::cast(klass)->find_field(name, signature, false, &fd);
  return fd.offset();
}

static const char* location_no_frag_string(oop codesource) {
  assert(codesource != nullptr, "invariant");
  static int loc_no_frag_offset = compute_field_offset(codesource->klass(), "locationNoFragString""Ljava/lang/String;");
  oop string = codesource->obj_field(loc_no_frag_offset);
  return string != nullptr ? allocate(string) : nullptr;
}

static oop codesource(oop pd) {
  assert(pd != nullptr, "invariant");
  static int codesource_offset = compute_field_offset(pd->klass(), "codesource""Ljava/security/CodeSource;");
  return pd->obj_field(codesource_offset);
}

static const char* get_codesource(const InstanceKlass* ik) {
  assert(ik != nullptr, "invariant");
  oop pd = java_lang_Class::protection_domain(ik->java_mirror());
  if (pd == nullptr) {
    return nullptr;
  }
  oop cs = codesource(pd);
  return cs != nullptr ? location_no_frag_string(cs) : nullptr;
}

FinalizerEntry::FinalizerEntry(const InstanceKlass* ik) :
    _ik(ik),
    _codesource(get_codesource(ik)),
    _objects_on_heap(0),
    _total_finalizers_run(0) {}

FinalizerEntry::~FinalizerEntry() {
  FREE_C_HEAP_ARRAY(char, _codesource);
}

const InstanceKlass* FinalizerEntry::klass() const {
  return _ik;
}

const char* FinalizerEntry::codesource() const {
  return _codesource;
}

uintptr_t FinalizerEntry::objects_on_heap() const {
  return Atomic::load(&_objects_on_heap);
}

uintptr_t FinalizerEntry::total_finalizers_run() const {
  return Atomic::load(&_total_finalizers_run);
}

void FinalizerEntry::on_register() {
  Atomic::inc(&_objects_on_heap, memory_order_relaxed);
}

void FinalizerEntry::on_complete() {
  Atomic::inc(&_total_finalizers_run, memory_order_relaxed);
  Atomic::dec(&_objects_on_heap, memory_order_relaxed);
}

static inline uintx hash_function(const InstanceKlass* ik) {
  assert(ik != nullptr, "invariant");
  return primitive_hash(ik);
}

static inline uintx hash_function(const FinalizerEntry* fe) {
  return hash_function(fe->klass());
}

class FinalizerEntryLookup : StackObj {
 private:
  const InstanceKlass* const _ik;
 public:
  FinalizerEntryLookup(const InstanceKlass* ik) : _ik(ik) {}
  uintx get_hash() const { return hash_function(_ik); }
  bool equals(FinalizerEntry** value, bool* is_dead) {
    assert(value != nullptr, "invariant");
    assert(*value != nullptr, "invariant");
    return (*value)->klass() == _ik;
  }
};

class FinalizerTableConfig : public AllStatic {
 public:
  typedef FinalizerEntry* Value;  // value of the Node in the hashtable

  static uintx get_hash(Value const& value, bool* is_dead) {
    return hash_function(value);
  }
  static void* allocate_node(void* context, size_t size, Value const& value) {
    return AllocateHeap(size, mtServiceability);
  }
  static void free_node(void* context, void* memory, Value const& value) {
    FreeHeap(memory);
  }
};

typedef ConcurrentHashTable<FinalizerTableConfig, mtServiceability> FinalizerHashtable;
static FinalizerHashtable* _table = nullptr;
static const size_t DEFAULT_TABLE_SIZE = 2048;
// 2^24 is max size, like StringTable.
static const size_t MAX_SIZE = 24;
static volatile bool _has_work = false;

class FinalizerEntryLookupResult {
 private:
  FinalizerEntry* _result;
 public:
  FinalizerEntryLookupResult() : _result(nullptr) {}
  void operator()(FinalizerEntry* node) {
    assert(node != nullptr, "invariant");
    _result = node;
  }
  FinalizerEntry* result() const { return _result; }
};

class FinalizerEntryLookupGet {
 private:
  FinalizerEntry* _result;
 public:
  FinalizerEntryLookupGet() : _result(nullptr) {}
  void operator()(FinalizerEntry** node) {
    assert(node != nullptr, "invariant");
    _result = *node;
  }
  FinalizerEntry* result() const { return _result; }
};

static inline void set_has_work(bool value) {
  Atomic::store(&_has_work, value);
}

static inline bool has_work() {
  return Atomic::load(&_has_work);
}

static void request_resize() {
  if (!has_work()) {
    MutexLocker ml(Service_lock, Mutex::_no_safepoint_check_flag);
    if (!has_work()) {
      set_has_work(true);
      Service_lock->notify_all();
    }
  }
}

static FinalizerEntry* add_to_table_if_needed(const InstanceKlass* ik, Thread* thread) {
  FinalizerEntryLookup lookup(ik);
  FinalizerEntry* entry = nullptr;
  bool grow_hint = false;
  do {
    // We have looked up the entry once, proceed with insertion.
    entry = new FinalizerEntry(ik);
    if (_table->insert(thread, lookup, entry, &grow_hint)) {
      break;
    }
    // In case another thread did a concurrent add, return value already in the table.
    // This could fail if the entry got deleted concurrently, so loop back until success.
    FinalizerEntryLookupGet felg;
    if (_table->get(thread, lookup, felg, &grow_hint)) {
      entry = felg.result();
      break;
    }
  } while (true);
  if (grow_hint) {
    request_resize();
  }
  assert(entry != nullptr, "invariant");
  return entry;
}

static void do_table_concurrent_work(JavaThread* jt) {
  if (!_table->is_max_size_reached()) {
    FinalizerHashtable::GrowTask gt(_table);
    if (!gt.prepare(jt)) {
      return;
    }
    while (gt.do_task(jt)) {
      gt.pause(jt);
      {
        ThreadBlockInVM tbivm(jt);
      }
      gt.cont(jt);
    }
    gt.done(jt);
  }
  set_has_work(false);
}

bool FinalizerService::has_work() {
  return ::has_work();
}

void FinalizerService::do_concurrent_work(JavaThread* service_thread) {
  assert(service_thread != nullptr, "invariant");
  assert(has_work(), "invariant");
  do_table_concurrent_work(service_thread);
}

void FinalizerService::init() {
  assert(_table == nullptr, "invariant");
  const size_t start_size_log_2 = ceil_log2(DEFAULT_TABLE_SIZE);
  _table = new FinalizerHashtable(start_size_log_2, MAX_SIZE, FinalizerHashtable::DEFAULT_GROW_HINT);
}

static FinalizerEntry* lookup_entry(const InstanceKlass* ik, Thread* thread) {
  FinalizerEntryLookup lookup(ik);
  FinalizerEntryLookupGet felg;
  _table->get(thread, lookup, felg);
  return felg.result();
}

const FinalizerEntry* FinalizerService::lookup(const InstanceKlass* ik, Thread* thread) {
  assert(ik != nullptr, "invariant");
  assert(thread != nullptr, "invariant");
  assert(ik->has_finalizer(), "invariant");
  return lookup_entry(ik, thread);
}

// Add if not exist.
static FinalizerEntry* get_entry(const InstanceKlass* ik, Thread* thread) {
  assert(ik != nullptr, "invariant");
  assert(ik->has_finalizer(), "invariant");
  FinalizerEntry* const entry = lookup_entry(ik, thread);
  return entry != nullptr ? entry : add_to_table_if_needed(ik, thread);
}

static FinalizerEntry* get_entry(oop finalizee, Thread* thread) {
  assert(finalizee != nullptr, "invariant");
  assert(finalizee->is_instance(), "invariant");
  return get_entry(InstanceKlass::cast(finalizee->klass()), thread);
}

static void log_registered(oop finalizee, Thread* thread) {
  ResourceMark rm(thread);
  const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee);
  log_info(finalizer)("Registered object (" INTPTR_FORMAT ") of class %s as finalizable", identity_hash, finalizee->klass()->external_name());
}

void FinalizerService::on_register(oop finalizee, Thread* thread) {
  FinalizerEntry* const fe = get_entry(finalizee, thread);
  assert(fe != nullptr, "invariant");
  fe->on_register();
  if (log_is_enabled(Info, finalizer)) {
    log_registered(finalizee, thread);
  }
}

static void log_completed(oop finalizee, Thread* thread) {
  ResourceMark rm(thread);
  const intptr_t identity_hash = ObjectSynchronizer::FastHashCode(thread, finalizee);
  log_info(finalizer)("Finalizer was run for object (" INTPTR_FORMAT ") of class %s", identity_hash, finalizee->klass()->external_name());
}

void FinalizerService::on_complete(oop finalizee, JavaThread* finalizer_thread) {
  FinalizerEntry* const fe = get_entry(finalizee, finalizer_thread);
  assert(fe != nullptr, "invariant");
  fe->on_complete();
  if (log_is_enabled(Info, finalizer)) {
    log_completed(finalizee, finalizer_thread);
  }
}

class FinalizerScan : public StackObj {
 private:
  FinalizerEntryClosure* _closure;
 public:
  FinalizerScan(FinalizerEntryClosure* closure) : _closure(closure) {}
  bool operator()(FinalizerEntry** fe) {
    return _closure->do_entry(*fe);
  }
};

void FinalizerService::do_entries(FinalizerEntryClosure* closure, Thread* thread) {
  assert(closure != nullptr, "invariant");
  FinalizerScan scan(closure);
  _table->do_scan(thread, scan);
}

static bool remove_entry(const InstanceKlass* ik) {
  assert(ik != nullptr, "invariant");
  FinalizerEntryLookup lookup(ik);
  return _table->remove(Thread::current(), lookup);
}

static void on_unloading(Klass* klass) {
  assert(klass != nullptr, "invariant");
  if (!klass->is_instance_klass()) {
    return;
  }
  const InstanceKlass* const ik = InstanceKlass::cast(klass);
  if (ik->has_finalizer()) {
    remove_entry(ik);
  }
}

void FinalizerService::purge_unloaded() {
  assert_locked_or_safepoint(ClassLoaderDataGraph_lock);
  ClassLoaderDataGraph::classes_unloading_do(&on_unloading);
}

#endif // INCLUDE_MANAGEMENT

97%


¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

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.