changeset 8395:c73c5d205d0a

8153267: nmethod's exception cache not multi-thread safe 8143897: Weblogic12medrec assert(handler_address == SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, force_unwind, true)) failed: Must be the same Reviewed-by: kvn, mdoerr
author dbuck
date Fri, 07 Apr 2017 02:15:31 +0900
parents 92cb89e23f3e
children dcaab7b518c4
files src/share/vm/code/nmethod.cpp src/share/vm/code/nmethod.hpp src/share/vm/runtime/vmStructs.cpp
diffstat 3 files changed, 23 insertions(+), 16 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/code/nmethod.cpp	Tue Apr 04 02:49:51 2017 -0700
+++ b/src/share/vm/code/nmethod.cpp	Fri Apr 07 02:15:31 2017 +0900
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -254,7 +254,8 @@
 
 
 address ExceptionCache::test_address(address addr) {
-  for (int i=0; i<count(); i++) {
+  int limit = count();
+  for (int i = 0; i < limit; i++) {
     if (pc_at(i) == addr) {
       return handler_at(i);
     }
@@ -265,9 +266,11 @@
 
 bool ExceptionCache::add_address_and_handler(address addr, address handler) {
   if (test_address(addr) == handler) return true;
-  if (count() < cache_size) {
-    set_pc_at(count(),addr);
-    set_handler_at(count(), handler);
+
+  int index = count();
+  if (index < cache_size) {
+    set_pc_at(index, addr);
+    set_handler_at(index, handler);
     increment_count();
     return true;
   }
@@ -380,10 +383,11 @@
   assert(new_entry != NULL,"Must be non null");
   assert(new_entry->next() == NULL, "Must be null");
 
-  if (exception_cache() != NULL) {
-    new_entry->set_next(exception_cache());
+  ExceptionCache *ec = exception_cache();
+  if (ec != NULL) {
+    new_entry->set_next(ec);
   }
-  set_exception_cache(new_entry);
+  release_set_exception_cache(new_entry);
 }
 
 void nmethod::clean_exception_cache(BoolObjectClosure* is_alive) {
--- a/src/share/vm/code/nmethod.hpp	Tue Apr 04 02:49:51 2017 -0700
+++ b/src/share/vm/code/nmethod.hpp	Fri Apr 07 02:15:31 2017 +0900
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -39,15 +39,16 @@
   Klass*   _exception_type;
   address  _pc[cache_size];
   address  _handler[cache_size];
-  int      _count;
+  volatile int _count;
   ExceptionCache* _next;
 
   address pc_at(int index)                     { assert(index >= 0 && index < count(),""); return _pc[index]; }
   void    set_pc_at(int index, address a)      { assert(index >= 0 && index < cache_size,""); _pc[index] = a; }
   address handler_at(int index)                { assert(index >= 0 && index < count(),""); return _handler[index]; }
   void    set_handler_at(int index, address a) { assert(index >= 0 && index < cache_size,""); _handler[index] = a; }
-  int     count()                              { return _count; }
-  void    increment_count()                    { _count++; }
+  int     count()                              { return OrderAccess::load_acquire(&_count); }
+  // increment_count is only called under lock, but there may be concurrent readers.
+  void    increment_count()                    { OrderAccess::release_store(&_count, _count + 1); }
 
  public:
 
@@ -237,7 +238,7 @@
   // counter is decreased (by 1) while sweeping.
   int _hotness_counter;
 
-  ExceptionCache *_exception_cache;
+  ExceptionCache * volatile _exception_cache;
   PcDescCache     _pc_desc_cache;
 
   // These are used for compiled synchronized native methods to
@@ -433,7 +434,7 @@
 
   // flag accessing and manipulation
   bool  is_in_use() const                         { return _state == in_use; }
-  bool  is_alive() const                          { return _state == in_use || _state == not_entrant; }
+  bool  is_alive() const                          { unsigned char s = _state; return s == in_use || s == not_entrant; }
   bool  is_not_entrant() const                    { return _state == not_entrant; }
   bool  is_zombie() const                         { return _state == zombie; }
   bool  is_unloaded() const                       { return _state == unloaded;   }
@@ -555,8 +556,10 @@
   void  set_stack_traversal_mark(long l)          { _stack_traversal_mark = l; }
 
   // Exception cache support
+  // Note: _exception_cache may be read concurrently. We rely on memory_order_consume here.
   ExceptionCache* exception_cache() const         { return _exception_cache; }
   void set_exception_cache(ExceptionCache *ec)    { _exception_cache = ec; }
+  void release_set_exception_cache(ExceptionCache *ec) { OrderAccess::release_store_ptr(&_exception_cache, ec); }
   address handler_for_exception_and_pc(Handle exception, address pc);
   void add_handler_for_exception_and_pc(Handle exception, address pc, address handler);
   void clean_exception_cache(BoolObjectClosure* is_alive);
--- a/src/share/vm/runtime/vmStructs.cpp	Tue Apr 04 02:49:51 2017 -0700
+++ b/src/share/vm/runtime/vmStructs.cpp	Fri Apr 07 02:15:31 2017 +0900
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -879,7 +879,7 @@
   nonstatic_field(nmethod,             _stack_traversal_mark,                         long)                                  \
   nonstatic_field(nmethod,             _compile_id,                                   int)                                   \
   nonstatic_field(nmethod,             _comp_level,                                   int)                                   \
-  nonstatic_field(nmethod,             _exception_cache,                              ExceptionCache*)                       \
+  volatile_nonstatic_field(nmethod,    _exception_cache,                              ExceptionCache*)                       \
   nonstatic_field(nmethod,             _marked_for_deoptimization,                    bool)                                  \
                                                                                                                              \
   unchecked_c2_static_field(Deoptimization,         _trap_reason_name,                   void*)                              \