< prev index next >
src/share/vm/code/dependencies.cpp
Print this page
*** 29,38 ****
--- 29,39 ----
#include "ci/ciMethod.hpp"
#include "classfile/javaClasses.inline.hpp"
#include "code/dependencies.hpp"
#include "compiler/compileLog.hpp"
#include "oops/oop.inline.hpp"
+ #include "oops/objArrayKlass.hpp"
#include "runtime/handles.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/thread.inline.hpp"
#include "utilities/copy.hpp"
*** 50,59 ****
--- 51,63 ----
void Dependencies::initialize(ciEnv* env) {
Arena* arena = env->arena();
_oop_recorder = env->oop_recorder();
_log = env->log();
_dep_seen = new(arena) GrowableArray<int>(arena, 500, 0, 0);
+ #if INCLUDE_JVMCI
+ _using_dep_values = false;
+ #endif
DEBUG_ONLY(_deps[end_marker] = NULL);
for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) {
_deps[i] = new(arena) GrowableArray<ciBaseObject*>(arena, 10, 0, 0);
}
_content_bytes = NULL;
*** 118,127 ****
--- 122,191 ----
void Dependencies::assert_call_site_target_value(ciCallSite* call_site, ciMethodHandle* method_handle) {
assert_common_2(call_site_target_value, call_site, method_handle);
}
+ #if INCLUDE_JVMCI
+
+ Dependencies::Dependencies(Arena* arena, OopRecorder* oop_recorder, CompileLog* log) {
+ _oop_recorder = oop_recorder;
+ _log = log;
+ _dep_seen = new(arena) GrowableArray<int>(arena, 500, 0, 0);
+ _using_dep_values = true;
+ DEBUG_ONLY(_dep_values[end_marker] = NULL);
+ for (int i = (int)FIRST_TYPE; i < (int)TYPE_LIMIT; i++) {
+ _dep_values[i] = new(arena) GrowableArray<DepValue>(arena, 10, 0, DepValue());
+ }
+ _content_bytes = NULL;
+ _size_in_bytes = (size_t)-1;
+
+ assert(TYPE_LIMIT <= (1<<LG2_TYPE_LIMIT), "sanity");
+ }
+
+ void Dependencies::assert_evol_method(Method* m) {
+ assert_common_1(evol_method, DepValue(_oop_recorder, m));
+ }
+
+ void Dependencies::assert_has_no_finalizable_subclasses(Klass* ctxk) {
+ check_ctxk(ctxk);
+ assert_common_1(no_finalizable_subclasses, DepValue(_oop_recorder, ctxk));
+ }
+
+ void Dependencies::assert_leaf_type(Klass* ctxk) {
+ if (ctxk->oop_is_array()) {
+ // 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.
+ BasicType elemt = ArrayKlass::cast(ctxk)->element_type();
+ if (is_java_primitive(elemt)) return; // Ex: int[][]
+ ctxk = ObjArrayKlass::cast(ctxk)->bottom_klass();
+ //if (ctxk->is_final()) return; // Ex: String[][]
+ }
+ check_ctxk(ctxk);
+ assert_common_1(leaf_type, DepValue(_oop_recorder, ctxk));
+ }
+
+ void Dependencies::assert_abstract_with_unique_concrete_subtype(Klass* ctxk, Klass* conck) {
+ check_ctxk_abstract(ctxk);
+ DepValue ctxk_dv(_oop_recorder, ctxk);
+ DepValue conck_dv(_oop_recorder, conck, &ctxk_dv);
+ assert_common_2(abstract_with_unique_concrete_subtype, ctxk_dv, conck_dv);
+ }
+
+ void Dependencies::assert_unique_concrete_method(Klass* ctxk, Method* uniqm) {
+ check_ctxk(ctxk);
+ assert_common_2(unique_concrete_method, DepValue(_oop_recorder, ctxk), DepValue(_oop_recorder, uniqm));
+ }
+
+ void Dependencies::assert_call_site_target_value(oop call_site, oop method_handle) {
+ assert_common_2(call_site_target_value, DepValue(_oop_recorder, JNIHandles::make_local(call_site)), DepValue(_oop_recorder, JNIHandles::make_local(method_handle)));
+ }
+
+ #endif // INCLUDE_JVMCI
+
+
// Helper function. If we are adding a new dep. under ctxk2,
// try to find an old dep. under a broader* ctxk1. If there is
//
bool Dependencies::maybe_merge_ctxk(GrowableArray<ciBaseObject*>* deps,
int ctxk_i, ciKlass* ctxk2) {
*** 228,237 ****
--- 292,373 ----
deps->append(ctxk);
deps->append(x);
deps->append(x2);
}
+ #if INCLUDE_JVMCI
+ bool Dependencies::maybe_merge_ctxk(GrowableArray<DepValue>* deps,
+ int ctxk_i, DepValue ctxk2_dv) {
+ Klass* ctxk1 = deps->at(ctxk_i).as_klass(_oop_recorder);
+ Klass* ctxk2 = ctxk2_dv.as_klass(_oop_recorder);
+ if (ctxk2->is_subtype_of(ctxk1)) {
+ return true; // success, and no need to change
+ } else if (ctxk1->is_subtype_of(ctxk2)) {
+ // new context class fully subsumes previous one
+ deps->at_put(ctxk_i, ctxk2_dv);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ void Dependencies::assert_common_1(DepType dept, DepValue x) {
+ assert(dep_args(dept) == 1, "sanity");
+ //log_dependency(dept, x);
+ GrowableArray<DepValue>* deps = _dep_values[dept];
+
+ // see if the same (or a similar) dep is already recorded
+ if (note_dep_seen(dept, x)) {
+ assert(deps->find(x) >= 0, "sanity");
+ } else {
+ deps->append(x);
+ }
+ }
+
+ void Dependencies::assert_common_2(DepType dept,
+ DepValue x0, DepValue x1) {
+ assert(dep_args(dept) == 2, "sanity");
+ //log_dependency(dept, x0, x1);
+ GrowableArray<DepValue>* deps = _dep_values[dept];
+
+ // see if the same (or a similar) dep is already recorded
+ bool has_ctxk = has_explicit_context_arg(dept);
+ if (has_ctxk) {
+ assert(dep_context_arg(dept) == 0, "sanity");
+ if (note_dep_seen(dept, x1)) {
+ // look in this bucket for redundant assertions
+ const int stride = 2;
+ for (int i = deps->length(); (i -= stride) >= 0; ) {
+ DepValue y1 = deps->at(i+1);
+ if (x1 == y1) { // same subject; check the context
+ if (maybe_merge_ctxk(deps, i+0, x0)) {
+ return;
+ }
+ }
+ }
+ }
+ } else {
+ assert(dep_implicit_context_arg(dept) == 0, "sanity");
+ if (note_dep_seen(dept, x0) && note_dep_seen(dept, x1)) {
+ // look in this bucket for redundant assertions
+ const int stride = 2;
+ for (int i = deps->length(); (i -= stride) >= 0; ) {
+ DepValue y0 = deps->at(i+0);
+ DepValue y1 = deps->at(i+1);
+ if (x0 == y0 && x1 == y1) {
+ return;
+ }
+ }
+ }
+ }
+
+ // append the assertion in the correct bucket:
+ deps->append(x0);
+ deps->append(x1);
+ }
+ #endif // INCLUDE_JVMCI
+
/// Support for encoding dependencies into an nmethod:
void Dependencies::copy_to(nmethod* nm) {
address beg = nm->dependencies_begin();
address end = nm->dependencies_end();
*** 254,264 ****
--- 390,433 ----
static int sort_dep_arg_2(ciBaseObject** p1, ciBaseObject** p2)
{ return sort_dep(p1, p2, 2); }
static int sort_dep_arg_3(ciBaseObject** p1, ciBaseObject** p2)
{ return sort_dep(p1, p2, 3); }
+ #if INCLUDE_JVMCI
+ // metadata deps are sorted before object deps
+ static int sort_dep_value(Dependencies::DepValue* p1, Dependencies::DepValue* p2, int narg) {
+ for (int i = 0; i < narg; i++) {
+ int diff = p1[i].sort_key() - p2[i].sort_key();
+ if (diff != 0) return diff;
+ }
+ return 0;
+ }
+ static int sort_dep_value_arg_1(Dependencies::DepValue* p1, Dependencies::DepValue* p2)
+ { return sort_dep_value(p1, p2, 1); }
+ static int sort_dep_value_arg_2(Dependencies::DepValue* p1, Dependencies::DepValue* p2)
+ { return sort_dep_value(p1, p2, 2); }
+ static int sort_dep_value_arg_3(Dependencies::DepValue* p1, Dependencies::DepValue* p2)
+ { return sort_dep_value(p1, p2, 3); }
+ #endif // INCLUDE_JVMCI
+
void Dependencies::sort_all_deps() {
+ #if INCLUDE_JVMCI
+ if (_using_dep_values) {
+ for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) {
+ DepType dept = (DepType)deptv;
+ GrowableArray<DepValue>* deps = _dep_values[dept];
+ if (deps->length() <= 1) continue;
+ switch (dep_args(dept)) {
+ case 1: deps->sort(sort_dep_value_arg_1, 1); break;
+ case 2: deps->sort(sort_dep_value_arg_2, 2); break;
+ case 3: deps->sort(sort_dep_value_arg_3, 3); break;
+ default: ShouldNotReachHere();
+ }
+ }
+ return;
+ }
+ #endif // INCLUDE_JVMCI
for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) {
DepType dept = (DepType)deptv;
GrowableArray<ciBaseObject*>* deps = _deps[dept];
if (deps->length() <= 1) continue;
switch (dep_args(dept)) {
*** 270,279 ****
--- 439,458 ----
}
}
size_t Dependencies::estimate_size_in_bytes() {
size_t est_size = 100;
+ #if INCLUDE_JVMCI
+ if (_using_dep_values) {
+ for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) {
+ DepType dept = (DepType)deptv;
+ GrowableArray<DepValue>* deps = _dep_values[dept];
+ est_size += deps->length() * 2; // tags and argument(s)
+ }
+ return est_size;
+ }
+ #endif // INCLUDE_JVMCI
for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) {
DepType dept = (DepType)deptv;
GrowableArray<ciBaseObject*>* deps = _deps[dept];
est_size += deps->length()*2; // tags and argument(s)
}
*** 309,318 ****
--- 488,528 ----
sort_all_deps();
// cast is safe, no deps can overflow INT_MAX
CompressedWriteStream bytes((int)estimate_size_in_bytes());
+ #if INCLUDE_JVMCI
+ if (_using_dep_values) {
+ for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) {
+ DepType dept = (DepType)deptv;
+ GrowableArray<DepValue>* deps = _dep_values[dept];
+ if (deps->length() == 0) continue;
+ int stride = dep_args(dept);
+ int ctxkj = dep_context_arg(dept); // -1 if no context arg
+ assert(stride > 0, "sanity");
+ for (int i = 0; i < deps->length(); i += stride) {
+ jbyte code_byte = (jbyte)dept;
+ int skipj = -1;
+ if (ctxkj >= 0 && ctxkj+1 < stride) {
+ Klass* ctxk = deps->at(i+ctxkj+0).as_klass(_oop_recorder);
+ DepValue x = deps->at(i+ctxkj+1); // following argument
+ if (ctxk == ctxk_encoded_as_null(dept, x.as_metadata(_oop_recorder))) {
+ skipj = ctxkj; // we win: maybe one less oop to keep track of
+ code_byte |= default_context_type_bit;
+ }
+ }
+ bytes.write_byte(code_byte);
+ for (int j = 0; j < stride; j++) {
+ if (j == skipj) continue;
+ DepValue v = deps->at(i+j);
+ int idx = v.index();
+ bytes.write_int(idx);
+ }
+ }
+ }
+ } else {
+ #endif // INCLUDE_JVMCI
for (int deptv = (int)FIRST_TYPE; deptv < (int)TYPE_LIMIT; deptv++) {
DepType dept = (DepType)deptv;
GrowableArray<ciBaseObject*>* deps = _deps[dept];
if (deps->length() == 0) continue;
int stride = dep_args(dept);
*** 342,351 ****
--- 552,564 ----
}
bytes.write_int(idx);
}
}
}
+ #if INCLUDE_JVMCI
+ }
+ #endif
// write a sentinel byte to mark the end
bytes.write_byte(end_marker);
// round it out to a word boundary
*** 538,551 ****
}
xtty->end_elem();
}
void Dependencies::print_dependency(DepType dept, GrowableArray<DepArgument>* args,
! Klass* witness) {
ResourceMark rm;
ttyLocker ttyl; // keep the following output all in one block
! tty->print_cr("%s of type %s",
(witness == NULL)? "Dependency": "Failed dependency",
dep_name(dept));
// print arguments
int ctxkj = dep_context_arg(dept); // -1 if no context arg
for (int j = 0; j < args->length(); j++) {
--- 751,764 ----
}
xtty->end_elem();
}
void Dependencies::print_dependency(DepType dept, GrowableArray<DepArgument>* args,
! Klass* witness, outputStream* st) {
ResourceMark rm;
ttyLocker ttyl; // keep the following output all in one block
! st->print_cr("%s of type %s",
(witness == NULL)? "Dependency": "Failed dependency",
dep_name(dept));
// print arguments
int ctxkj = dep_context_arg(dept); // -1 if no context arg
for (int j = 0; j < args->length(); j++) {
*** 563,588 ****
} else if (arg.is_klass()) {
what = "class ";
} else {
what = "object ";
}
! tty->print(" %s = %s", what, (put_star? "*": ""));
if (arg.is_klass()) {
! tty->print("%s", ((Klass*)arg.metadata_value())->external_name());
} else if (arg.is_method()) {
! ((Method*)arg.metadata_value())->print_value();
} else if (arg.is_oop()) {
! arg.oop_value()->print_value_on(tty);
} else {
ShouldNotReachHere(); // Provide impl for this type.
}
! tty->cr();
}
if (witness != NULL) {
bool put_star = !Dependencies::is_concrete_klass(witness);
! tty->print_cr(" witness = %s%s",
(put_star? "*": ""),
witness->external_name());
}
}
--- 776,801 ----
} else if (arg.is_klass()) {
what = "class ";
} else {
what = "object ";
}
! st->print(" %s = %s", what, (put_star? "*": ""));
if (arg.is_klass()) {
! st->print("%s", ((Klass*)arg.metadata_value())->external_name());
} else if (arg.is_method()) {
! ((Method*)arg.metadata_value())->print_value_on(st);
} else if (arg.is_oop()) {
! arg.oop_value()->print_value_on(st);
} else {
ShouldNotReachHere(); // Provide impl for this type.
}
! st->cr();
}
if (witness != NULL) {
bool put_star = !Dependencies::is_concrete_klass(witness);
! st->print_cr(" witness = %s%s",
(put_star? "*": ""),
witness->external_name());
}
}
*** 598,615 ****
args->push(argument(j));
}
}
int argslen = args->length();
if (_deps != NULL && _deps->log() != NULL) {
Dependencies::write_dependency_to(_deps->log(), type(), args, witness);
} else {
Dependencies::write_dependency_to(xtty, type(), args, witness);
}
guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope");
}
! void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose) {
ResourceMark rm;
int nargs = argument_count();
GrowableArray<DepArgument>* args = new GrowableArray<DepArgument>(nargs);
for (int j = 0; j < nargs; j++) {
if (is_oop_argument(j)) {
--- 811,833 ----
args->push(argument(j));
}
}
int argslen = args->length();
if (_deps != NULL && _deps->log() != NULL) {
+ if (ciEnv::current() != NULL) {
Dependencies::write_dependency_to(_deps->log(), type(), args, witness);
} else {
+ // Treat the CompileLog as an xmlstream instead
+ Dependencies::write_dependency_to((xmlStream*)_deps->log(), type(), args, witness);
+ }
+ } else {
Dependencies::write_dependency_to(xtty, type(), args, witness);
}
guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope");
}
! void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose, outputStream* st) {
ResourceMark rm;
int nargs = argument_count();
GrowableArray<DepArgument>* args = new GrowableArray<DepArgument>(nargs);
for (int j = 0; j < nargs; j++) {
if (is_oop_argument(j)) {
*** 617,632 ****
} else {
args->push(argument(j));
}
}
int argslen = args->length();
! Dependencies::print_dependency(type(), args, witness);
if (verbose) {
if (_code != NULL) {
! tty->print(" code: ");
! _code->print_value_on(tty);
! tty->cr();
}
}
guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope");
}
--- 835,850 ----
} else {
args->push(argument(j));
}
}
int argslen = args->length();
! Dependencies::print_dependency(type(), args, witness, st);
if (verbose) {
if (_code != NULL) {
! st->print(" code: ");
! _code->print_value_on(st);
! st->cr();
}
}
guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope");
}
< prev index next >