Shark monitor improvements

Gary Benson gbenson at redhat.com
Wed May 27 07:03:54 PDT 2009


Hi all,

Monitors are used in Java bytecode for synchronization.  Previously,
Shark handled monitors in a similar manner to the C++ interpreter,
and a lot of the work of monitor allocation was performed at runtime.
With this commit, a lot of that work is handled at compile time.

Cheers,
Gary

-- 
http://gbenson.net/
-------------- next part --------------
diff -r b22d229ddbcf ChangeLog
--- a/ChangeLog	Wed May 27 13:49:38 2009 +0100
+++ b/ChangeLog	Wed May 27 14:59:07 2009 +0100
@@ -1,3 +1,101 @@
+2009-05-27  Gary Benson  <gbenson at redhat.com>
+
+	* ports/hotspot/src/share/vm/shark/sharkFunction.hpp
+	(SharkFunction::_monitor_count): Removed.
+	(SharkFunction::_max_monitors): New field.
+	(SharkFunction::monitor_count): Removed.
+	(SharkFunction::max_monitors): New method.
+	(SharkFunction::_exception_slot_offset): Removed.
+	(SharkFunction::exception_slot): Likewise.
+	(SharkFunction::_oop_tmp_slot_offset): New field.
+	(SharkFunction::oop_tmp_slot_offset): New method.
+	(SharkFunction::monitors_slots): Removed.
+	(SharkFunction::monitors_slots_offset): Likewise.
+	(SharkFunction::monitor_offset): New method.
+	(SharkFunction::monitor_object_offset): Likewise.
+	(SharkFunction::monitor_header_offset): Likewise.
+	(SharkFunction::monitor_addr): Likewise.
+	(SharkFunction::monitor_object_addr): Likewise.
+	(SharkFunction::monitor_header_addr): Likewise.
+	* ports/hotspot/src/share/vm/shark/sharkFunction.cpp
+	(SharkFunction::initialize): Renamed _monitor_count as _max_monitors.
+	(SharkFunction::CreateBuildFrame): Renamed _monitor_count as
+	_max_monitors, remove monitor initialization, remove exception
+	pointer and add temporary oop slot.
+	(SharkFunction::monitor): Removed.
+
+	* ports/hotspot/src/share/vm/shark/sharkState.hpp
+	(SharkState::_num_monitors): New field.
+	(SharkState::max_monitors): New method.
+	(SharkState::num_monitors): Likewise.
+	(SharkState::set_num_monitors): Likewise.
+	(SharkState::_oop_tmp): New field.
+	(SharkState::oop_tmp_addr): New method.
+	(SharkState::oop_tmp): Likewise.
+	(SharkState::set_oop_tmp): Likewise.
+	* ports/hotspot/src/share/vm/shark/sharkState.inline.hpp
+	(SharkState::max_monitors): New method.
+	* ports/hotspot/src/share/vm/shark/sharkState.cpp
+	(SharkState::SharkState): Initialize oop_tmp.
+	(SharkState::initialize): Initialize num_monitors.
+	(SharkPHIState::SharkPHIState): Likewise.
+	(SharkState::equal_to): Also check oop_tmp and num_monitors.
+	(SharkPHIState::add_incoming): Likewise.
+	(SharkState::merge): Also merge oop_tmp and check num_monitors.
+
+	* ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp
+	(SharkStateScanner::process_monitor): New argument.
+	(SharkStateScanner::process_oop_tmp_slot): New method.
+	(SharkStateScanner::process_exception_slot): Removed.
+	* ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp
+	(SharkStateScanner::scan): Replace monitor scanning, remove
+	exception slot, and add temporary oop slot.
+	
+ 	* ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp
+	(SharkDecacher::process_monitor): New argument.
+	(SharkDecacher::process_oop_tmp_slot): New method.
+	(SharkCacher::process_oop_tmp_slot): Likewise.
+	(SharkDecacher::process_exception_slot): Removed.
+	* ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp
+	(SharkDecacher::process_monitor): New argument.
+	(SharkDecacher::process_oop_tmp_slot): New method.
+	(SharkCacher::process_oop_tmp_slot): Likewise.
+	(SharkDecacher::process_exception_slot): Removed.
+
+	* ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp
+	(SharkTopLevelBlock::set_oop_tmp): New method.
+	(SharkTopLevelBlock::get_oop_tmp): Likewise.
+	(SharkTopLevelBlock::num_monitors): Likewise.
+	(SharkTopLevelBlock::set_num_monitors): Likewise.
+	(SharkTopLevelBlock::release_method_lock): Removed.
+	(SharkTopLevelBlock::release_locked_monitors): Likewise.
+	(SharkTopLevelBlock::acquire_lock): New method.
+	(SharkTopLevelBlock::release_lock): Likewise.
+	* ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp
+	(SharkTopLevelBlock::acquire_method_lock): Rewritten.
+	(SharkTopLevelBlock::release_method_lock): Removed.
+	(SharkTopLevelBlock::release_locked_monitors): Likewise.
+	(SharkTopLevelBlock::handle_return): New monitor release code.
+	(SharkTopLevelBlock::do_monitorenter): Rewritten.
+	(SharkTopLevelBlock::do_monitorexit): Likewise.
+	(SharkTopLevelBlock::acquire_lock): New method.
+	(SharkTopLevelBlock::release_lock): Likewise.
+
+	* ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp
+	(SharkFrame::Layout): Replaced exception slot with oop_tmp slot.
+ 	* ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp
+	(ZeroStackPrinter::print_word): Likewise.
+
+	* ports/hotspot/src/share/vm/shark/sharkMonitor.hpp: Removed.
+	* ports/hotspot/src/share/vm/shark/sharkMonitor.cpp: Likewise.
+
+	* ports/hotspot/src/share/vm/includeDB_shark: Updated.
+
+	* patches/hotspot/default/icedtea-shark.patch
+	(vframeArrayElement::fill_in): Remove workaround for
+	unused but recorded monitors.
+	(vframeArrayElement::unpack_on_stack): Likewise.
+
 2009-05-27  Gary Benson  <gbenson at redhat.com>
 
 	* ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp
diff -r b22d229ddbcf patches/hotspot/default/icedtea-shark.patch
--- a/patches/hotspot/default/icedtea-shark.patch	Wed May 27 13:49:38 2009 +0100
+++ b/patches/hotspot/default/icedtea-shark.patch	Wed May 27 14:59:07 2009 +0100
@@ -56,32 +56,6 @@
   {0, NULL, NULL}
  };
  
---- openjdk/hotspot/src/share/vm/runtime/vframeArray.cpp.orig	2008-11-22 00:11:18.000000000 +0000
-+++ openjdk/hotspot/src/share/vm/runtime/vframeArray.cpp	2008-12-03 14:33:49.000000000 +0000
-@@ -64,6 +64,11 @@
-       assert(monitor->owner() == NULL || (!monitor->owner()->is_unlocked() && !monitor->owner()->has_bias_pattern()), "object must be null or locked, and unbiased");
-       BasicObjectLock* dest = _monitors->at(index);
-       dest->set_obj(monitor->owner());
-+#ifdef SHARK
-+      // XXX This can be removed when Shark knows
-+      // which monitors are in use.
-+      if (monitor->owner())
-+#endif // SHARK
-       monitor->lock()->move_to(monitor->owner(), dest->lock());
-     }
-   }
-@@ -262,6 +267,11 @@
-     top = iframe()->previous_monitor_in_interpreter_frame(top);
-     BasicObjectLock* src = _monitors->at(index);
-     top->set_obj(src->obj());
-+#ifdef SHARK
-+    // XXX This can be removed when Shark knows
-+    // which monitors are in use.
-+    if (src->obj())
-+#endif // SHARK    
-     src->lock()->move_to(src->obj(), top->lock());
-   }
-   if (ProfileInterpreter) {
 --- openjdk/hotspot/src/share/vm/runtime/vm_version.cpp.orig	2008-12-03 14:23:37.000000000 +0000
 +++ openjdk/hotspot/src/share/vm/runtime/vm_version.cpp	2008-12-03 14:33:48.000000000 +0000
 @@ -94,6 +94,9 @@
diff -r b22d229ddbcf ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp
--- a/ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/cpu/zero/vm/sharkFrame_zero.hpp	Wed May 27 14:59:07 2009 +0100
@@ -31,7 +31,7 @@
 // | monitor m-1        |
 // |  ...               |
 // | monitor 0          |
-// | exception          |
+// | oop_tmp            |
 // | method             |
 // | unextended_sp      |
 // | pc                 |
@@ -55,7 +55,7 @@
     pc_off = jf_header_words,
     unextended_sp_off,
     method_off,
-    exception_off,
+    oop_tmp_off,
     header_words
   };
 
diff -r b22d229ddbcf ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp
--- a/ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/cpu/zero/vm/stackPrinter_zero.hpp	Wed May 27 14:59:07 2009 +0100
@@ -222,8 +222,8 @@
           if (method->is_oop())
             value = method->name_and_sig_as_C_string(_buf, _buflen);
         }
-        else if (word == SharkFrame::exception_off) {
-          field = "exception";
+        else if (word == SharkFrame::oop_tmp_off) {
+          field = "oop_tmp";
         }
         else {
           SharkFrame *sf = (SharkFrame *) frame;
diff -r b22d229ddbcf ports/hotspot/src/share/vm/includeDB_shark
--- a/ports/hotspot/src/share/vm/includeDB_shark	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/includeDB_shark	Wed May 27 14:59:07 2009 +0100
@@ -193,7 +193,6 @@
 sharkFunction.cpp                       sharkBuilder.hpp
 sharkFunction.cpp                       sharkEntry.hpp
 sharkFunction.cpp                       sharkFunction.hpp
-sharkFunction.cpp                       sharkMonitor.hpp
 sharkFunction.cpp                       sharkState.inline.hpp
 sharkFunction.cpp                       sharkTopLevelBlock.hpp
 
@@ -241,19 +240,6 @@
 sharkMemoryManager.cpp                  sharkEntry.hpp
 sharkMemoryManager.cpp                  sharkMemoryManager.hpp
 
-sharkMonitor.cpp                        llvmHeaders.hpp
-sharkMonitor.cpp                        llvmValue.hpp
-sharkMonitor.cpp                        sharkMonitor.hpp
-sharkMonitor.cpp                        sharkRuntime.hpp
-sharkMonitor.cpp                        sharkState.inline.hpp
-sharkMonitor.cpp                        sharkTopLevelBlock.hpp
-
-sharkMonitor.hpp                        allocation.hpp
-sharkMonitor.hpp                        llvmHeaders.hpp
-sharkMonitor.hpp                        llvmValue.hpp
-sharkMonitor.hpp                        sharkBuilder.hpp
-sharkMonitor.hpp                        sharkFunction.hpp
-
 sharkRuntime.cpp                        biasedLocking.hpp
 sharkRuntime.cpp                        deoptimization.hpp
 sharkRuntime.cpp                        llvmHeaders.hpp
@@ -326,7 +312,6 @@
 sharkTopLevelBlock.hpp                  sharkBlock.hpp
 sharkTopLevelBlock.hpp                  sharkBuilder.hpp
 sharkTopLevelBlock.hpp                  sharkFunction.hpp
-sharkTopLevelBlock.hpp                  sharkMonitor.hpp
 sharkTopLevelBlock.hpp                  sharkState.inline.hpp
 sharkTopLevelBlock.hpp                  sharkValue.hpp
 
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp
--- a/ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkCacheDecache.cpp	Wed May 27 14:59:07 2009 +0100
@@ -82,11 +82,8 @@
   _monarray = new GrowableArray<MonitorValue*>(num_monitors);
 }
 
-void SharkDecacher::process_monitor(int index, int box_offset)
+void SharkDecacher::process_monitor(int index, int box_offset, int obj_offset)
 {
-  int obj_offset =
-    box_offset + (BasicObjectLock::obj_offset_in_bytes() >> LogBytesPerWord);
-
   oopmap()->set_oop(slot2reg(obj_offset));
 
   monarray()->append(new MonitorValue(
@@ -94,13 +91,20 @@
     slot2loc(box_offset, Location::normal)));
 }
 
-void SharkDecacher::process_exception_slot(int offset)
+void SharkDecacher::process_oop_tmp_slot(Value** value, int offset)
 {
-  // Record the exception slot
-  oopmap()->set_oop(slot2reg(offset));
+  // Decache the temporary oop slot
+  if (*value) {
+    write_value_to_frame(
+      SharkType::oop_type(),
+      *value,
+      offset);
+
+    oopmap()->set_oop(slot2reg(offset));
+  }
 }
 
-void SharkDecacher::process_method_slot(llvm::Value** value, int offset)
+void SharkDecacher::process_method_slot(Value** value, int offset)
 {
   // Decache the method pointer
   write_value_to_frame(
@@ -182,14 +186,20 @@
   }
 }
 
-void SharkCacher::process_method_slot(llvm::Value** value, int offset)
+void SharkCacher::process_oop_tmp_slot(Value** value, int offset)
+{
+  // Cache the temporary oop
+  if (*value)
+    *value = read_value_from_frame(SharkType::oop_type(), offset);
+}
+
+void SharkCacher::process_method_slot(Value** value, int offset)
 {
   // Cache the method pointer
   *value = read_value_from_frame(SharkType::methodOop_type(), offset);
 }
 
-void SharkFunctionEntryCacher::process_method_slot(llvm::Value** value,
-                                                   int           offset)
+void SharkFunctionEntryCacher::process_method_slot(Value** value, int offset)
 {
   // "Cache" the method pointer
   *value = method();
@@ -212,9 +222,9 @@
   }
 }
 
-void SharkDecacher::write_value_to_frame(const llvm::Type* type,
-                                         llvm::Value*      value,
-                                         int               offset)
+void SharkDecacher::write_value_to_frame(const Type* type,
+                                         Value*      value,
+                                         int         offset)
 {
   if (frame_cache()->value(offset) != value) {
     builder()->CreateStore(
@@ -223,7 +233,7 @@
   }
 }
 
-Value* SharkCacher::read_value_from_frame(const llvm::Type* type, int offset)
+Value* SharkCacher::read_value_from_frame(const Type* type, int offset)
 {
   Value *result = builder()->CreateLoad(
     function()->CreateAddressOfFrameEntry(offset, type));
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkCacheDecache.hpp	Wed May 27 14:59:07 2009 +0100
@@ -122,9 +122,9 @@
   void process_stack_slot(int index, SharkValue** value, int offset);
 
   void start_monitors(int num_monitors);
-  void process_monitor(int index, int offset);
+  void process_monitor(int index, int box_offset, int obj_offset);
 
-  void process_exception_slot(int offset);
+  void process_oop_tmp_slot(llvm::Value** value, int offset);
   void process_method_slot(llvm::Value** value, int offset);
   void process_pc_slot(int offset);
   
@@ -354,6 +354,7 @@
  protected:
   void process_stack_slot(int index, SharkValue** value, int offset);
 
+  void process_oop_tmp_slot(llvm::Value** value, int offset);
   virtual void process_method_slot(llvm::Value** value, int offset);
 
   void process_local_slot(int index, SharkValue** value, int offset);
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkFunction.cpp
--- a/ports/hotspot/src/share/vm/shark/sharkFunction.cpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkFunction.cpp	Wed May 27 14:59:07 2009 +0100
@@ -53,15 +53,16 @@
   // Create the list of blocks
   set_block_insertion_point(NULL);
   _blocks = NEW_RESOURCE_ARRAY(SharkTopLevelBlock*, flow()->block_count());
-  for (int i = 0; i < block_count(); i++)
-    {
-      ciTypeFlow::Block *b = flow()->pre_order_at(i);
-      // Work around a bug in pre_order_at() that does not return the
-      // correct pre-ordering.  If pre_order_at() were correct this
-      // line could simply be:
-      // _blocks[i] = new SharkTopLevelBlock(this, b);
-      _blocks[b->pre_order()] = new SharkTopLevelBlock(this, b);
-    }
+  for (int i = 0; i < block_count(); i++) {
+    ciTypeFlow::Block *b = flow()->pre_order_at(i);
+
+    // Work around a bug in pre_order_at() that does not return
+    // the correct pre-ordering.  If pre_order_at() were correct
+    // this line could simply be:
+    // _blocks[i] = new SharkTopLevelBlock(this, b);
+    _blocks[b->pre_order()] = new SharkTopLevelBlock(this, b);
+  }
+
   // Walk the tree from the start block to determine which
   // blocks are entered and which blocks require phis
   SharkTopLevelBlock *start_block = block(0);
@@ -75,11 +76,11 @@
   }
 
   // Initialize the monitors
-  _monitor_count = 0;  
+  _max_monitors = 0;  
   if (target()->is_synchronized() || target()->uses_monitors()) {
     for (int i = 0; i < block_count(); i++)
-      _monitor_count = MAX2(
-        _monitor_count, block(i)->ciblock()->monitor_count());
+      _max_monitors = MAX2(
+        _max_monitors, block(i)->ciblock()->monitor_count());
   }
   
   // Create the method preamble
@@ -216,7 +217,7 @@
   int locals_words  = max_locals();
   int extra_locals  = locals_words - arg_size();
   int header_words  = SharkFrame::header_words;
-  int monitor_words = monitor_count()*frame::interpreter_frame_monitor_size();
+  int monitor_words = max_monitors()*frame::interpreter_frame_monitor_size();
   int stack_words   = max_stack();
   int frame_words   = header_words + monitor_words + stack_words;
 
@@ -242,19 +243,11 @@
   offset += stack_words;
 
   // Monitors
-  if (monitor_count()) {
-    _monitors_slots_offset = offset; 
-
-    for (int i = 0; i < monitor_count(); i++) {
-      if (i != 0 || !target()->is_synchronized())
-        monitor(i)->mark_free();
-    }
-  }
+  _monitors_slots_offset = offset; 
   offset += monitor_words;
 
-  // Exception pointer
-  _exception_slot_offset = offset++;
-  builder()->CreateStore(LLVMValue::null(), exception_slot());
+  // Temporary oop slot
+  _oop_tmp_slot_offset = offset++;
 
   // Method pointer
   _method_slot_offset = offset++;
@@ -297,18 +290,6 @@
   return result;
 }
 
-SharkMonitor* SharkFunction::monitor(Value *index) const
-{
-  Value *indexes[] = {
-    LLVMValue::jint_constant(0),
-    builder()->CreateSub(
-      LLVMValue::jint_constant(monitor_count() - 1), index),
-  };
-  return new SharkMonitor(
-    this,
-    builder()->CreateGEP(monitors_slots(), indexes, indexes + 2));
-}
-
 class DeferredZeroCheck : public ResourceObj {
  public:
   DeferredZeroCheck(SharkTopLevelBlock* block, SharkValue* value)
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkFunction.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkFunction.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkFunction.hpp	Wed May 27 14:59:07 2009 +0100
@@ -23,7 +23,6 @@
  *
  */
 
-class SharkMonitor;
 class SharkTopLevelBlock;
 
 class DeferredZeroCheck;
@@ -55,7 +54,7 @@
   SharkTopLevelBlock**              _blocks;
   llvm::Value*                      _base_pc;
   llvm::Value*                      _thread;
-  int                               _monitor_count;
+  int                               _max_monitors;
   GrowableArray<DeferredZeroCheck*> _deferred_zero_checks;
 
  public:  
@@ -95,9 +94,9 @@
   {
     return _thread;
   }
-  int monitor_count() const
+  int max_monitors() const
   {
-    return _monitor_count;
+    return _max_monitors;
   }
   GrowableArray<DeferredZeroCheck*>* deferred_zero_checks()
   {
@@ -215,29 +214,6 @@
   llvm::Value* CreateAddressOfFrameEntry(int               offset,
                                          const llvm::Type* type = NULL,
                                          const char*       name = "") const;
- public:
-  llvm::Value* exception_slot() const
-  {
-    return CreateAddressOfFrameEntry(
-      exception_slot_offset(),
-      SharkType::oop_type(),
-      "exception_slot");
-  }
-  llvm::Value* monitors_slots() const
-  {
-    return CreateAddressOfFrameEntry(
-      monitors_slots_offset(),
-      llvm::ArrayType::get(SharkType::monitor_type(), monitor_count()),
-      "monitors");
-  }
-
- public:
-  SharkMonitor* monitor(int index) const
-  {
-    return monitor(LLVMValue::jint_constant(index));
-  }
-  SharkMonitor* monitor(llvm::Value* index) const;
-
  private:
   llvm::Value* CreateBuildFrame();
 
@@ -256,7 +232,7 @@
   int _extended_frame_size;
   int _stack_slots_offset;
   int _monitors_slots_offset;
-  int _exception_slot_offset;
+  int _oop_tmp_slot_offset;
   int _method_slot_offset;
   int _pc_slot_offset;
   int _locals_slots_offset;
@@ -274,13 +250,9 @@
   {
     return _stack_slots_offset;
   }
-  int monitors_slots_offset() const
+  int oop_tmp_slot_offset() const
   {
-    return _monitors_slots_offset;
-  }
-  int exception_slot_offset() const
-  {
-    return _exception_slot_offset;
+    return _oop_tmp_slot_offset;
   }
   int method_slot_offset() const
   {
@@ -295,6 +267,49 @@
     return _locals_slots_offset;
   }
 
+  // Monitors
+ public:
+  int monitor_offset(int index) const
+  {
+    assert(index >= 0 && index < max_monitors(), "invalid monitor index");
+    return _monitors_slots_offset +
+      (max_monitors() - 1 - index) * frame::interpreter_frame_monitor_size();
+  }
+  int monitor_object_offset(int index) const
+  {
+    return monitor_offset(index) +
+      (BasicObjectLock::obj_offset_in_bytes() >> LogBytesPerWord);
+  }
+  int monitor_header_offset(int index) const
+  {
+    return monitor_offset(index) +
+      ((BasicObjectLock::lock_offset_in_bytes() +
+        BasicLock::displaced_header_offset_in_bytes()) >> LogBytesPerWord);
+  }
+
+ public:
+  llvm::Value* monitor_addr(int index) const
+  {
+    return CreateAddressOfFrameEntry(
+      monitor_offset(index),
+      SharkType::monitor_type(),
+      "monitor");
+  }
+  llvm::Value* monitor_object_addr(int index) const
+  {
+    return CreateAddressOfFrameEntry(
+      monitor_object_offset(index),
+      SharkType::oop_type(),
+      "object_addr");
+  }
+  llvm::Value* monitor_header_addr(int index) const
+  {
+    return CreateAddressOfFrameEntry(
+      monitor_header_offset(index),
+      SharkType::intptr_type(),
+      "displaced_header_addr");
+  }
+
   // VM interface
  private:
   llvm::StoreInst* CreateStoreLastJavaSP(llvm::Value* value) const
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkMonitor.cpp
--- a/ports/hotspot/src/share/vm/shark/sharkMonitor.cpp	Wed May 27 13:49:38 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,170 +0,0 @@
-/*
- * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
- * Copyright 2008 Red Hat, Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- */
-
-#include "incls/_precompiled.incl"
-#include "incls/_sharkMonitor.cpp.incl"
-
-using namespace llvm;
-
-void SharkMonitor::initialize()
-{
-  _object_addr = builder()->CreateAddressOfStructEntry(
-    monitor(), in_ByteSize(BasicObjectLock::obj_offset_in_bytes()),
-    PointerType::getUnqual(SharkType::oop_type()),
-    "object_addr");
-
-  _displaced_header_addr = builder()->CreateAddressOfStructEntry(
-    monitor(), in_ByteSize(
-      BasicObjectLock::lock_offset_in_bytes() +
-      BasicLock::displaced_header_offset_in_bytes()),
-    PointerType::getUnqual(SharkType::intptr_type()),
-    "displaced_header_addr");
-}
-
-void SharkMonitor::acquire(SharkTopLevelBlock* block, Value *lockee) const
-{
-  BasicBlock *try_recursive = function()->CreateBlock("try_recursive");
-  BasicBlock *got_recursive = function()->CreateBlock("got_recursive");
-  BasicBlock *not_recursive = function()->CreateBlock("not_recursive");
-  BasicBlock *acquired_fast = function()->CreateBlock("acquired_fast");
-  BasicBlock *lock_acquired = function()->CreateBlock("lock_acquired");
-
-  set_object(lockee);
-
-  Value *lock = builder()->CreatePtrToInt(
-    displaced_header_addr(), SharkType::intptr_type());
-
-  Value *mark_addr = builder()->CreateAddressOfStructEntry(
-    lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()),
-    PointerType::getUnqual(SharkType::intptr_type()),
-    "mark_addr");
-
-  Value *mark = builder()->CreateLoad(mark_addr, "mark");
-  Value *disp = builder()->CreateOr(
-    mark, LLVMValue::intptr_constant(markOopDesc::unlocked_value), "disp");
-  set_displaced_header(disp);
-
-  // Try a simple lock
-  Value *check = builder()->CreateCmpxchgPtr(lock, mark_addr, disp);
-  builder()->CreateCondBr(
-    builder()->CreateICmpEQ(disp, check),
-    acquired_fast, try_recursive);
-
-  // Locking failed, but maybe this thread already owns it
-  builder()->SetInsertPoint(try_recursive);
-  Value *addr = builder()->CreateAnd(
-    disp,
-    LLVMValue::intptr_constant(~markOopDesc::lock_mask_in_place));
-
-  // NB we use the entire stack, but JavaThread::is_lock_owned()
-  // uses a more limited range.  I don't think it hurts though...
-  Value *stack_limit = builder()->CreateValueOfStructEntry(
-    function()->thread(), Thread::stack_base_offset(),
-    SharkType::intptr_type(),
-    "stack_limit");
-
-  assert(sizeof(size_t) == sizeof(intptr_t), "should be");
-  Value *stack_size = builder()->CreateValueOfStructEntry(
-    function()->thread(), Thread::stack_size_offset(),
-    SharkType::intptr_type(),
-    "stack_size");
-
-  Value *stack_start =
-    builder()->CreateSub(stack_limit, stack_size, "stack_start");
-
-  builder()->CreateCondBr(
-    builder()->CreateAnd(
-      builder()->CreateICmpUGE(addr, stack_start),
-      builder()->CreateICmpULT(addr, stack_limit)),
-    got_recursive, not_recursive);
-                         
-  builder()->SetInsertPoint(got_recursive);
-  set_displaced_header(LLVMValue::intptr_constant(0));
-  builder()->CreateBr(acquired_fast);
-
-  // Create an edge for the state merge
-  builder()->SetInsertPoint(acquired_fast);
-  SharkState *fast_state = block->current_state()->copy();
-  builder()->CreateBr(lock_acquired);
-
-  // It's not a recursive case so we need to drop into the runtime
-  builder()->SetInsertPoint(not_recursive);
-  block->call_vm_nocheck(SharkRuntime::monitorenter(), monitor());
-  BasicBlock *acquired_slow = builder()->GetInsertBlock();
-  builder()->CreateBr(lock_acquired);  
-
-  // All done
-  builder()->SetInsertPoint(lock_acquired);
-  block->current_state()->merge(fast_state, acquired_fast, acquired_slow);
-}
-
-void SharkMonitor::release(SharkTopLevelBlock* block) const
-{
-  BasicBlock *not_recursive = function()->CreateBlock("not_recursive");
-  BasicBlock *released_fast = function()->CreateBlock("released_fast");
-  BasicBlock *slow_path     = function()->CreateBlock("slow_path");
-  BasicBlock *lock_released = function()->CreateBlock("lock_released");
-
-  Value *disp = displaced_header();
-  Value *lockee = object();
-  set_object(LLVMValue::null());
-
-  // If it is recursive then we're already done
-  builder()->CreateCondBr(
-    builder()->CreateICmpEQ(disp, LLVMValue::intptr_constant(0)),
-    released_fast, not_recursive);
-
-  // Try a simple unlock
-  builder()->SetInsertPoint(not_recursive);
-
-  Value *lock = builder()->CreatePtrToInt(
-    displaced_header_addr(), SharkType::intptr_type());
-
-  Value *mark_addr = builder()->CreateAddressOfStructEntry(
-    lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()),
-    PointerType::getUnqual(SharkType::intptr_type()),
-    "mark_addr");
-
-  Value *check = builder()->CreateCmpxchgPtr(disp, mark_addr, lock);
-  builder()->CreateCondBr(
-    builder()->CreateICmpEQ(lock, check),
-    released_fast, slow_path);
-
-  // Create an edge for the state merge
-  builder()->SetInsertPoint(released_fast);
-  SharkState *fast_state = block->current_state()->copy();
-  builder()->CreateBr(lock_released);  
-
-  // Need to drop into the runtime to release this one
-  builder()->SetInsertPoint(slow_path);
-  set_object(lockee);
-  block->call_vm_nocheck(SharkRuntime::monitorexit(), monitor());
-  BasicBlock *released_slow = builder()->GetInsertBlock();
-  builder()->CreateBr(lock_released);  
-
-  // All done
-  builder()->SetInsertPoint(lock_released);
-  block->current_state()->merge(fast_state, released_fast, released_slow);
-}
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkMonitor.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkMonitor.hpp	Wed May 27 13:49:38 2009 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,94 +0,0 @@
-/*
- * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
- * Copyright 2008 Red Hat, Inc.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- *
- */
-
-class SharkTopLevelBlock;
-
-class SharkMonitor : public ResourceObj {
- public:
-  SharkMonitor(const SharkFunction* function, llvm::Value* monitor)
-    : _function(function), _monitor(monitor)
-  { initialize(); }
-
- private:
-  void initialize();
-
- private:
-  const SharkFunction* _function;
-  llvm::Value*         _monitor;
-  llvm::Value*         _object_addr;
-  llvm::Value*         _displaced_header_addr;
-
- private:
-  const SharkFunction* function() const
-  {
-    return _function;
-  }
-  llvm::Value* monitor() const
-  {
-    return _monitor;
-  }
-  llvm::Value* object_addr() const
-  {
-    return _object_addr;
-  }
-  llvm::Value* displaced_header_addr() const
-  {
-    return _displaced_header_addr;
-  }
-
- public:
-  SharkBuilder* builder() const
-  {
-    return function()->builder();
-  }
-
- public:
-  llvm::Value* object() const
-  {
-    return builder()->CreateLoad(object_addr());
-  }
-  void set_object(llvm::Value* object) const
-  {
-    builder()->CreateStore(object, object_addr());
-  }
-  llvm::Value* displaced_header() const
-  {
-    return builder()->CreateLoad(displaced_header_addr());
-  }
-  void set_displaced_header(llvm::Value* displaced_header) const
-  {
-    builder()->CreateStore(displaced_header, displaced_header_addr());
-  }
-
- public:
-  void mark_free() const
-  {
-    set_object(LLVMValue::null());
-  }
-
- public:
-  void acquire(SharkTopLevelBlock* block, llvm::Value* lockee) const;
-  void release(SharkTopLevelBlock* block) const;
-};
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkState.cpp
--- a/ports/hotspot/src/share/vm/shark/sharkState.cpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkState.cpp	Wed May 27 14:59:07 2009 +0100
@@ -32,6 +32,7 @@
   : _block(block),
     _function(function),
     _method(NULL),
+    _oop_tmp(NULL),
     _frame_cache(NULL)
 {
   initialize(NULL);
@@ -41,6 +42,7 @@
   : _block(block),
     _function(state->function()),
     _method(state->method()),
+    _oop_tmp(state->oop_tmp()),
     _frame_cache(NULL)
 {
   initialize(state);
@@ -76,6 +78,8 @@
   else if (function()) {
     _frame_cache = new SharkFrameCache(function());
   }
+
+  set_num_monitors(state ? state->num_monitors() : 0);
 }
 
 bool SharkState::equal_to(SharkState *other)
@@ -89,12 +93,18 @@
   if (method() != other->method())
     return false;
 
+  if (oop_tmp() != other->oop_tmp())
+    return false;
+
   if (max_locals() != other->max_locals())
     return false;
 
   if (stack_depth() != other->stack_depth())
     return false;
 
+  if (num_monitors() != other->num_monitors())
+    return false;
+
   // Local variables
   for (int i = 0; i < max_locals(); i++) {
     SharkValue *value = local(i);
@@ -161,6 +171,20 @@
     set_method(phi);
   }
 
+  // Temporary oop slot
+  Value *this_oop_tmp = this->oop_tmp();
+  Value *other_oop_tmp = other->oop_tmp();
+  if (this_oop_tmp != other_oop_tmp) {
+    assert(this_oop_tmp && other_oop_tmp, "can't merge NULL with non-NULL");
+    PHINode *phi = builder()->CreatePHI(SharkType::oop_type(), "oop_tmp");
+    phi->addIncoming(this_oop_tmp, this_block);
+    phi->addIncoming(other_oop_tmp, other_block);
+    set_oop_tmp(phi);
+  }
+
+  // Monitors
+  assert(this->num_monitors() == other->num_monitors(), "should be");
+
   // Local variables
   assert(this->max_locals() == other->max_locals(), "should be");
   for (int i = 0; i < max_locals(); i++) {
@@ -365,6 +389,9 @@
     push(value);
   }
 
+  // Monitors
+  set_num_monitors(block->ciblock()->monitor_count());
+
   builder()->SetInsertPoint(saved_insert_point);    
 }
 
@@ -389,4 +416,10 @@
     if (stack(i))
       stack(i)->addIncoming(incoming_state->stack(i), predecessor);
   }    
+
+  // Monitors
+  assert(num_monitors() == incoming_state->num_monitors(), "should be");
+
+  // Temporary oop slot
+  assert(oop_tmp() == incoming_state->oop_tmp(), "should be");  
 }
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkState.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkState.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkState.hpp	Wed May 27 14:59:07 2009 +0100
@@ -43,6 +43,8 @@
   SharkValue**     _locals;
   SharkValue**     _stack;
   SharkValue**     _sp;
+  int              _num_monitors;
+  llvm::Value*     _oop_tmp;
 
  public:
   SharkBlock *block() const
@@ -62,6 +64,7 @@
   inline SharkBuilder* builder() const;
   inline int max_locals() const;
   inline int max_stack() const;
+  inline int max_monitors() const;
 
   // Method
  public:
@@ -132,6 +135,32 @@
     _sp -= slots;
   }
 
+  // Monitors
+ public:
+  int num_monitors() const
+  {
+    return _num_monitors;
+  }
+  void set_num_monitors(int num_monitors)
+  {
+    _num_monitors = num_monitors;
+  }
+
+  // Temporary oop slot
+ public:
+  llvm::Value** oop_tmp_addr()
+  {
+    return &_oop_tmp;
+  }
+  llvm::Value* oop_tmp() const
+  {
+    return _oop_tmp;
+  }
+  void set_oop_tmp(llvm::Value* oop_tmp)
+  {
+    _oop_tmp = oop_tmp;
+  }
+
   // Comparison
  public:
   bool equal_to(SharkState* other);
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkState.inline.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkState.inline.hpp	Wed May 27 14:59:07 2009 +0100
@@ -37,3 +37,8 @@
 {
   return block()->max_stack();
 }
+
+inline int SharkState::max_monitors() const
+{
+  return function()->max_monitors();
+}
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp
--- a/ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkStateScanner.cpp	Wed May 27 14:59:07 2009 +0100
@@ -1,6 +1,6 @@
 /*
  * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
- * Copyright 2008 Red Hat, Inc.
+ * Copyright 2008, 2009 Red Hat, Inc.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -45,18 +45,19 @@
   end_stack();
 
   // Monitors
-  start_monitors(function()->monitor_count());
-  for (int i = 0; i < function()->monitor_count(); i++) {
+  start_monitors(state->num_monitors());
+  for (int i = 0; i < state->num_monitors(); i++) {
     process_monitor(
       i,
-      function()->monitors_slots_offset() +
-        i * frame::interpreter_frame_monitor_size());
+      function()->monitor_offset(i),
+      function()->monitor_object_offset(i));
   }
   end_monitors();
 
   // Frame header
   start_frame_header();
-  process_exception_slot(function()->exception_slot_offset());
+  process_oop_tmp_slot(
+    state->oop_tmp_addr(), function()->oop_tmp_slot_offset());
   process_method_slot(state->method_addr(), function()->method_slot_offset());
   process_pc_slot(function()->pc_slot_offset());
   end_frame_header();
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkStateScanner.hpp	Wed May 27 14:59:07 2009 +0100
@@ -1,6 +1,6 @@
 /*
  * Copyright 1999-2007 Sun Microsystems, Inc.  All Rights Reserved.
- * Copyright 2008 Red Hat, Inc.
+ * Copyright 2008, 2009 Red Hat, Inc.
  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  *
  * This code is free software; you can redistribute it and/or modify it
@@ -54,11 +54,11 @@
   virtual void end_stack()                                                   {}
 
   virtual void start_monitors(int num_monitors)                              {}
-  virtual void process_monitor(int index, int offset)                        {}
+  virtual void process_monitor(int index, int box_offset, int obj_offset)    {}
   virtual void end_monitors()                                                {}
 
   virtual void start_frame_header()                                          {}
-  virtual void process_exception_slot(int offset)                            {}
+  virtual void process_oop_tmp_slot(llvm::Value** value, int offset)         {}
   virtual void process_method_slot(llvm::Value** value, int offset)          {}
   virtual void process_pc_slot(int offset)                                   {}
   virtual void end_frame_header()                                            {}
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp
--- a/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.cpp	Wed May 27 14:59:07 2009 +0100
@@ -205,34 +205,6 @@
   _entry_block = function()->CreateBlock(name);
 }
 
-void SharkTopLevelBlock::acquire_method_lock()
-{
-  Value *object;
-  if (target()->is_static()) {
-    SharkConstantPool constants(this);
-    object = constants.java_mirror();
-  }
-  else {
-    object = local(0)->jobject_value();
-  }
-  iter()->force_bci(start()); // for the decache
-  function()->monitor(0)->acquire(this, object);
-  check_pending_exception(false);
-}
-
-void SharkTopLevelBlock::release_method_lock()
-{
-  function()->monitor(0)->release(this);
-
-  // We neither need nor want to check for pending exceptions here.
-  // This method is only called by handle_return, which copes with
-  // them implicitly:
-  //  - if a value is being returned then we just carry on as normal;
-  //    the caller will see the pending exception and handle it.
-  //  - if an exception is being thrown then that exception takes
-  //    priority and ours will be ignored.
-}
-
 void SharkTopLevelBlock::emit_IR()
 {
   builder()->SetInsertPoint(entry_block());
@@ -544,15 +516,25 @@
 {
   assert (exception == NULL || type == T_VOID, "exception OR result, please");
 
-  if (exception)
-    builder()->CreateStore(exception, function()->exception_slot());
+  if (num_monitors()) {
+    // Protect our exception across possible monitor release decaches
+    if (exception)
+      set_oop_tmp(exception);
 
-  release_locked_monitors();
-  if (target()->is_synchronized())
-    release_method_lock();
-  
+    // We don't need to check for exceptions thrown here.  If
+    // we're returning a value then we just carry on as normal:
+    // the caller will see the pending exception and handle it.
+    // If we're returning with an exception then that exception
+    // takes priority and the release_lock one will be ignored.
+    while (num_monitors())
+      release_lock();
+
+    // Reload the exception we're throwing
+    if (exception)
+      exception = get_oop_tmp();
+  }
+
   if (exception) {
-    exception = builder()->CreateLoad(function()->exception_slot());
     builder()->CreateStore(exception, function()->pending_exception_address());
   }
 
@@ -568,26 +550,6 @@
   builder()->CreateRetVoid();
 }
 
-void SharkTopLevelBlock::release_locked_monitors()
-{
-  int base = target()->is_synchronized();
-  for (int i = function()->monitor_count() - 1; i >= base; i--) {
-    BasicBlock *locked   = function()->CreateBlock("locked");
-    BasicBlock *unlocked = function()->CreateBlock("unlocked");
-
-    Value *object = function()->monitor(i)->object();
-    builder()->CreateCondBr(
-      builder()->CreateICmpNE(object, LLVMValue::null()),
-      locked, unlocked);
-    
-    builder()->SetInsertPoint(locked);
-    builder()->CreateUnimplemented(__FILE__, __LINE__);
-    builder()->CreateUnreachable();
-
-    builder()->SetInsertPoint(unlocked);
-  }
-}
-
 Value *SharkTopLevelBlock::lookup_for_ldc()
 {
   int index = iter()->get_constant_index();
@@ -1583,102 +1545,166 @@
     array_klass, function()->CreateGetVMResult(), true));
 }
 
+void SharkTopLevelBlock::acquire_method_lock()
+{
+  iter()->force_bci(start()); // for the decache in acquire_lock
+  if (target()->is_static()) {
+    SharkConstantPool constants(this);
+    acquire_lock(constants.java_mirror());
+  }
+  else {
+    acquire_lock(local(0)->jobject_value());
+  }
+  check_pending_exception(false);
+}
+
 void SharkTopLevelBlock::do_monitorenter()
 {
   SharkValue *lockee = pop();
   check_null(lockee);
-  Value *object = lockee->jobject_value();
-
-  // Find a free monitor, or one already allocated for this object
-  BasicBlock *loop_top    = function()->CreateBlock("loop_top");
-  BasicBlock *loop_iter   = function()->CreateBlock("loop_iter");
-  BasicBlock *loop_check  = function()->CreateBlock("loop_check");
-  BasicBlock *no_monitor  = function()->CreateBlock("no_monitor");
-  BasicBlock *got_monitor = function()->CreateBlock("got_monitor");
-
-  BasicBlock *entry_block = builder()->GetInsertBlock();
-  builder()->CreateBr(loop_check);
-
-  builder()->SetInsertPoint(loop_check);
-  PHINode *index = builder()->CreatePHI(SharkType::jint_type(), "index");
-  index->addIncoming(
-    LLVMValue::jint_constant(function()->monitor_count() - 1), entry_block);
-  builder()->CreateCondBr(
-    builder()->CreateICmpUGE(index, LLVMValue::jint_constant(0)),
-    loop_top, no_monitor);
-
-  builder()->SetInsertPoint(loop_top);
-  SharkMonitor* monitor = function()->monitor(index);
-  Value *smo = monitor->object();
-  builder()->CreateCondBr(
-    builder()->CreateOr(
-      builder()->CreateICmpEQ(smo, LLVMValue::null()),
-      builder()->CreateICmpEQ(smo, object)),
-    got_monitor, loop_iter);
-
-  builder()->SetInsertPoint(loop_iter);
-  index->addIncoming(
-    builder()->CreateSub(index, LLVMValue::jint_constant(1)), loop_iter);
-  builder()->CreateBr(loop_check);
-
-  builder()->SetInsertPoint(no_monitor);
-  builder()->CreateShouldNotReachHere(__FILE__, __LINE__);
-  builder()->CreateUnreachable();
-
-  // Acquire the lock
-  builder()->SetInsertPoint(got_monitor);
-  monitor->acquire(this, object);
-  check_pending_exception();
+  acquire_lock(lockee->jobject_value());
 }
 
 void SharkTopLevelBlock::do_monitorexit()
 {
-  SharkValue *lockee = pop();
-  // The monitorexit can't throw an NPE because the verifier checks
-  // that the monitor operations are block structured before we
-  // compile.
-  // check_null(lockee);
-  Value *object = lockee->jobject_value();
+  pop(); // don't need this (monitors are block structured)
+  release_lock();
+}
 
-  // Find the monitor associated with this object
-  BasicBlock *loop_top    = function()->CreateBlock("loop_top");
-  BasicBlock *loop_iter   = function()->CreateBlock("loop_iter");
-  BasicBlock *loop_check  = function()->CreateBlock("loop_check");
-  BasicBlock *no_monitor  = function()->CreateBlock("no_monitor");
-  BasicBlock *got_monitor = function()->CreateBlock("got_monitor");
+void SharkTopLevelBlock::acquire_lock(Value *lockee)
+{
+  BasicBlock *try_recursive = function()->CreateBlock("try_recursive");
+  BasicBlock *got_recursive = function()->CreateBlock("got_recursive");
+  BasicBlock *not_recursive = function()->CreateBlock("not_recursive");
+  BasicBlock *acquired_fast = function()->CreateBlock("acquired_fast");
+  BasicBlock *lock_acquired = function()->CreateBlock("lock_acquired");
 
-  BasicBlock *entry_block = builder()->GetInsertBlock();
-  builder()->CreateBr(loop_check);
+  int monitor = num_monitors();
+  Value *monitor_addr        = function()->monitor_addr(monitor);
+  Value *monitor_object_addr = function()->monitor_object_addr(monitor);
+  Value *monitor_header_addr = function()->monitor_header_addr(monitor);
 
-  builder()->SetInsertPoint(loop_check);
-  PHINode *index = builder()->CreatePHI(SharkType::jint_type(), "index");
-  index->addIncoming(
-    LLVMValue::jint_constant(function()->monitor_count() - 1), entry_block);
+  // Store the object and mark the slot as live
+  builder()->CreateStore(lockee, monitor_object_addr);
+  set_num_monitors(monitor + 1);
+
+  // Try a simple lock
+  Value *mark_addr = builder()->CreateAddressOfStructEntry(
+    lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()),
+    PointerType::getUnqual(SharkType::intptr_type()),
+    "mark_addr");
+
+  Value *mark = builder()->CreateLoad(mark_addr, "mark");
+  Value *disp = builder()->CreateOr(
+    mark, LLVMValue::intptr_constant(markOopDesc::unlocked_value), "disp");
+  builder()->CreateStore(disp, monitor_header_addr);
+
+  Value *lock = builder()->CreatePtrToInt(
+    monitor_header_addr, SharkType::intptr_type());
+  Value *check = builder()->CreateCmpxchgPtr(lock, mark_addr, disp);
   builder()->CreateCondBr(
-    builder()->CreateICmpUGE(index, LLVMValue::jint_constant(0)),
-    loop_top, no_monitor);
+    builder()->CreateICmpEQ(disp, check),
+    acquired_fast, try_recursive);
 
-  builder()->SetInsertPoint(loop_top);
-  SharkMonitor* monitor = function()->monitor(index);
-  Value *smo = monitor->object();
+  // Locking failed, but maybe this thread already owns it
+  builder()->SetInsertPoint(try_recursive);
+  Value *addr = builder()->CreateAnd(
+    disp,
+    LLVMValue::intptr_constant(~markOopDesc::lock_mask_in_place));
+
+  // NB we use the entire stack, but JavaThread::is_lock_owned()
+  // uses a more limited range.  I don't think it hurts though...
+  Value *stack_limit = builder()->CreateValueOfStructEntry(
+    function()->thread(), Thread::stack_base_offset(),
+    SharkType::intptr_type(),
+    "stack_limit");
+
+  assert(sizeof(size_t) == sizeof(intptr_t), "should be");
+  Value *stack_size = builder()->CreateValueOfStructEntry(
+    function()->thread(), Thread::stack_size_offset(),
+    SharkType::intptr_type(),
+    "stack_size");
+
+  Value *stack_start =
+    builder()->CreateSub(stack_limit, stack_size, "stack_start");
+
   builder()->CreateCondBr(
-    builder()->CreateICmpEQ(smo, object),
-    got_monitor, loop_iter);
+    builder()->CreateAnd(
+      builder()->CreateICmpUGE(addr, stack_start),
+      builder()->CreateICmpULT(addr, stack_limit)),
+    got_recursive, not_recursive);
 
-  builder()->SetInsertPoint(loop_iter);
-  index->addIncoming(
-    builder()->CreateSub(index, LLVMValue::jint_constant(1)), loop_iter);
-  builder()->CreateBr(loop_check);
+  builder()->SetInsertPoint(got_recursive);
+  builder()->CreateStore(LLVMValue::intptr_constant(0), monitor_header_addr);
+  builder()->CreateBr(acquired_fast);
 
-  builder()->SetInsertPoint(no_monitor);
-  builder()->CreateShouldNotReachHere(__FILE__, __LINE__);
-  builder()->CreateUnreachable();
+  // Create an edge for the state merge
+  builder()->SetInsertPoint(acquired_fast);
+  SharkState *fast_state = current_state()->copy();
+  builder()->CreateBr(lock_acquired);
 
-  // Release the lock
-  builder()->SetInsertPoint(got_monitor);
-  monitor->release(this);
-  // The monitorexit can't throw an NPE because the verifier checks
-  // that the monitor operations are block structured before we
-  // compile.
-  // check_pending_exception();
+  // It's not a recursive case so we need to drop into the runtime
+  builder()->SetInsertPoint(not_recursive);
+  call_vm_nocheck(SharkRuntime::monitorenter(), monitor_addr);
+  BasicBlock *acquired_slow = builder()->GetInsertBlock();
+  builder()->CreateBr(lock_acquired);  
+
+  // All done
+  builder()->SetInsertPoint(lock_acquired);
+  current_state()->merge(fast_state, acquired_fast, acquired_slow);
 }
+
+void SharkTopLevelBlock::release_lock()
+{
+  BasicBlock *not_recursive = function()->CreateBlock("not_recursive");
+  BasicBlock *released_fast = function()->CreateBlock("released_fast");
+  BasicBlock *slow_path     = function()->CreateBlock("slow_path");
+  BasicBlock *lock_released = function()->CreateBlock("lock_released");
+
+  int monitor = num_monitors() - 1;
+  Value *monitor_addr        = function()->monitor_addr(monitor);
+  Value *monitor_object_addr = function()->monitor_object_addr(monitor);
+  Value *monitor_header_addr = function()->monitor_header_addr(monitor);
+
+  // If it is recursive then we're already done
+  Value *disp = builder()->CreateLoad(monitor_header_addr);
+  builder()->CreateCondBr(
+    builder()->CreateICmpEQ(disp, LLVMValue::intptr_constant(0)),
+    released_fast, not_recursive);
+
+  // Try a simple unlock
+  builder()->SetInsertPoint(not_recursive);
+
+  Value *lock = builder()->CreatePtrToInt(
+    monitor_header_addr, SharkType::intptr_type());
+
+  Value *lockee = builder()->CreateLoad(monitor_object_addr);
+
+  Value *mark_addr = builder()->CreateAddressOfStructEntry(
+    lockee, in_ByteSize(oopDesc::mark_offset_in_bytes()),
+    PointerType::getUnqual(SharkType::intptr_type()),
+    "mark_addr");
+
+  Value *check = builder()->CreateCmpxchgPtr(disp, mark_addr, lock);
+  builder()->CreateCondBr(
+    builder()->CreateICmpEQ(lock, check),
+    released_fast, slow_path);
+
+  // Create an edge for the state merge
+  builder()->SetInsertPoint(released_fast);
+  SharkState *fast_state = current_state()->copy();
+  builder()->CreateBr(lock_released);  
+
+  // Need to drop into the runtime to release this one
+  builder()->SetInsertPoint(slow_path);
+  call_vm_nocheck(SharkRuntime::monitorexit(), monitor_addr);
+  BasicBlock *released_slow = builder()->GetInsertBlock();
+  builder()->CreateBr(lock_released);  
+
+  // All done
+  builder()->SetInsertPoint(lock_released);
+  current_state()->merge(fast_state, released_fast, released_slow);
+
+  // The object slot is now dead
+  set_num_monitors(monitor);
+}
diff -r b22d229ddbcf ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp
--- a/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp	Wed May 27 13:49:38 2009 +0100
+++ b/ports/hotspot/src/share/vm/shark/sharkTopLevelBlock.hpp	Wed May 27 14:59:07 2009 +0100
@@ -189,6 +189,33 @@
     return current_state()->method();
   }
 
+  // Temporary oop storage
+ public:
+  void set_oop_tmp(llvm::Value* value)
+  {
+    assert(value, "value must be non-NULL (will be reset by get_oop_tmp)");
+    assert(!current_state()->oop_tmp(), "oop_tmp gets and sets must match");
+    current_state()->set_oop_tmp(value);
+  }
+  llvm::Value* get_oop_tmp()
+  {
+    llvm::Value* value = current_state()->oop_tmp();
+    assert(value, "oop_tmp gets and sets must match");
+    current_state()->set_oop_tmp(NULL);
+    return value;
+  }
+
+  // Monitors
+ private:
+  int num_monitors()
+  {
+    return current_state()->num_monitors();
+  }
+  int set_num_monitors(int num_monitors)
+  {
+    current_state()->set_num_monitors(num_monitors);
+  }
+
   // Code generation
  public:
   void emit_IR();
@@ -288,10 +315,13 @@
     return call_vm_nocheck(callee, args, args + 4);
   }
 
-  // Whole-method synchronization
+  // Synchronization
+ private:
+  void acquire_lock(llvm::Value* lockee);
+  void release_lock();
+
  public:
-  void acquire_method_lock();  
-  void release_method_lock();  
+  void acquire_method_lock();
 
   // Error checking
  private:
@@ -311,7 +341,6 @@
  private:
   void call_register_finalizer(llvm::Value* receiver);
   void handle_return(BasicType type, llvm::Value* exception);
-  void release_locked_monitors();
 
   // arraylength
  private:


More information about the distro-pkg-dev mailing list