hotspot/src/share/vm/opto/doCall.cpp
changeset 35086 bbf32241d851
parent 34174 4db2fb26dc49
child 37774 b5e945f27f3a
--- a/hotspot/src/share/vm/opto/doCall.cpp	Fri Dec 04 16:38:04 2015 +0100
+++ b/hotspot/src/share/vm/opto/doCall.cpp	Fri Dec 04 23:46:19 2015 +0300
@@ -393,6 +393,100 @@
   return false;
 }
 
+#ifdef ASSERT
+static bool check_type(ciType* t1, ciType* t2) {
+  // Either oop-oop or prim-prim pair.
+  if (t1->is_primitive_type() && t2->is_primitive_type()) {
+    return t1->size() == t2->size(); // argument sizes should match
+  } else {
+    return !t1->is_primitive_type() && !t2->is_primitive_type(); // oop-oop
+  }
+}
+
+static bool check_inlined_mh_linker_info(ciMethod* symbolic_info, ciMethod* resolved_method) {
+  assert(symbolic_info->is_method_handle_intrinsic(), "sanity");
+  assert(!resolved_method->is_method_handle_intrinsic(), "sanity");
+
+  if (!symbolic_info->is_loaded() || !resolved_method->is_loaded()) {
+    return true; // Don't compare unloaded methods.
+  }
+  // Linkers have appendix argument which is not passed to callee.
+  int has_appendix = MethodHandles::has_member_arg(symbolic_info->intrinsic_id()) ? 1 : 0;
+  if (symbolic_info->arg_size() != (resolved_method->arg_size() + has_appendix)) {
+    return false; // Total size of arguments on stack mismatch.
+  }
+  if (!check_type(symbolic_info->return_type(), resolved_method->return_type())) {
+    return false; // Return value size or type mismatch encountered.
+  }
+
+  switch (symbolic_info->intrinsic_id()) {
+    case vmIntrinsics::_linkToVirtual:
+    case vmIntrinsics::_linkToInterface:
+    case vmIntrinsics::_linkToSpecial: {
+      if (resolved_method->is_static())  return false;
+      break;
+    }
+    case vmIntrinsics::_linkToStatic: {
+      if (!resolved_method->is_static())  return false;
+      break;
+    }
+  }
+
+  ciSignature* symbolic_sig = symbolic_info->signature();
+  ciSignature* resolved_sig = resolved_method->signature();
+
+  if (symbolic_sig->count() + (symbolic_info->is_static() ? 0 : 1) !=
+      resolved_sig->count() + (resolved_method->is_static() ? 0 : 1) + has_appendix) {
+    return false; // Argument count mismatch
+  }
+
+  int sbase = 0, rbase = 0;
+  int arg_count = MIN2(symbolic_sig->count() - has_appendix, resolved_sig->count());
+  ciType* recv_type = NULL;
+  if (symbolic_info->is_static() && !resolved_method->is_static()) {
+    recv_type = symbolic_sig->type_at(0);
+    sbase = 1;
+  } else if (!symbolic_info->is_static() && resolved_method->is_static()) {
+    recv_type = resolved_sig->type_at(0);
+    rbase = 1;
+  }
+  if (recv_type != NULL && recv_type->is_primitive_type()) {
+    return false; // Receiver should be an oop.
+  }
+  for (int i = 0; i < arg_count; i++) {
+    if (!check_type(symbolic_sig->type_at(sbase + i), resolved_sig->type_at(rbase + i))) {
+      return false; // Argument size or type mismatch encountered.
+    }
+  }
+  return true;
+}
+
+static bool is_call_consistent_with_jvms(JVMState* jvms, CallGenerator* cg) {
+  ciMethod* symbolic_info = jvms->method()->get_method_at_bci(jvms->bci());
+  ciMethod* resolved_method = cg->method();
+
+  if (CallGenerator::is_inlined_mh_linker(jvms, resolved_method)) {
+    return check_inlined_mh_linker_info(symbolic_info, resolved_method);
+  } else {
+    // Method name & descriptor should stay the same.
+    return (symbolic_info->get_Method()->name() == resolved_method->get_Method()->name()) &&
+           (symbolic_info->get_Method()->signature() == resolved_method->get_Method()->signature());
+  }
+}
+
+static bool check_call_consistency(JVMState* jvms, CallGenerator* cg) {
+  if (!is_call_consistent_with_jvms(jvms, cg)) {
+    tty->print_cr("JVMS:");
+    jvms->dump();
+    tty->print_cr("Bytecode info:");
+    jvms->method()->get_method_at_bci(jvms->bci())->print(); tty->cr();
+    tty->print_cr("Resolved method:");
+    cg->method()->print(); tty->cr();
+    return false;
+  }
+  return true;
+}
+#endif // ASSERT
 
 //------------------------------do_call----------------------------------------
 // Handle your basic call.  Inline if we can & want to, else just setup call.
@@ -571,6 +665,8 @@
     set_jvms(new_jvms);
   }
 
+  assert(check_call_consistency(jvms, cg), "inconsistent info");
+
   if (!stopped()) {
     // This was some sort of virtual call, which did a null check for us.
     // Now we can assert receiver-not-null, on the normal return path.