mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-23 12:34:32 +02:00
7071653: JSR 292: call site change notification should be pushed not pulled
Reviewed-by: kvn, never, bdelsart
This commit is contained in:
parent
ac99f413d7
commit
134c40b4db
27 changed files with 906 additions and 526 deletions
|
@ -113,6 +113,11 @@ void Dependencies::assert_has_no_finalizable_subclasses(ciKlass* ctxk) {
|
|||
assert_common_1(no_finalizable_subclasses, ctxk);
|
||||
}
|
||||
|
||||
void Dependencies::assert_call_site_target_value(ciKlass* ctxk, ciCallSite* call_site, ciMethodHandle* method_handle) {
|
||||
check_ctxk(ctxk);
|
||||
assert_common_3(call_site_target_value, ctxk, call_site, method_handle);
|
||||
}
|
||||
|
||||
// Helper function. If we are adding a new dep. under ctxk2,
|
||||
// try to find an old dep. under a broader* ctxk1. If there is
|
||||
//
|
||||
|
@ -341,7 +346,8 @@ const char* Dependencies::_dep_name[TYPE_LIMIT] = {
|
|||
"unique_concrete_method",
|
||||
"abstract_with_exclusive_concrete_subtypes_2",
|
||||
"exclusive_concrete_methods_2",
|
||||
"no_finalizable_subclasses"
|
||||
"no_finalizable_subclasses",
|
||||
"call_site_target_value"
|
||||
};
|
||||
|
||||
int Dependencies::_dep_args[TYPE_LIMIT] = {
|
||||
|
@ -354,7 +360,8 @@ int Dependencies::_dep_args[TYPE_LIMIT] = {
|
|||
2, // unique_concrete_method ctxk, m
|
||||
3, // unique_concrete_subtypes_2 ctxk, k1, k2
|
||||
3, // unique_concrete_methods_2 ctxk, m1, m2
|
||||
1 // no_finalizable_subclasses ctxk
|
||||
1, // no_finalizable_subclasses ctxk
|
||||
3 // call_site_target_value ctxk, call_site, method_handle
|
||||
};
|
||||
|
||||
const char* Dependencies::dep_name(Dependencies::DepType dept) {
|
||||
|
@ -367,6 +374,13 @@ int Dependencies::dep_args(Dependencies::DepType dept) {
|
|||
return _dep_args[dept];
|
||||
}
|
||||
|
||||
void Dependencies::check_valid_dependency_type(DepType dept) {
|
||||
for (int deptv = (int) FIRST_TYPE; deptv < (int) TYPE_LIMIT; deptv++) {
|
||||
if (dept == ((DepType) deptv)) return;
|
||||
}
|
||||
ShouldNotReachHere();
|
||||
}
|
||||
|
||||
// for the sake of the compiler log, print out current dependencies:
|
||||
void Dependencies::log_all_dependencies() {
|
||||
if (log() == NULL) return;
|
||||
|
@ -800,11 +814,11 @@ class ClassHierarchyWalker {
|
|||
bool participants_hide_witnesses,
|
||||
bool top_level_call = true);
|
||||
// the spot-checking version:
|
||||
klassOop find_witness_in(DepChange& changes,
|
||||
klassOop find_witness_in(KlassDepChange& changes,
|
||||
klassOop context_type,
|
||||
bool participants_hide_witnesses);
|
||||
public:
|
||||
klassOop find_witness_subtype(klassOop context_type, DepChange* changes = NULL) {
|
||||
klassOop find_witness_subtype(klassOop context_type, KlassDepChange* changes = NULL) {
|
||||
assert(doing_subtype_search(), "must set up a subtype search");
|
||||
// When looking for unexpected concrete types,
|
||||
// do not look beneath expected ones.
|
||||
|
@ -817,7 +831,7 @@ class ClassHierarchyWalker {
|
|||
return find_witness_anywhere(context_type, participants_hide_witnesses);
|
||||
}
|
||||
}
|
||||
klassOop find_witness_definer(klassOop context_type, DepChange* changes = NULL) {
|
||||
klassOop find_witness_definer(klassOop context_type, KlassDepChange* changes = NULL) {
|
||||
assert(!doing_subtype_search(), "must set up a method definer search");
|
||||
// When looking for unexpected concrete methods,
|
||||
// look beneath expected ones, to see if there are overrides.
|
||||
|
@ -878,7 +892,7 @@ static bool count_find_witness_calls() {
|
|||
#endif //PRODUCT
|
||||
|
||||
|
||||
klassOop ClassHierarchyWalker::find_witness_in(DepChange& changes,
|
||||
klassOop ClassHierarchyWalker::find_witness_in(KlassDepChange& changes,
|
||||
klassOop context_type,
|
||||
bool participants_hide_witnesses) {
|
||||
assert(changes.involves_context(context_type), "irrelevant dependency");
|
||||
|
@ -1137,7 +1151,7 @@ klassOop Dependencies::check_leaf_type(klassOop ctxk) {
|
|||
// when dealing with the types of actual instances.
|
||||
klassOop Dependencies::check_abstract_with_unique_concrete_subtype(klassOop ctxk,
|
||||
klassOop conck,
|
||||
DepChange* changes) {
|
||||
KlassDepChange* changes) {
|
||||
ClassHierarchyWalker wf(conck);
|
||||
return wf.find_witness_subtype(ctxk, changes);
|
||||
}
|
||||
|
@ -1146,7 +1160,7 @@ klassOop Dependencies::check_abstract_with_unique_concrete_subtype(klassOop ctxk
|
|||
// instantiatable. This can allow the compiler to make some paths go
|
||||
// dead, if they are gated by a test of the type.
|
||||
klassOop Dependencies::check_abstract_with_no_concrete_subtype(klassOop ctxk,
|
||||
DepChange* changes) {
|
||||
KlassDepChange* changes) {
|
||||
// Find any concrete subtype, with no participants:
|
||||
ClassHierarchyWalker wf;
|
||||
return wf.find_witness_subtype(ctxk, changes);
|
||||
|
@ -1156,7 +1170,7 @@ klassOop Dependencies::check_abstract_with_no_concrete_subtype(klassOop ctxk,
|
|||
// If a concrete class has no concrete subtypes, it can always be
|
||||
// exactly typed. This allows the use of a cheaper type test.
|
||||
klassOop Dependencies::check_concrete_with_no_concrete_subtype(klassOop ctxk,
|
||||
DepChange* changes) {
|
||||
KlassDepChange* changes) {
|
||||
// Find any concrete subtype, with only the ctxk as participant:
|
||||
ClassHierarchyWalker wf(ctxk);
|
||||
return wf.find_witness_subtype(ctxk, changes);
|
||||
|
@ -1217,7 +1231,7 @@ klassOop Dependencies::check_abstract_with_exclusive_concrete_subtypes(
|
|||
klassOop ctxk,
|
||||
klassOop k1,
|
||||
klassOop k2,
|
||||
DepChange* changes) {
|
||||
KlassDepChange* changes) {
|
||||
ClassHierarchyWalker wf;
|
||||
wf.add_participant(k1);
|
||||
wf.add_participant(k2);
|
||||
|
@ -1278,7 +1292,7 @@ int Dependencies::find_exclusive_concrete_subtypes(klassOop ctxk,
|
|||
// If a class (or interface) has a unique concrete method uniqm, return NULL.
|
||||
// Otherwise, return a class that contains an interfering method.
|
||||
klassOop Dependencies::check_unique_concrete_method(klassOop ctxk, methodOop uniqm,
|
||||
DepChange* changes) {
|
||||
KlassDepChange* changes) {
|
||||
// Here is a missing optimization: If uniqm->is_final(),
|
||||
// we don't really need to search beneath it for overrides.
|
||||
// This is probably not important, since we don't use dependencies
|
||||
|
@ -1321,7 +1335,7 @@ methodOop Dependencies::find_unique_concrete_method(klassOop ctxk, methodOop m)
|
|||
klassOop Dependencies::check_exclusive_concrete_methods(klassOop ctxk,
|
||||
methodOop m1,
|
||||
methodOop m2,
|
||||
DepChange* changes) {
|
||||
KlassDepChange* changes) {
|
||||
ClassHierarchyWalker wf(m1);
|
||||
wf.add_participant(m1->method_holder());
|
||||
wf.add_participant(m2->method_holder());
|
||||
|
@ -1383,7 +1397,7 @@ int Dependencies::find_exclusive_concrete_methods(klassOop ctxk,
|
|||
}
|
||||
|
||||
|
||||
klassOop Dependencies::check_has_no_finalizable_subclasses(klassOop ctxk, DepChange* changes) {
|
||||
klassOop Dependencies::check_has_no_finalizable_subclasses(klassOop ctxk, KlassDepChange* changes) {
|
||||
Klass* search_at = ctxk->klass_part();
|
||||
if (changes != NULL)
|
||||
search_at = changes->new_type()->klass_part(); // just look at the new bit
|
||||
|
@ -1395,8 +1409,39 @@ klassOop Dependencies::check_has_no_finalizable_subclasses(klassOop ctxk, DepCha
|
|||
}
|
||||
|
||||
|
||||
klassOop Dependencies::DepStream::check_dependency_impl(DepChange* changes) {
|
||||
klassOop Dependencies::check_call_site_target_value(klassOop ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes) {
|
||||
assert(call_site ->is_a(SystemDictionary::CallSite_klass()), "sanity");
|
||||
assert(method_handle->is_a(SystemDictionary::MethodHandle_klass()), "sanity");
|
||||
if (changes == NULL) {
|
||||
// Validate all CallSites
|
||||
if (java_lang_invoke_CallSite::target(call_site) != method_handle)
|
||||
return ctxk; // assertion failed
|
||||
} else {
|
||||
// Validate the given CallSite
|
||||
if (call_site == changes->call_site() && java_lang_invoke_CallSite::target(call_site) != changes->method_handle()) {
|
||||
assert(method_handle != changes->method_handle(), "must be");
|
||||
return ctxk; // assertion failed
|
||||
}
|
||||
}
|
||||
assert(java_lang_invoke_CallSite::target(call_site) == method_handle, "should still be valid");
|
||||
return NULL; // assertion still valid
|
||||
}
|
||||
|
||||
|
||||
void Dependencies::DepStream::trace_and_log_witness(klassOop witness) {
|
||||
if (witness != NULL) {
|
||||
if (TraceDependencies) {
|
||||
print_dependency(witness, /*verbose=*/ true);
|
||||
}
|
||||
// The following is a no-op unless logging is enabled:
|
||||
log_dependency(witness);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
klassOop Dependencies::DepStream::check_klass_dependency(KlassDepChange* changes) {
|
||||
assert_locked_or_safepoint(Compile_lock);
|
||||
Dependencies::check_valid_dependency_type(type());
|
||||
|
||||
klassOop witness = NULL;
|
||||
switch (type()) {
|
||||
|
@ -1407,95 +1452,103 @@ klassOop Dependencies::DepStream::check_dependency_impl(DepChange* changes) {
|
|||
witness = check_leaf_type(context_type());
|
||||
break;
|
||||
case abstract_with_unique_concrete_subtype:
|
||||
witness = check_abstract_with_unique_concrete_subtype(context_type(),
|
||||
type_argument(1),
|
||||
changes);
|
||||
witness = check_abstract_with_unique_concrete_subtype(context_type(), type_argument(1), changes);
|
||||
break;
|
||||
case abstract_with_no_concrete_subtype:
|
||||
witness = check_abstract_with_no_concrete_subtype(context_type(),
|
||||
changes);
|
||||
witness = check_abstract_with_no_concrete_subtype(context_type(), changes);
|
||||
break;
|
||||
case concrete_with_no_concrete_subtype:
|
||||
witness = check_concrete_with_no_concrete_subtype(context_type(),
|
||||
changes);
|
||||
witness = check_concrete_with_no_concrete_subtype(context_type(), changes);
|
||||
break;
|
||||
case unique_concrete_method:
|
||||
witness = check_unique_concrete_method(context_type(),
|
||||
method_argument(1),
|
||||
changes);
|
||||
witness = check_unique_concrete_method(context_type(), method_argument(1), changes);
|
||||
break;
|
||||
case abstract_with_exclusive_concrete_subtypes_2:
|
||||
witness = check_abstract_with_exclusive_concrete_subtypes(context_type(),
|
||||
type_argument(1),
|
||||
type_argument(2),
|
||||
changes);
|
||||
witness = check_abstract_with_exclusive_concrete_subtypes(context_type(), type_argument(1), type_argument(2), changes);
|
||||
break;
|
||||
case exclusive_concrete_methods_2:
|
||||
witness = check_exclusive_concrete_methods(context_type(),
|
||||
method_argument(1),
|
||||
method_argument(2),
|
||||
changes);
|
||||
witness = check_exclusive_concrete_methods(context_type(), method_argument(1), method_argument(2), changes);
|
||||
break;
|
||||
case no_finalizable_subclasses:
|
||||
witness = check_has_no_finalizable_subclasses(context_type(),
|
||||
changes);
|
||||
witness = check_has_no_finalizable_subclasses(context_type(), changes);
|
||||
break;
|
||||
default:
|
||||
default:
|
||||
witness = NULL;
|
||||
ShouldNotReachHere();
|
||||
break;
|
||||
}
|
||||
if (witness != NULL) {
|
||||
if (TraceDependencies) {
|
||||
print_dependency(witness, /*verbose=*/ true);
|
||||
}
|
||||
// The following is a no-op unless logging is enabled:
|
||||
log_dependency(witness);
|
||||
trace_and_log_witness(witness);
|
||||
return witness;
|
||||
}
|
||||
|
||||
|
||||
klassOop Dependencies::DepStream::check_call_site_dependency(CallSiteDepChange* changes) {
|
||||
assert_locked_or_safepoint(Compile_lock);
|
||||
Dependencies::check_valid_dependency_type(type());
|
||||
|
||||
klassOop witness = NULL;
|
||||
switch (type()) {
|
||||
case call_site_target_value:
|
||||
witness = check_call_site_target_value(context_type(), argument(1), argument(2), changes);
|
||||
break;
|
||||
default:
|
||||
witness = NULL;
|
||||
break;
|
||||
}
|
||||
trace_and_log_witness(witness);
|
||||
return witness;
|
||||
}
|
||||
|
||||
|
||||
klassOop Dependencies::DepStream::spot_check_dependency_at(DepChange& changes) {
|
||||
if (!changes.involves_context(context_type()))
|
||||
// irrelevant dependency; skip it
|
||||
return NULL;
|
||||
// Handle klass dependency
|
||||
if (changes.is_klass_change() && changes.as_klass_change()->involves_context(context_type()))
|
||||
return check_klass_dependency(changes.as_klass_change());
|
||||
|
||||
return check_dependency_impl(&changes);
|
||||
// Handle CallSite dependency
|
||||
if (changes.is_call_site_change())
|
||||
return check_call_site_dependency(changes.as_call_site_change());
|
||||
|
||||
// irrelevant dependency; skip it
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void DepChange::initialize() {
|
||||
// entire transaction must be under this lock:
|
||||
assert_lock_strong(Compile_lock);
|
||||
|
||||
// Mark all dependee and all its superclasses
|
||||
// Mark transitive interfaces
|
||||
void DepChange::print() {
|
||||
int nsup = 0, nint = 0;
|
||||
for (ContextStream str(*this); str.next(); ) {
|
||||
klassOop d = str.klass();
|
||||
assert(!instanceKlass::cast(d)->is_marked_dependent(), "checking");
|
||||
instanceKlass::cast(d)->set_is_marked_dependent(true);
|
||||
klassOop k = str.klass();
|
||||
switch (str.change_type()) {
|
||||
case Change_new_type:
|
||||
tty->print_cr(" dependee = %s", instanceKlass::cast(k)->external_name());
|
||||
break;
|
||||
case Change_new_sub:
|
||||
if (!WizardMode) {
|
||||
++nsup;
|
||||
} else {
|
||||
tty->print_cr(" context super = %s", instanceKlass::cast(k)->external_name());
|
||||
}
|
||||
break;
|
||||
case Change_new_impl:
|
||||
if (!WizardMode) {
|
||||
++nint;
|
||||
} else {
|
||||
tty->print_cr(" context interface = %s", instanceKlass::cast(k)->external_name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (nsup + nint != 0) {
|
||||
tty->print_cr(" context supers = %d, interfaces = %d", nsup, nint);
|
||||
}
|
||||
}
|
||||
|
||||
DepChange::~DepChange() {
|
||||
// Unmark all dependee and all its superclasses
|
||||
// Unmark transitive interfaces
|
||||
for (ContextStream str(*this); str.next(); ) {
|
||||
klassOop d = str.klass();
|
||||
instanceKlass::cast(d)->set_is_marked_dependent(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool DepChange::involves_context(klassOop k) {
|
||||
if (k == NULL || !Klass::cast(k)->oop_is_instance()) {
|
||||
return false;
|
||||
}
|
||||
instanceKlass* ik = instanceKlass::cast(k);
|
||||
bool is_contained = ik->is_marked_dependent();
|
||||
assert(is_contained == Klass::cast(new_type())->is_subtype_of(k),
|
||||
"correct marking of potential context types");
|
||||
return is_contained;
|
||||
void DepChange::ContextStream::start() {
|
||||
klassOop new_type = _changes.is_klass_change() ? _changes.as_klass_change()->new_type() : (klassOop) NULL;
|
||||
_change_type = (new_type == NULL ? NO_CHANGE : Start_Klass);
|
||||
_klass = new_type;
|
||||
_ti_base = NULL;
|
||||
_ti_index = 0;
|
||||
_ti_limit = 0;
|
||||
}
|
||||
|
||||
bool DepChange::ContextStream::next() {
|
||||
|
@ -1534,35 +1587,39 @@ bool DepChange::ContextStream::next() {
|
|||
return false;
|
||||
}
|
||||
|
||||
void DepChange::print() {
|
||||
int nsup = 0, nint = 0;
|
||||
void KlassDepChange::initialize() {
|
||||
// entire transaction must be under this lock:
|
||||
assert_lock_strong(Compile_lock);
|
||||
|
||||
// Mark all dependee and all its superclasses
|
||||
// Mark transitive interfaces
|
||||
for (ContextStream str(*this); str.next(); ) {
|
||||
klassOop k = str.klass();
|
||||
switch (str.change_type()) {
|
||||
case Change_new_type:
|
||||
tty->print_cr(" dependee = %s", instanceKlass::cast(k)->external_name());
|
||||
break;
|
||||
case Change_new_sub:
|
||||
if (!WizardMode) {
|
||||
++nsup;
|
||||
} else {
|
||||
tty->print_cr(" context super = %s", instanceKlass::cast(k)->external_name());
|
||||
}
|
||||
break;
|
||||
case Change_new_impl:
|
||||
if (!WizardMode) {
|
||||
++nint;
|
||||
} else {
|
||||
tty->print_cr(" context interface = %s", instanceKlass::cast(k)->external_name());
|
||||
}
|
||||
break;
|
||||
}
|
||||
klassOop d = str.klass();
|
||||
assert(!instanceKlass::cast(d)->is_marked_dependent(), "checking");
|
||||
instanceKlass::cast(d)->set_is_marked_dependent(true);
|
||||
}
|
||||
if (nsup + nint != 0) {
|
||||
tty->print_cr(" context supers = %d, interfaces = %d", nsup, nint);
|
||||
}
|
||||
|
||||
KlassDepChange::~KlassDepChange() {
|
||||
// Unmark all dependee and all its superclasses
|
||||
// Unmark transitive interfaces
|
||||
for (ContextStream str(*this); str.next(); ) {
|
||||
klassOop d = str.klass();
|
||||
instanceKlass::cast(d)->set_is_marked_dependent(false);
|
||||
}
|
||||
}
|
||||
|
||||
bool KlassDepChange::involves_context(klassOop k) {
|
||||
if (k == NULL || !Klass::cast(k)->oop_is_instance()) {
|
||||
return false;
|
||||
}
|
||||
instanceKlass* ik = instanceKlass::cast(k);
|
||||
bool is_contained = ik->is_marked_dependent();
|
||||
assert(is_contained == Klass::cast(new_type())->is_subtype_of(k),
|
||||
"correct marking of potential context types");
|
||||
return is_contained;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void Dependencies::print_statistics() {
|
||||
if (deps_find_witness_print != 0) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2011, 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
|
||||
|
@ -25,18 +25,21 @@
|
|||
#ifndef SHARE_VM_CODE_DEPENDENCIES_HPP
|
||||
#define SHARE_VM_CODE_DEPENDENCIES_HPP
|
||||
|
||||
#include "ci/ciCallSite.hpp"
|
||||
#include "ci/ciKlass.hpp"
|
||||
#include "ci/ciMethodHandle.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "code/compressedStream.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "utilities/growableArray.hpp"
|
||||
|
||||
//** Dependencies represent assertions (approximate invariants) within
|
||||
// the class hierarchy. An example is an assertion that a given
|
||||
// method is not overridden; another example is that a type has only
|
||||
// one concrete subtype. Compiled code which relies on such
|
||||
// assertions must be discarded if they are overturned by changes in
|
||||
// the class hierarchy. We can think of these assertions as
|
||||
// approximate invariants, because we expect them to be overturned
|
||||
// the runtime system, e.g. class hierarchy changes. An example is an
|
||||
// assertion that a given method is not overridden; another example is
|
||||
// that a type has only one concrete subtype. Compiled code which
|
||||
// relies on such assertions must be discarded if they are overturned
|
||||
// by changes in the runtime system. We can think of these assertions
|
||||
// as approximate invariants, because we expect them to be overturned
|
||||
// very infrequently. We are willing to perform expensive recovery
|
||||
// operations when they are overturned. The benefit, of course, is
|
||||
// performing optimistic optimizations (!) on the object code.
|
||||
|
@ -52,6 +55,8 @@ class OopRecorder;
|
|||
class xmlStream;
|
||||
class CompileLog;
|
||||
class DepChange;
|
||||
class KlassDepChange;
|
||||
class CallSiteDepChange;
|
||||
class No_Safepoint_Verifier;
|
||||
|
||||
class Dependencies: public ResourceObj {
|
||||
|
@ -152,6 +157,9 @@ class Dependencies: public ResourceObj {
|
|||
// subclasses require finalization registration.
|
||||
no_finalizable_subclasses,
|
||||
|
||||
// This dependency asserts when the CallSite.target value changed.
|
||||
call_site_target_value,
|
||||
|
||||
TYPE_LIMIT
|
||||
};
|
||||
enum {
|
||||
|
@ -179,6 +187,7 @@ class Dependencies: public ResourceObj {
|
|||
static int dep_context_arg(DepType dept) {
|
||||
return dept_in_mask(dept, ctxk_types)? 0: -1;
|
||||
}
|
||||
static void check_valid_dependency_type(DepType dept);
|
||||
|
||||
private:
|
||||
// State for writing a new set of dependencies:
|
||||
|
@ -255,6 +264,7 @@ class Dependencies: public ResourceObj {
|
|||
void assert_abstract_with_exclusive_concrete_subtypes(ciKlass* ctxk, ciKlass* k1, ciKlass* k2);
|
||||
void assert_exclusive_concrete_methods(ciKlass* ctxk, ciMethod* m1, ciMethod* m2);
|
||||
void assert_has_no_finalizable_subclasses(ciKlass* ctxk);
|
||||
void assert_call_site_target_value(ciKlass* ctxk, ciCallSite* call_site, ciMethodHandle* method_handle);
|
||||
|
||||
// Define whether a given method or type is concrete.
|
||||
// These methods define the term "concrete" as used in this module.
|
||||
|
@ -296,19 +306,19 @@ class Dependencies: public ResourceObj {
|
|||
static klassOop check_evol_method(methodOop m);
|
||||
static klassOop check_leaf_type(klassOop ctxk);
|
||||
static klassOop check_abstract_with_unique_concrete_subtype(klassOop ctxk, klassOop conck,
|
||||
DepChange* changes = NULL);
|
||||
KlassDepChange* changes = NULL);
|
||||
static klassOop check_abstract_with_no_concrete_subtype(klassOop ctxk,
|
||||
DepChange* changes = NULL);
|
||||
KlassDepChange* changes = NULL);
|
||||
static klassOop check_concrete_with_no_concrete_subtype(klassOop ctxk,
|
||||
DepChange* changes = NULL);
|
||||
KlassDepChange* changes = NULL);
|
||||
static klassOop check_unique_concrete_method(klassOop ctxk, methodOop uniqm,
|
||||
DepChange* changes = NULL);
|
||||
KlassDepChange* changes = NULL);
|
||||
static klassOop check_abstract_with_exclusive_concrete_subtypes(klassOop ctxk, klassOop k1, klassOop k2,
|
||||
DepChange* changes = NULL);
|
||||
KlassDepChange* changes = NULL);
|
||||
static klassOop check_exclusive_concrete_methods(klassOop ctxk, methodOop m1, methodOop m2,
|
||||
DepChange* changes = NULL);
|
||||
static klassOop check_has_no_finalizable_subclasses(klassOop ctxk,
|
||||
DepChange* changes = NULL);
|
||||
KlassDepChange* changes = NULL);
|
||||
static klassOop check_has_no_finalizable_subclasses(klassOop ctxk, KlassDepChange* changes = NULL);
|
||||
static klassOop check_call_site_target_value(klassOop ctxk, oop call_site, oop method_handle, CallSiteDepChange* changes = NULL);
|
||||
// A returned klassOop is NULL if the dependency assertion is still
|
||||
// valid. A non-NULL klassOop is a 'witness' to the assertion
|
||||
// failure, a point in the class hierarchy where the assertion has
|
||||
|
@ -415,7 +425,10 @@ class Dependencies: public ResourceObj {
|
|||
inline oop recorded_oop_at(int i);
|
||||
// => _code? _code->oop_at(i): *_deps->_oop_recorder->handle_at(i)
|
||||
|
||||
klassOop check_dependency_impl(DepChange* changes);
|
||||
klassOop check_klass_dependency(KlassDepChange* changes);
|
||||
klassOop check_call_site_dependency(CallSiteDepChange* changes);
|
||||
|
||||
void trace_and_log_witness(klassOop witness);
|
||||
|
||||
public:
|
||||
DepStream(Dependencies* deps)
|
||||
|
@ -453,10 +466,13 @@ class Dependencies: public ResourceObj {
|
|||
return (klassOop) x;
|
||||
}
|
||||
|
||||
// The point of the whole exercise: Is this dep is still OK?
|
||||
// The point of the whole exercise: Is this dep still OK?
|
||||
klassOop check_dependency() {
|
||||
return check_dependency_impl(NULL);
|
||||
klassOop result = check_klass_dependency(NULL);
|
||||
if (result != NULL) return result;
|
||||
return check_call_site_dependency(NULL);
|
||||
}
|
||||
|
||||
// A lighter version: Checks only around recent changes in a class
|
||||
// hierarchy. (See Universe::flush_dependents_on.)
|
||||
klassOop spot_check_dependency_at(DepChange& changes);
|
||||
|
@ -472,12 +488,26 @@ class Dependencies: public ResourceObj {
|
|||
static void print_statistics() PRODUCT_RETURN;
|
||||
};
|
||||
|
||||
// A class hierarchy change coming through the VM (under the Compile_lock).
|
||||
// The change is structured as a single new type with any number of supers
|
||||
// and implemented interface types. Other than the new type, any of the
|
||||
// super types can be context types for a relevant dependency, which the
|
||||
// new type could invalidate.
|
||||
|
||||
// Every particular DepChange is a sub-class of this class.
|
||||
class DepChange : public StackObj {
|
||||
public:
|
||||
// What kind of DepChange is this?
|
||||
virtual bool is_klass_change() const { return false; }
|
||||
virtual bool is_call_site_change() const { return false; }
|
||||
|
||||
// Subclass casting with assertions.
|
||||
KlassDepChange* as_klass_change() {
|
||||
assert(is_klass_change(), "bad cast");
|
||||
return (KlassDepChange*) this;
|
||||
}
|
||||
CallSiteDepChange* as_call_site_change() {
|
||||
assert(is_call_site_change(), "bad cast");
|
||||
return (CallSiteDepChange*) this;
|
||||
}
|
||||
|
||||
void print();
|
||||
|
||||
public:
|
||||
enum ChangeType {
|
||||
NO_CHANGE = 0, // an uninvolved klass
|
||||
|
@ -488,28 +518,6 @@ class DepChange : public StackObj {
|
|||
Start_Klass = CHANGE_LIMIT // internal indicator for ContextStream
|
||||
};
|
||||
|
||||
private:
|
||||
// each change set is rooted in exactly one new type (at present):
|
||||
KlassHandle _new_type;
|
||||
|
||||
void initialize();
|
||||
|
||||
public:
|
||||
// notes the new type, marks it and all its super-types
|
||||
DepChange(KlassHandle new_type)
|
||||
: _new_type(new_type)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
// cleans up the marks
|
||||
~DepChange();
|
||||
|
||||
klassOop new_type() { return _new_type(); }
|
||||
|
||||
// involves_context(k) is true if k is new_type or any of the super types
|
||||
bool involves_context(klassOop k);
|
||||
|
||||
// Usage:
|
||||
// for (DepChange::ContextStream str(changes); str.next(); ) {
|
||||
// klassOop k = str.klass();
|
||||
|
@ -530,14 +538,7 @@ class DepChange : public StackObj {
|
|||
int _ti_limit;
|
||||
|
||||
// start at the beginning:
|
||||
void start() {
|
||||
klassOop new_type = _changes.new_type();
|
||||
_change_type = (new_type == NULL ? NO_CHANGE: Start_Klass);
|
||||
_klass = new_type;
|
||||
_ti_base = NULL;
|
||||
_ti_index = 0;
|
||||
_ti_limit = 0;
|
||||
}
|
||||
void start();
|
||||
|
||||
public:
|
||||
ContextStream(DepChange& changes)
|
||||
|
@ -555,8 +556,62 @@ class DepChange : public StackObj {
|
|||
klassOop klass() { return _klass; }
|
||||
};
|
||||
friend class DepChange::ContextStream;
|
||||
};
|
||||
|
||||
void print();
|
||||
|
||||
// A class hierarchy change coming through the VM (under the Compile_lock).
|
||||
// The change is structured as a single new type with any number of supers
|
||||
// and implemented interface types. Other than the new type, any of the
|
||||
// super types can be context types for a relevant dependency, which the
|
||||
// new type could invalidate.
|
||||
class KlassDepChange : public DepChange {
|
||||
private:
|
||||
// each change set is rooted in exactly one new type (at present):
|
||||
KlassHandle _new_type;
|
||||
|
||||
void initialize();
|
||||
|
||||
public:
|
||||
// notes the new type, marks it and all its super-types
|
||||
KlassDepChange(KlassHandle new_type)
|
||||
: _new_type(new_type)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
|
||||
// cleans up the marks
|
||||
~KlassDepChange();
|
||||
|
||||
// What kind of DepChange is this?
|
||||
virtual bool is_klass_change() const { return true; }
|
||||
|
||||
klassOop new_type() { return _new_type(); }
|
||||
|
||||
// involves_context(k) is true if k is new_type or any of the super types
|
||||
bool involves_context(klassOop k);
|
||||
};
|
||||
|
||||
|
||||
// A CallSite has changed its target.
|
||||
class CallSiteDepChange : public DepChange {
|
||||
private:
|
||||
Handle _call_site;
|
||||
Handle _method_handle;
|
||||
|
||||
public:
|
||||
CallSiteDepChange(Handle call_site, Handle method_handle)
|
||||
: _call_site(call_site),
|
||||
_method_handle(method_handle)
|
||||
{
|
||||
assert(_call_site() ->is_a(SystemDictionary::CallSite_klass()), "must be");
|
||||
assert(_method_handle()->is_a(SystemDictionary::MethodHandle_klass()), "must be");
|
||||
}
|
||||
|
||||
// What kind of DepChange is this?
|
||||
virtual bool is_call_site_change() const { return true; }
|
||||
|
||||
oop call_site() const { return _call_site(); }
|
||||
oop method_handle() const { return _method_handle(); }
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_CODE_DEPENDENCIES_HPP
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
#include "precompiled.hpp"
|
||||
#include "code/codeCache.hpp"
|
||||
#include "code/compiledIC.hpp"
|
||||
#include "code/dependencies.hpp"
|
||||
#include "code/nmethod.hpp"
|
||||
#include "code/scopeDesc.hpp"
|
||||
#include "compiler/abstractCompiler.hpp"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue