--- a/hotspot/src/share/vm/opto/compile.cpp Wed Nov 20 11:08:09 2013 -0800
+++ b/hotspot/src/share/vm/opto/compile.cpp Thu Nov 21 12:30:35 2013 -0800
@@ -851,6 +851,7 @@
}
#endif
+ NOT_PRODUCT( verify_barriers(); )
// Now that we know the size of all the monitors we can add a fixed slot
// for the original deopt pc.
@@ -3027,12 +3028,17 @@
// Phi nodes shouldn't be moved. They would only match below if they
// had the same control as the MathExactNode. The only time that
// would happen is if the Phi is also an input to the MathExact
- if (!out->is_Phi()) {
- if (out->in(0) == NULL) {
- out->set_req(0, non_throwing);
- } else if (out->in(0) == ctrl) {
- out->set_req(0, non_throwing);
- }
+ //
+ // Cmp nodes shouldn't have control set at all.
+ if (out->is_Phi() ||
+ out->is_Cmp()) {
+ continue;
+ }
+
+ if (out->in(0) == NULL) {
+ out->set_req(0, non_throwing);
+ } else if (out->in(0) == ctrl) {
+ out->set_req(0, non_throwing);
}
}
}
@@ -3377,6 +3383,72 @@
}
}
}
+
+// Verify GC barriers consistency
+// Currently supported:
+// - G1 pre-barriers (see GraphKit::g1_write_barrier_pre())
+void Compile::verify_barriers() {
+ if (UseG1GC) {
+ // Verify G1 pre-barriers
+ const int marking_offset = in_bytes(JavaThread::satb_mark_queue_offset() + PtrQueue::byte_offset_of_active());
+
+ ResourceArea *area = Thread::current()->resource_area();
+ Unique_Node_List visited(area);
+ Node_List worklist(area);
+ // We're going to walk control flow backwards starting from the Root
+ worklist.push(_root);
+ while (worklist.size() > 0) {
+ Node* x = worklist.pop();
+ if (x == NULL || x == top()) continue;
+ if (visited.member(x)) {
+ continue;
+ } else {
+ visited.push(x);
+ }
+
+ if (x->is_Region()) {
+ for (uint i = 1; i < x->req(); i++) {
+ worklist.push(x->in(i));
+ }
+ } else {
+ worklist.push(x->in(0));
+ // We are looking for the pattern:
+ // /->ThreadLocal
+ // If->Bool->CmpI->LoadB->AddP->ConL(marking_offset)
+ // \->ConI(0)
+ // We want to verify that the If and the LoadB have the same control
+ // See GraphKit::g1_write_barrier_pre()
+ if (x->is_If()) {
+ IfNode *iff = x->as_If();
+ if (iff->in(1)->is_Bool() && iff->in(1)->in(1)->is_Cmp()) {
+ CmpNode *cmp = iff->in(1)->in(1)->as_Cmp();
+ if (cmp->Opcode() == Op_CmpI && cmp->in(2)->is_Con() && cmp->in(2)->bottom_type()->is_int()->get_con() == 0
+ && cmp->in(1)->is_Load()) {
+ LoadNode* load = cmp->in(1)->as_Load();
+ if (load->Opcode() == Op_LoadB && load->in(2)->is_AddP() && load->in(2)->in(2)->Opcode() == Op_ThreadLocal
+ && load->in(2)->in(3)->is_Con()
+ && load->in(2)->in(3)->bottom_type()->is_intptr_t()->get_con() == marking_offset) {
+
+ Node* if_ctrl = iff->in(0);
+ Node* load_ctrl = load->in(0);
+
+ if (if_ctrl != load_ctrl) {
+ // Skip possible CProj->NeverBranch in infinite loops
+ if ((if_ctrl->is_Proj() && if_ctrl->Opcode() == Op_CProj)
+ && (if_ctrl->in(0)->is_MultiBranch() && if_ctrl->in(0)->Opcode() == Op_NeverBranch)) {
+ if_ctrl = if_ctrl->in(0)->in(0);
+ }
+ }
+ assert(load_ctrl != NULL && if_ctrl == load_ctrl, "controls must match");
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
#endif
// The Compile object keeps track of failure reasons separately from the ciEnv.