--- a/hotspot/src/share/vm/code/dependencies.cpp Thu Oct 15 13:28:22 2015 +0200
+++ b/hotspot/src/share/vm/code/dependencies.cpp Sat Oct 17 19:40:30 2015 -0400
@@ -31,6 +31,7 @@
#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"
@@ -52,6 +53,9 @@
_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);
@@ -120,6 +124,66 @@
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
//
@@ -230,6 +294,78 @@
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) {
@@ -256,7 +392,40 @@
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];
@@ -272,6 +441,16 @@
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];
@@ -311,6 +490,37 @@
// 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];
@@ -344,6 +554,9 @@
}
}
}
+#if INCLUDE_JVMCI
+ }
+#endif
// write a sentinel byte to mark the end
bytes.write_byte(end_marker);
@@ -540,10 +753,10 @@
}
void Dependencies::print_dependency(DepType dept, GrowableArray<DepArgument>* args,
- Klass* witness) {
+ Klass* witness, outputStream* st) {
ResourceMark rm;
ttyLocker ttyl; // keep the following output all in one block
- tty->print_cr("%s of type %s",
+ st->print_cr("%s of type %s",
(witness == NULL)? "Dependency": "Failed dependency",
dep_name(dept));
// print arguments
@@ -565,22 +778,22 @@
} else {
what = "object ";
}
- tty->print(" %s = %s", what, (put_star? "*": ""));
+ st->print(" %s = %s", what, (put_star? "*": ""));
if (arg.is_klass()) {
- tty->print("%s", ((Klass*)arg.metadata_value())->external_name());
+ st->print("%s", ((Klass*)arg.metadata_value())->external_name());
} else if (arg.is_method()) {
- ((Method*)arg.metadata_value())->print_value();
+ ((Method*)arg.metadata_value())->print_value_on(st);
} else if (arg.is_oop()) {
- arg.oop_value()->print_value_on(tty);
+ arg.oop_value()->print_value_on(st);
} else {
ShouldNotReachHere(); // Provide impl for this type.
}
- tty->cr();
+ st->cr();
}
if (witness != NULL) {
bool put_star = !Dependencies::is_concrete_klass(witness);
- tty->print_cr(" witness = %s%s",
+ st->print_cr(" witness = %s%s",
(put_star? "*": ""),
witness->external_name());
}
@@ -600,14 +813,19 @@
}
int argslen = args->length();
if (_deps != NULL && _deps->log() != NULL) {
- Dependencies::write_dependency_to(_deps->log(), type(), args, witness);
+ 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) {
+void Dependencies::DepStream::print_dependency(Klass* witness, bool verbose, outputStream* st) {
ResourceMark rm;
int nargs = argument_count();
GrowableArray<DepArgument>* args = new GrowableArray<DepArgument>(nargs);
@@ -619,12 +837,12 @@
}
}
int argslen = args->length();
- Dependencies::print_dependency(type(), args, witness);
+ Dependencies::print_dependency(type(), args, witness, st);
if (verbose) {
if (_code != NULL) {
- tty->print(" code: ");
- _code->print_value_on(tty);
- tty->cr();
+ st->print(" code: ");
+ _code->print_value_on(st);
+ st->cr();
}
}
guarantee(argslen == args->length(), "args array cannot grow inside nested ResoureMark scope");