8166317: InterpreterCodeSize should be computed
authorsimonis
Mon, 04 Sep 2017 19:50:01 +0200
changeset 47688 3d1e3786d66e
parent 47687 fb290fd1f9d4
child 47689 54b78d6243c5
child 47690 bba11a95e927
8166317: InterpreterCodeSize should be computed Reviewed-by: kvn, coleenp
src/hotspot/cpu/sparc/macroAssembler_sparc.cpp
src/hotspot/share/code/codeBlob.hpp
src/hotspot/share/code/codeCache.cpp
src/hotspot/share/code/codeCache.hpp
src/hotspot/share/code/stubs.cpp
src/hotspot/share/code/stubs.hpp
src/hotspot/share/interpreter/templateInterpreter.cpp
src/hotspot/share/memory/heap.cpp
src/hotspot/share/memory/heap.hpp
src/hotspot/share/runtime/init.cpp
--- a/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/cpu/sparc/macroAssembler_sparc.cpp	Mon Sep 04 19:50:01 2017 +0200
@@ -3575,20 +3575,6 @@
 #undef __
 }
 
-static inline void generate_satb_log_enqueue_if_necessary(bool with_frame) {
-  if (with_frame) {
-    if (satb_log_enqueue_with_frame == 0) {
-      generate_satb_log_enqueue(with_frame);
-      assert(satb_log_enqueue_with_frame != 0, "postcondition.");
-    }
-  } else {
-    if (satb_log_enqueue_frameless == 0) {
-      generate_satb_log_enqueue(with_frame);
-      assert(satb_log_enqueue_frameless != 0, "postcondition.");
-    }
-  }
-}
-
 void MacroAssembler::g1_write_barrier_pre(Register obj,
                                           Register index,
                                           int offset,
@@ -3658,13 +3644,9 @@
             "Or we need to think harder.");
 
   if (pre_val->is_global() && !preserve_o_regs) {
-    generate_satb_log_enqueue_if_necessary(true); // with frame
-
     call(satb_log_enqueue_with_frame);
     delayed()->mov(pre_val, O0);
   } else {
-    generate_satb_log_enqueue_if_necessary(false); // frameless
-
     save_frame(0);
     call(satb_log_enqueue_frameless);
     delayed()->mov(pre_val->after_save(), O0);
@@ -3768,15 +3750,6 @@
 
 }
 
-static inline void
-generate_dirty_card_log_enqueue_if_necessary(jbyte* byte_map_base) {
-  if (dirty_card_log_enqueue == 0) {
-    generate_dirty_card_log_enqueue(byte_map_base);
-    assert(dirty_card_log_enqueue != 0, "postcondition.");
-  }
-}
-
-
 void MacroAssembler::g1_write_barrier_post(Register store_addr, Register new_val, Register tmp) {
 
   Label filtered;
@@ -3806,7 +3779,6 @@
   } else {
     post_filter_masm->nop();
   }
-  generate_dirty_card_log_enqueue_if_necessary(bs->byte_map_base);
   save_frame(0);
   call(dirty_card_log_enqueue);
   if (use_scr) {
@@ -3819,6 +3791,28 @@
   bind(filtered);
 }
 
+// Called from init_globals() after universe_init() and before interpreter_init()
+void g1_barrier_stubs_init() {
+  CollectedHeap* heap = Universe::heap();
+  if (heap->kind() == CollectedHeap::G1CollectedHeap) {
+    // Only needed for G1
+    if (dirty_card_log_enqueue == 0) {
+      G1SATBCardTableLoggingModRefBS* bs =
+        barrier_set_cast<G1SATBCardTableLoggingModRefBS>(heap->barrier_set());
+      generate_dirty_card_log_enqueue(bs->byte_map_base);
+      assert(dirty_card_log_enqueue != 0, "postcondition.");
+    }
+    if (satb_log_enqueue_with_frame == 0) {
+      generate_satb_log_enqueue(true);
+      assert(satb_log_enqueue_with_frame != 0, "postcondition.");
+    }
+    if (satb_log_enqueue_frameless == 0) {
+      generate_satb_log_enqueue(false);
+      assert(satb_log_enqueue_frameless != 0, "postcondition.");
+    }
+  }
+}
+
 #endif // INCLUDE_ALL_GCS
 ///////////////////////////////////////////////////////////////////////////////////
 
--- a/src/hotspot/share/code/codeBlob.hpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/code/codeBlob.hpp	Mon Sep 04 19:50:01 2017 +0200
@@ -156,6 +156,13 @@
   int relocation_size() const                    { return (address) relocation_end() - (address) relocation_begin(); }
   int content_size() const                       { return           content_end()    -           content_begin();    }
   int code_size() const                          { return           code_end()       -           code_begin();       }
+  // Only used from CodeCache::free_unused_tail() after the Interpreter blob was trimmed
+  void adjust_size(size_t used) {
+    _size = (int)used;
+    _data_offset = (int)used;
+    _code_end = (address)this + used;
+    _data_end = (address)this + used;
+  }
 
   // Containment
   bool blob_contains(address addr) const         { return header_begin()       <= addr && addr < data_end();       }
--- a/src/hotspot/share/code/codeCache.cpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/code/codeCache.cpp	Mon Sep 04 19:50:01 2017 +0200
@@ -569,6 +569,21 @@
   assert(heap->blob_count() >= 0, "sanity check");
 }
 
+void CodeCache::free_unused_tail(CodeBlob* cb, size_t used) {
+  assert_locked_or_safepoint(CodeCache_lock);
+  guarantee(cb->is_buffer_blob() && strncmp("Interpreter", cb->name(), 11) == 0, "Only possible for interpreter!");
+  print_trace("free_unused_tail", cb);
+
+  // We also have to account for the extra space (i.e. header) used by the CodeBlob
+  // which provides the memory (see BufferBlob::create() in codeBlob.cpp).
+  used += CodeBlob::align_code_offset(cb->header_size());
+
+  // Get heap for given CodeBlob and deallocate its unused tail
+  get_code_heap(cb)->deallocate_tail(cb, used);
+  // Adjust the sizes of the CodeBlob
+  cb->adjust_size(used);
+}
+
 void CodeCache::commit(CodeBlob* cb) {
   // this is called by nmethod::nmethod, which must already own CodeCache_lock
   assert_locked_or_safepoint(CodeCache_lock);
--- a/src/hotspot/share/code/codeCache.hpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/code/codeCache.hpp	Mon Sep 04 19:50:01 2017 +0200
@@ -143,6 +143,7 @@
   static int  alignment_unit();                            // guaranteed alignment of all CodeBlobs
   static int  alignment_offset();                          // guaranteed offset of first CodeBlob byte within alignment unit (i.e., allocation header)
   static void free(CodeBlob* cb);                          // frees a CodeBlob
+  static void free_unused_tail(CodeBlob* cb, size_t used); // frees the unused tail of a CodeBlob (only used by TemplateInterpreter::initialize())
   static bool contains(void *p);                           // returns whether p is included
   static bool contains(nmethod* nm);                       // returns whether nm is included
   static void blobs_do(void f(CodeBlob* cb));              // iterates over all CodeBlobs
--- a/src/hotspot/share/code/stubs.cpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/code/stubs.cpp	Mon Sep 04 19:50:01 2017 +0200
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "code/codeBlob.hpp"
+#include "code/codeCache.hpp"
 #include "code/stubs.hpp"
 #include "memory/allocation.inline.hpp"
 #include "oops/oop.inline.hpp"
@@ -89,6 +90,13 @@
   Unimplemented();
 }
 
+void StubQueue::deallocate_unused_tail() {
+  CodeBlob* blob = CodeCache::find_blob((void*)_stub_buffer);
+  CodeCache::free_unused_tail(blob, used_space());
+  // Update the limits to the new, trimmed CodeBlob size
+  _buffer_size = blob->content_size();
+  _buffer_limit = blob->content_size();
+}
 
 Stub* StubQueue::stub_containing(address pc) const {
   if (contains(pc)) {
--- a/src/hotspot/share/code/stubs.hpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/code/stubs.hpp	Mon Sep 04 19:50:01 2017 +0200
@@ -201,12 +201,15 @@
   void  remove_first(int n);                     // remove the first n stubs in the queue
   void  remove_all();                            // remove all stubs in the queue
 
+  void deallocate_unused_tail();                 // deallocate the unused tail of the underlying CodeBlob
+                                                 // only used from TemplateInterpreter::initialize()
   // Iteration
   static void queues_do(void f(StubQueue* s));   // call f with each StubQueue
   void  stubs_do(void f(Stub* s));               // call f with all stubs
   Stub* first() const                            { return number_of_stubs() > 0 ? stub_at(_queue_begin) : NULL; }
   Stub* next(Stub* s) const                      { int i = index_of(s) + stub_size(s);
-                                                   if (i == _buffer_limit) i = 0;
+                                                   // Only wrap around in the non-contiguous case (see stubss.cpp)
+                                                   if (i == _buffer_limit && _queue_end < _buffer_limit) i = 0;
                                                    return (i == _queue_end) ? NULL : stub_at(i);
                                                  }
 
--- a/src/hotspot/share/interpreter/templateInterpreter.cpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/interpreter/templateInterpreter.cpp	Mon Sep 04 19:50:01 2017 +0200
@@ -54,6 +54,8 @@
     _code = new StubQueue(new InterpreterCodeletInterface, code_size, NULL,
                           "Interpreter");
     TemplateInterpreterGenerator g(_code);
+    // Free the unused memory not occupied by the interpreter and the stubs
+    _code->deallocate_unused_tail();
   }
 
   if (PrintInterpreter) {
--- a/src/hotspot/share/memory/heap.cpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/memory/heap.cpp	Mon Sep 04 19:50:01 2017 +0200
@@ -222,6 +222,20 @@
   }
 }
 
+void CodeHeap::deallocate_tail(void* p, size_t used_size) {
+  assert(p == find_start(p), "illegal deallocation");
+  // Find start of HeapBlock
+  HeapBlock* b = (((HeapBlock *)p) - 1);
+  assert(b->allocated_space() == p, "sanity check");
+  size_t used_number_of_segments = size_to_segments(used_size + header_size());
+  size_t actual_number_of_segments = b->length();
+  guarantee(used_number_of_segments <= actual_number_of_segments, "Must be!");
+  guarantee(b == block_at(_next_segment - actual_number_of_segments), "Intermediate allocation!");
+  size_t number_of_segments_to_deallocate = actual_number_of_segments - used_number_of_segments;
+  _next_segment -= number_of_segments_to_deallocate;
+  mark_segmap_as_free(_next_segment, _next_segment + number_of_segments_to_deallocate);
+  b->initialize(used_number_of_segments);
+}
 
 void CodeHeap::deallocate(void* p) {
   assert(p == find_start(p), "illegal deallocation");
--- a/src/hotspot/share/memory/heap.hpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/memory/heap.hpp	Mon Sep 04 19:50:01 2017 +0200
@@ -147,6 +147,12 @@
   // Memory allocation
   void* allocate (size_t size); // Allocate 'size' bytes in the code cache or return NULL
   void  deallocate(void* p);    // Deallocate memory
+  // Free the tail of segments allocated by the last call to 'allocate()' which exceed 'used_size'.
+  // ATTENTION: this is only safe to use if there was no other call to 'allocate()' after
+  //            'p' was allocated. Only intended for freeing memory which would be otherwise
+  //            wasted after the interpreter generation because we don't know the interpreter size
+  //            beforehand and we also can't easily relocate the interpreter to a new location.
+  void  deallocate_tail(void* p, size_t used_size);
 
   // Attributes
   char* low_boundary() const                     { return _memory.low_boundary(); }
--- a/src/hotspot/share/runtime/init.cpp	Sun Oct 15 22:54:03 2017 +0200
+++ b/src/hotspot/share/runtime/init.cpp	Mon Sep 04 19:50:01 2017 +0200
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2016, 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
@@ -58,6 +58,10 @@
 void os_init_globals();        // depends on VM_Version_init, before universe_init
 void stubRoutines_init1();
 jint universe_init();          // depends on codeCache_init and stubRoutines_init
+#if INCLUDE_ALL_GCS
+// depends on universe_init, must be before interpreter_init (currently only on SPARC)
+void g1_barrier_stubs_init() NOT_SPARC({});
+#endif
 void interpreter_init();       // before any methods loaded
 void invocationCounter_init(); // before any methods loaded
 void marksweep_init();
@@ -112,7 +116,10 @@
   if (status != JNI_OK)
     return status;
 
-  interpreter_init();  // before any methods loaded
+#if INCLUDE_ALL_GCS
+  g1_barrier_stubs_init();   // depends on universe_init, must be before interpreter_init
+#endif
+  interpreter_init();        // before any methods loaded
   invocationCounter_init();  // before any methods loaded
   marksweep_init();
   accessFlags_init();