dependencies.cpp revision 2062
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* 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 "ci/ciArrayKlass.hpp"
#include "ci/ciKlass.hpp"
#include "ci/ciMethod.hpp"
#include "code/dependencies.hpp"
#include "compiler/compileLog.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/handles.inline.hpp"
#ifdef ASSERT
static bool must_be_in_vm() {
if (thread->is_Java_thread())
else
return true; //something like this: thread->is_VM_thread();
}
#endif //ASSERT
for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) {
}
}
}
if (ctxk->is_array_klass()) {
// As a special case, support this assertion on an array type,
// which reduces to an assertion on its element type.
// Note that this cannot be done with assertions that
// relate to concreteness or abstractness.
//if (ctxk->is_final()) return; // Ex: String[][]
}
}
}
}
}
}
void Dependencies::assert_abstract_with_exclusive_concrete_subtypes(ciKlass* ctxk, ciKlass* k1, ciKlass* k2) {
}
}
}
// Helper function. If we are adding a new dep. under ctxk2,
// try to find an old dep. under a broader* ctxk1. If there is
//
return true; // success, and no need to change
// new context class fully subsumes previous one
return true;
} else {
return false;
}
}
log_dependency(dept, x);
// see if the same (or a similar) dep is already recorded
if (note_dep_seen(dept, x)) {
} else {
}
}
// see if the same (or a similar) dep is already recorded
if (note_dep_seen(dept, x)) {
// look in this bucket for redundant assertions
const int stride = 2;
if (x == x1) { // same subject; check the context
return;
}
}
}
}
// append the assertion in the correct bucket:
}
// try to normalize an unordered pair:
bool swap = false;
switch (dept) {
break;
break;
}
// see if the same (or a similar) dep is already recorded
// look in this bucket for redundant assertions
const int stride = 3;
return;
}
}
}
}
// append the assertion in the correct bucket:
}
/// Support for encoding dependencies into an nmethod:
size_in_bytes() / sizeof(HeapWord));
}
for (int i = 0; i < narg; i++) {
}
return 0;
}
void Dependencies::sort_all_deps() {
default: ShouldNotReachHere();
}
}
}
}
return est_size;
}
switch (dept) {
return x->as_klass();
case unique_concrete_method:
}
return NULL; // let NULL be NULL
}
switch (dept) {
return (klassOop) x;
case unique_concrete_method:
return ((methodOop)x)->method_holder();
}
return NULL; // let NULL be NULL
}
void Dependencies::encode_content_bytes() {
// cast is safe, no deps can overflow INT_MAX
int skipj = -1;
}
}
for (int j = 0; j < stride; j++) {
if (j == skipj) continue;
}
}
}
// write a sentinel byte to mark the end
// round it out to a word boundary
}
// check whether the dept byte encoding really works
}
"end_marker",
"evol_method",
"leaf_type",
"abstract_with_unique_concrete_subtype",
"abstract_with_no_concrete_subtype",
"concrete_with_no_concrete_subtype",
"unique_concrete_method",
"abstract_with_exclusive_concrete_subtypes_2",
"exclusive_concrete_methods_2",
"no_finalizable_subclasses"
};
-1,// end_marker
1, // evol_method m
1, // leaf_type ctxk
2, // abstract_with_unique_concrete_subtype ctxk, k
1, // abstract_with_no_concrete_subtype ctxk
1, // concrete_with_no_concrete_subtype ctxk
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
};
}
}
// for the sake of the compiler log, print out current dependencies:
void Dependencies::log_all_dependencies() {
for (int j = 0; j < stride; j++) {
// flush out the identities before printing
}
}
}
}
return;
}
for (int j = 0; j < nargs; j++) {
}
}
int argids[max_arg_count];
int j;
for (j = 0; j < nargs; j++) {
}
} else {
}
if (ctxkj >= 0) {
}
// write remaining arguments, if any.
for (j = 0; j < nargs; j++) {
if (j == ctxkj) continue; // already logged
if (j == 1) {
} else {
}
}
}
}
} else {
}
if (ctxkj >= 0) {
}
// write remaining arguments, if any.
for (int j = 0; j < nargs; j++) {
if (j == ctxkj) continue; // already logged
if (j == 1) {
} else {
}
}
}
}
// print arguments
for (int j = 0; j < nargs; j++) {
bool put_star = false;
const char* what;
if (j == ctxkj) {
what = "context";
what = "method ";
what = "class ";
} else {
what = "object ";
}
else
arg->print_value();
}
}
}
int nargs = argument_count();
for (int j = 0; j < nargs; j++) {
}
} else {
}
}
int nargs = argument_count();
for (int j = 0; j < nargs; j++) {
}
if (verbose) {
}
}
}
/// Dependency stream support (decodes dependencies from an nmethod):
#ifdef ASSERT
}
#endif //ASSERT
&& _code->dependencies_size() == 0) {
// Method has no dependencies at all.
return false;
}
if (code_byte == end_marker) {
return false;
} else {
"bad dependency type tag");
int skipj = -1;
if (ctxk_bit != 0) {
skipj = 0; // currently the only context argument is at zero
}
for (int j = 0; j < stride; j++) {
}
return true;
}
}
}
return recorded_oop_at(argument_index(i));
}
if (ctxkj < 0) {
return NULL; // for example, evol_method
} else {
if (k != NULL) { // context type was not compressed away
return (klassOop) k;
} else { // recompute "default" context type
}
}
}
/// Checking dependencies:
// This hierarchy walker inspects subtypes of a given type,
// trying to find a "bad" class which breaks a dependency.
// Such a class is called a "witness" to the broken dependency.
// While searching around, we ignore "participants", which
// are already known to the dependency.
class ClassHierarchyWalker {
public:
enum { PARTICIPANT_LIMIT = 3 };
private:
// optional method descriptor to check for:
// special classes which are not allowed to be witnesses:
int _num_participants;
// cache of method lookups
// if non-zero, tells how many witnesses to convert to participants
int _record_witnesses;
_record_witnesses = 0;
_participants[0] = participant;
_found_methods[0] = NULL;
_num_participants = 0;
if (participant != NULL) {
// Terminating NULL.
_num_participants = 1;
}
}
void initialize_from_method(methodOop m) {
_signature = m->signature();
}
public:
// as friendly participants.
}
}
_signature = NULL;
}
// This is common code for two searches: One for concrete subtypes,
// the other for concrete method implementations and overrides.
bool doing_subtype_search() {
}
int num_participants() { return _num_participants; }
klassOop participant(int n) {
return _participants[n];
}
// Note: If n==num_participants, returns NULL.
methodOop found_method(int n) {
return fm;
}
#ifdef ASSERT
// Assert that m is inherited into ctxk, without intervening overrides.
// (May return true even if this is not true, in corner cases where we punt.)
if (m->method_holder() == ctxk)
return true; // Quick win.
if (m->is_private())
return false; // Quick lose. Should not happen.
if (!(m->is_public() || m->is_protected()))
// The override story is complex when packages get involved.
return true; // Must punt the assertion to true.
// It might be an abstract interface method, devoid of mirandas.
m->signature());
}
if (lm == m)
// Method m is inherited into ctxk.
return true;
// Method is [package-]private, so the override story is complex.
return true; // Must punt the assertion to true.
&& !Dependencies::is_concrete_method(m)
// Method m is overridden by lm, but both are non-concrete.
return true;
}
}
return false;
}
#endif
int np = _num_participants++;
}
void record_witnesses(int add) {
}
bool is_witness(klassOop k) {
if (doing_subtype_search()) {
return Dependencies::is_concrete_klass(k);
} else {
// Note: If add_participant(k) is called,
// the method m will already be memoized for it.
return true;
}
}
bool is_participant(klassOop k) {
if (k == _participants[0]) {
return true;
} else if (_num_participants <= 1) {
return false;
} else {
}
}
if (_record_witnesses == 0) {
return false;
} else {
return true;
}
}
for (int i = 0; ; i++) {
if (y == NULL) break;
if (y == x) return true;
}
return false; // not in list
}
private:
// the actual search method:
bool top_level_call = true);
// the spot-checking version:
bool participants_hide_witnesses);
public:
// When looking for unexpected concrete types,
// do not look beneath expected ones.
const bool participants_hide_witnesses = true;
// CX > CC > C' is OK, even if C' is new.
// CX > { CC, C' } is not OK if C' is new, and C' is the witness.
} else {
}
}
// When looking for unexpected concrete methods,
// look beneath expected ones, to see if there are overrides.
const bool participants_hide_witnesses = true;
// CX.m > CC.m > C'.m is not OK, if C'.m is new, and C' is the witness.
} else {
}
}
};
#ifndef PRODUCT
static int deps_find_witness_calls = 0;
static int deps_find_witness_steps = 0;
static int deps_find_witness_recursions = 0;
static int deps_find_witness_singles = 0;
static int deps_find_witness_print = 0; // set to -1 to force a final print
static bool count_find_witness_calls() {
if (TraceDependencies || LogCompilation) {
bool final_stats = (pcount == 0);
if (VerifyDependencies && initial_call) {
}
if (occasional_print || final_stats) {
// Every now and then dump a little info about dependency searching.
}
"calls=%d, steps=%d (avg=%.1f), recursions=%d, singles=%d",
(double)deps_find_witness_steps / deps_find_witness_calls,
}
}
return true;
}
return false;
}
#else
#define count_find_witness_calls() (0)
#endif //PRODUCT
bool participants_hide_witnesses) {
// Current thread must be in VM (not native mode, as in CI):
// Must not move the class hierarchy during this check:
if (nof_impls > 1) {
// Avoid this case: *I.m > { A.m, C }; B.m > C
// %%% Until this is fixed more systematically, bail out.
// See corresponding comment in find_witness_anywhere.
return context_type;
}
if (participants_hide_witnesses) {
// If the new type is a subtype of a participant, we are done.
for (int i = 0; i < num_participants(); i++) {
"correct marking of participants, b/c new_type is unique");
// new guy is protected from this check by previous participant
return NULL;
}
}
}
if (is_witness(new_type) &&
!ignore_witness(new_type)) {
return new_type;
}
return NULL;
}
// Walk hierarchy under a context type, looking for unexpected types.
// Do not report participant types, and recursively walk beneath
// them only if participants_hide_witnesses is false.
// If top_level_call is false, skip testing the context type,
// because the caller has already considered it.
bool top_level_call) {
// Current thread must be in VM (not native mode, as in CI):
// Must not move the class hierarchy during this check:
bool do_counts = count_find_witness_calls();
// Check the root of the sub-hierarchy first.
if (top_level_call) {
if (do_counts) {
}
if (is_participant(context_type)) {
if (participants_hide_witnesses) return NULL;
// else fall through to search loop...
// The context is an abstract class or interface, to start with.
return context_type;
}
}
// Now we must check each implementor and each subclass.
// Use a short worklist to avoid blowing the stack.
// Each worklist entry is a *chain* of subklass siblings to process.
int chaini = 0; // index into worklist
#define ADD_SUBCLASS_CHAIN(k) { \
// Look for non-abstract subclasses.
// (Note: Interfaces do not have subclasses.)
// If it is an interface, search its direct implementors.
// (Their subclasses are additional indirect implementors.
// See instanceKlass::add_implementor.)
// (Note: nof_implementors is always zero for non-interfaces.)
if (nof_impls > 1) {
// Avoid this case: *I.m > { A.m, C }; B.m > C
// Here, I.m has 2 concrete implementations, but m appears unique
// as A.m, because the search misses B.m when checking C.
// The inherited method B.m was getting missed by the walker
// when interface 'I' was the starting point.
// %%% Until this is fixed more systematically, bail out.
// (Old CHA had the same limitation.)
return context_type;
}
for (int i = 0; i < nof_impls; i++) {
// implementors array overflowed => no exact info.
return context_type; // report an inexact witness to this sad affair
}
if (do_counts)
{ NOT_PRODUCT(deps_find_witness_steps++); }
if (is_participant(impl)) {
if (participants_hide_witnesses) continue;
// else fall through to process this guy's subclasses
return impl;
}
}
// Recursively process each non-trivial sibling chain.
while (chaini > 0) {
if (is_participant(sub)) {
if (participants_hide_witnesses) continue;
// else fall through to process this guy's subclasses
return sub;
}
// Fast path. (Partially disabled if VerifyDependencies.)
} else {
// Worklist overflow. Do a recursive call. Should be rare.
// The recursive call will have its own worklist, of course.
// (Note that sub has already been tested, so that there is
// no need for the recursive call to re-test. That's handy,
// since the recursive call sees sub as the context_type.)
/*top_level_call=*/ false);
}
}
}
// No witness found. The dependency remains unbroken.
return NULL;
}
// %%% We could treat classes which are concrete but
// have not yet been instantiated as virtually abstract.
// This would require a deoptimization barrier on first instantiation.
//if (k->is_not_instantiated()) return false;
return true;
}
if (m->is_abstract()) return false;
// %%% We could treat unexecuted methods as virtually abstract also.
// This would require a deoptimization barrier on first execution.
return !m->is_abstract();
}
if (k->is_interface()) return NULL;
if (k->has_finalizer()) return k;
k = k->subklass();
while (k != NULL) {
k = k->next_sibling();
}
return NULL;
}
if (k->is_abstract()) return false;
// We could return also false if k does not yet appear to be
// instantiated, if the VM version supports this distinction also.
//if (k->is_not_instantiated()) return false;
return true;
}
// Statics are irrelevant to virtual call sites.
if (m->is_static()) return false;
// We could return also false if m does not yet appear to be
// executed, if the VM version supports this distinction also.
return !m->is_abstract();
}
return k->has_finalizable_subclass();
}
// Any use of the contents (bytecodes) of a method must be
// marked by an "evol_method" dependency, if those contents
// can change. (Note: A method is always dependent on itself.)
// Did somebody do a JVMTI RedefineClasses while our backs were turned?
// Or is there a now a breakpoint?
// (Assumes compiled code cannot handle bkpts; change if UseFastBreakpoints.)
if (m->is_old()
|| m->number_of_breakpoints() > 0) {
return m->method_holder();
} else {
return NULL;
}
}
// This is a strong assertion: It is that the given type
// has no subtypes whatever. It is most useful for
// optimizing checks on reflected types or on array types.
// (Checks on types which are derived from real instances
// can be optimized more strongly than this, because we
// know that the checked type comes from a concrete type,
// and therefore we can disregard abstract types.)
return sub->as_klassOop();
} else if (ctx->nof_implementors() != 0) {
// if it is an interface, it must be unimplemented
// (if it is not an interface, nof_implementors is always zero)
} else {
return NULL;
}
}
// Test the assertion that conck is the only concrete subtype* of ctxk.
// The type conck itself is allowed to have have further concrete subtypes.
// This allows the compiler to narrow occurrences of ctxk by conck,
// when dealing with the types of actual instances.
}
// If a non-concrete class has no concrete subtypes, it is not (yet)
// instantiatable. This can allow the compiler to make some paths go
// dead, if they are gated by a test of the type.
// Find any concrete subtype, with no participants:
}
// If a concrete class has no concrete subtypes, it can always be
// exactly typed. This allows the use of a cheaper type test.
// Find any concrete subtype, with only the ctxk as participant:
}
// Find the unique concrete proper subtype of ctxk, or NULL if there
// is more than one concrete proper subtype. If there are no concrete
// proper subtypes, return ctxk itself, whether it is concrete or not.
// The returned subtype is allowed to have have further concrete subtypes.
// That is, return CC1 for CX > CC1 > CC2, but NULL for CX > { CC1, CC2 }.
#ifndef PRODUCT
// Make sure the dependency mechanism will pass this discovery:
if (VerifyDependencies) {
// Turn off dependency tracing while actually testing deps.
(void *)check_abstract_with_no_concrete_subtype(ctxk),
"verify dep.");
} else {
(void *)check_concrete_with_no_concrete_subtype(ctxk),
"verify dep.");
}
}
#endif //PRODUCT
return ctxk; // Return ctxk as a flag for "no subtypes".
} else {
#ifndef PRODUCT
// Make sure the dependency mechanism will pass this discovery:
if (VerifyDependencies) {
// Turn off dependency tracing while actually testing deps.
"verify dep.");
}
}
#endif //PRODUCT
return conck;
}
}
// Test the assertion that the k[12] are the only concrete subtypes of ctxk,
// except possibly for further subtypes of k[12] themselves.
// The context type must be abstract. The types k1 and k2 are themselves
// allowed to have further concrete subtypes.
}
// Search ctxk for concrete implementations. If there are klen or fewer,
// pack them into the given array and return the number.
// Otherwise, return -1, meaning the given array would overflow.
// (Note that a return of 0 means there are exactly no concrete subtypes.)
// In this search, if ctxk is concrete, it will be reported alone.
// For any type CC reported, no proper subtypes of CC will be reported.
int klen,
// Pack the result array with the good news.
for (int i = 0; i < num; i++)
#ifndef PRODUCT
// Make sure the dependency mechanism will pass this discovery:
if (VerifyDependencies) {
// Turn off dependency tracing while actually testing deps.
case -1: // ctxk was itself concrete
break;
case 0:
"verify dep.");
break;
case 1:
"verify dep.");
break;
case 2:
karray[0],
karray[1]),
"verify dep.");
break;
default:
ShouldNotReachHere(); // klen > 2 yet supported
}
}
#endif //PRODUCT
return num;
}
// If a class (or interface) has a unique concrete method uniqm, return NULL.
// Otherwise, return a class that contains an interfering method.
// 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
// to track final methods. (They can't be "definalized".)
}
// Find the set of all non-abstract methods under ctxk that match m.
// (The method m must be defined or inherited in ctxk.)
// Include m itself in the set, unless it is abstract.
// If this set has exactly one element, return that element.
if (Dependencies::is_concrete_method(m)) {
// It turns out that m was always the only implementation.
fm = m;
} else if (fm != m) {
// Two conflicting implementations after all.
// (This can happen if m is inherited into ctxk and fm overrides it.)
return NULL;
}
}
#ifndef PRODUCT
// Make sure the dependency mechanism will pass this discovery:
"verify dep.");
}
#endif //PRODUCT
return fm;
}
}
// Find the set of all non-abstract methods under ctxk that match m[0].
// (The method m[0] must be defined or inherited in ctxk.)
// Include m itself in the set, unless it is abstract.
// Fill the given array m[0..(mlen-1)] with this set, and return the length.
// (The length may be zero if no concrete methods are found anywhere.)
// If there are too many concrete methods to fit in marray, return -1.
int mlen,
bool participants_hide_witnesses = true;
// Keep track of whether m is also part of the result set.
int mfill = 0;
mfill++; // keep m0 as marray[0], the first result
for (int i = 0; i < num; i++) {
return -1; // Oops. Too many methods after all!
}
}
#ifndef PRODUCT
// Make sure the dependency mechanism will pass this discovery:
if (VerifyDependencies) {
// Turn off dependency tracing while actually testing deps.
switch (mfill) {
case 1:
"verify dep.");
break;
case 2:
"verify dep.");
break;
default:
ShouldNotReachHere(); // mlen > 2 yet supported
}
}
#endif //PRODUCT
return mfill;
}
return NULL;
}
return result->as_klassOop();
}
switch (type()) {
case evol_method:
break;
case leaf_type:
break;
type_argument(1),
changes);
break;
changes);
break;
changes);
break;
case unique_concrete_method:
method_argument(1),
changes);
break;
type_argument(1),
type_argument(2),
changes);
break;
method_argument(1),
method_argument(2),
changes);
break;
changes);
break;
default:
break;
}
if (TraceDependencies) {
}
// The following is a no-op unless logging is enabled:
}
return witness;
}
// irrelevant dependency; skip it
return NULL;
return check_dependency_impl(&changes);
}
void DepChange::initialize() {
// entire transaction must be under this lock:
// Mark all dependee and all its superclasses
// Mark transitive interfaces
}
}
// Unmark all dependee and all its superclasses
// Unmark transitive interfaces
}
}
return false;
}
"correct marking of potential context types");
return is_contained;
}
switch (_change_type) {
case Start_Klass: // initial state; _klass is the new type
_ti_index = 0;
return true;
case Change_new_type:
// fall through:
case Change_new_sub:
// 6598190: brackets workaround Sun Studio C++ compiler bug 6629277
{
return true;
}
}
// else set up _ti_limit and fall through:
case Change_new_impl:
return true;
}
// fall through:
case NO_CHANGE:
break;
default:
}
return false;
}
switch (str.change_type()) {
case Change_new_type:
break;
case Change_new_sub:
if (!WizardMode) {
++nsup;
} else {
}
break;
case Change_new_impl:
if (!WizardMode) {
++nint;
} else {
}
break;
}
}
}
}
#ifndef PRODUCT
void Dependencies::print_statistics() {
if (deps_find_witness_print != 0) {
// Call one final time, to flush out the data.
deps_find_witness_print = -1;
}
}
#endif