rev 4560 : 8006088: Incompatible heap size flags accepted by VM
Summary: Make processing of minimum, initial and maximum heap size more intiutive by removing previous limitations on allowed values, and make error reporting consistent. Further, fix errors in ergonomic heap sizing.
Reviewed-by: johnc, jwilhelm, tamao

   1 /*
   2  * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */
  24 
  25 #include "precompiled.hpp"
  26 
  27 #include "memory/universe.hpp"
  28 #include "oops/oop.inline.hpp"
  29 
  30 #include "classfile/symbolTable.hpp"
  31 #include "classfile/classLoaderData.hpp"
  32 
  33 #include "prims/whitebox.hpp"
  34 #include "prims/wbtestmethods/parserTests.hpp"
  35 
  36 #include "runtime/interfaceSupport.hpp"
  37 #include "runtime/os.hpp"
  38 #include "utilities/debug.hpp"
  39 #include "utilities/macros.hpp"
  40 
  41 #if INCLUDE_ALL_GCS
  42 #include "gc_implementation/g1/concurrentMark.hpp"
  43 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
  44 #include "gc_implementation/g1/heapRegionRemSet.hpp"
  45 #endif // INCLUDE_ALL_GCS
  46 
  47 #ifdef INCLUDE_NMT
  48 #include "services/memTracker.hpp"
  49 #endif // INCLUDE_NMT
  50 
  51 #include "compiler/compileBroker.hpp"
  52 #include "runtime/compilationPolicy.hpp"
  53 
  54 bool WhiteBox::_used = false;
  55 
  56 WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj))
  57   return (jlong)(void*)JNIHandles::resolve(obj);
  58 WB_END
  59 
  60 WB_ENTRY(jint, WB_GetHeapOopSize(JNIEnv* env, jobject o))
  61   return heapOopSize;
  62 WB_END
  63 
  64 
  65 class WBIsKlassAliveClosure : public KlassClosure {
  66     Symbol* _name;
  67     bool _found;
  68 public:
  69     WBIsKlassAliveClosure(Symbol* name) : _name(name), _found(false) {}
  70 
  71     void do_klass(Klass* k) {
  72       if (_found) return;
  73       Symbol* ksym = k->name();
  74       if (ksym->fast_compare(_name) == 0) {
  75         _found = true;
  76       }
  77     }
  78 
  79     bool found() const {
  80         return _found;
  81     }
  82 };
  83 
  84 WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name))
  85   Handle h_name = JNIHandles::resolve(name);
  86   if (h_name.is_null()) return false;
  87   Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_false);
  88   TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return
  89 
  90   WBIsKlassAliveClosure closure(sym);
  91   ClassLoaderDataGraph::classes_do(&closure);
  92 
  93   return closure.found();
  94 WB_END
  95 
  96 WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) {
  97   CollectorPolicy * p = Universe::heap()->collector_policy();
  98   gclog_or_tty->print_cr("Minimum heap "SIZE_FORMAT" Initial heap "
  99     SIZE_FORMAT" Maximum heap "SIZE_FORMAT" Min alignment "SIZE_FORMAT" Max alignment "SIZE_FORMAT,
 100     p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(),
 101     p->min_alignment(), p->max_alignment());
 102 }
 103 WB_END
 104 
 105 #if INCLUDE_ALL_GCS
 106 WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
 107   G1CollectedHeap* g1 = G1CollectedHeap::heap();
 108   oop result = JNIHandles::resolve(obj);
 109   const HeapRegion* hr = g1->heap_region_containing(result);
 110   return hr->isHumongous();
 111 WB_END
 112 
 113 WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o))
 114   G1CollectedHeap* g1 = G1CollectedHeap::heap();
 115   size_t nr = g1->free_regions();
 116   return (jlong)nr;
 117 WB_END
 118 
 119 WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o))
 120   G1CollectedHeap* g1 = G1CollectedHeap::heap();
 121   ConcurrentMark* cm = g1->concurrent_mark();
 122   return cm->concurrent_marking_in_progress();
 123 WB_END
 124 
 125 WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
 126   return (jint)HeapRegion::GrainBytes;
 127 WB_END
 128 #endif // INCLUDE_ALL_GCS
 129 
 130 #ifdef INCLUDE_NMT
 131 // Alloc memory using the test memory type so that we can use that to see if
 132 // NMT picks it up correctly
 133 WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size))
 134   jlong addr = 0;
 135 
 136   if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) {
 137     addr = (jlong)(uintptr_t)os::malloc(size, mtTest);
 138   }
 139 
 140   return addr;
 141 WB_END
 142 
 143 // Free the memory allocated by NMTAllocTest
 144 WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem))
 145   os::free((void*)(uintptr_t)mem, mtTest);
 146 WB_END
 147 
 148 WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
 149   jlong addr = 0;
 150 
 151   if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) {
 152     addr = (jlong)(uintptr_t)os::reserve_memory(size);
 153     MemTracker::record_virtual_memory_type((address)addr, mtTest);
 154   }
 155 
 156   return addr;
 157 WB_END
 158 
 159 
 160 WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
 161   os::commit_memory((char *)(uintptr_t)addr, size);
 162   MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest);
 163 WB_END
 164 
 165 WB_ENTRY(void, WB_NMTUncommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
 166   os::uncommit_memory((char *)(uintptr_t)addr, size);
 167 WB_END
 168 
 169 WB_ENTRY(void, WB_NMTReleaseMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
 170   os::release_memory((char *)(uintptr_t)addr, size);
 171 WB_END
 172 
 173 // Block until the current generation of NMT data to be merged, used to reliably test the NMT feature
 174 WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env))
 175 
 176   if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) {
 177     return false;
 178   }
 179 
 180   return MemTracker::wbtest_wait_for_data_merge();
 181 WB_END
 182 
 183 #endif // INCLUDE_NMT
 184 
 185 static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) {
 186   assert(method != NULL, "method should not be null");
 187   ThreadToNativeFromVM ttn(thread);
 188   return env->FromReflectedMethod(method);
 189 }
 190 
 191 WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o))
 192   MutexLockerEx mu(Compile_lock);
 193   CodeCache::mark_all_nmethods_for_deoptimization();
 194   VM_Deoptimize op;
 195   VMThread::execute(&op);
 196 WB_END
 197 
 198 WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method))
 199   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 200   MutexLockerEx mu(Compile_lock);
 201   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 202   int result = 0;
 203   nmethod* code = mh->code();
 204   if (code != NULL) {
 205     code->mark_for_deoptimization();
 206     ++result;
 207   }
 208   result += CodeCache::mark_for_deoptimization(mh());
 209   if (result > 0) {
 210     VM_Deoptimize op;
 211     VMThread::execute(&op);
 212   }
 213   return result;
 214 WB_END
 215 
 216 WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method))
 217   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 218   MutexLockerEx mu(Compile_lock);
 219   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 220   nmethod* code = mh->code();
 221   if (code == NULL) {
 222     return JNI_FALSE;
 223   }
 224   return (code->is_alive() && !code->is_marked_for_deoptimization());
 225 WB_END
 226 
 227 WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level))
 228   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 229   MutexLockerEx mu(Compile_lock);
 230   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 231   return CompilationPolicy::can_be_compiled(mh, comp_level);
 232 WB_END
 233 
 234 WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method))
 235   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 236   MutexLockerEx mu(Compile_lock);
 237   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 238   return mh->queued_for_compilation();
 239 WB_END
 240 
 241 WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method))
 242   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 243   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 244   nmethod* code = mh->code();
 245   return (code != NULL ? code->comp_level() : CompLevel_none);
 246 WB_END
 247 
 248 
 249 WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level))
 250   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 251   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 252   mh->set_not_compilable(comp_level, true /* report */, "WhiteBox");
 253 WB_END
 254 
 255 WB_ENTRY(jboolean, WB_TestSetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
 256   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 257   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 258   bool result = mh->dont_inline();
 259   mh->set_dont_inline(value == JNI_TRUE);
 260   return result;
 261 WB_END
 262 
 263 WB_ENTRY(jint, WB_GetCompileQueuesSize(JNIEnv* env, jobject o))
 264   return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ +
 265          CompileBroker::queue_size(CompLevel_full_profile) /* C1 */;
 266 WB_END
 267 
 268 
 269 WB_ENTRY(jboolean, WB_TestSetForceInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
 270   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 271   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 272   bool result = mh->force_inline();
 273   mh->set_force_inline(value == JNI_TRUE);
 274   return result;
 275 WB_END
 276 
 277 WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level))
 278   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 279   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 280   nmethod* nm = CompileBroker::compile_method(mh, InvocationEntryBci, comp_level, mh, mh->invocation_count(), "WhiteBox", THREAD);
 281   MutexLockerEx mu(Compile_lock);
 282   return (mh->queued_for_compilation() || nm != NULL);
 283 WB_END
 284 
 285 WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
 286   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 287   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 288   MutexLockerEx mu(Compile_lock);
 289   MethodData* mdo = mh->method_data();
 290   MethodCounters* mcs = mh->method_counters();
 291 
 292   if (mdo != NULL) {
 293     mdo->init();
 294     ResourceMark rm;
 295     int arg_count = mdo->method()->size_of_parameters();
 296     for (int i = 0; i < arg_count; i++) {
 297       mdo->set_arg_modified(i, 0);
 298     }
 299   }
 300 
 301   mh->clear_not_c1_compilable();
 302   mh->clear_not_c2_compilable();
 303   mh->clear_not_c2_osr_compilable();
 304   NOT_PRODUCT(mh->set_compiled_invocation_count(0));
 305   if (mcs != NULL) {
 306     mcs->backedge_counter()->init();
 307     mcs->invocation_counter()->init();
 308     mcs->set_interpreter_invocation_count(0);
 309     mcs->set_interpreter_throwout_count(0);
 310 
 311 #ifdef TIERED
 312     mcs->set_rate(0.0F);
 313     mh->set_prev_event_count(0, THREAD);
 314     mh->set_prev_time(0, THREAD);
 315 #endif
 316   }
 317 WB_END
 318 
 319 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
 320   ResourceMark rm(THREAD);
 321   int len;
 322   jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len);
 323   oop found_string = StringTable::the_table()->lookup(name, len);
 324   if (found_string == NULL) {
 325         return false;
 326   }
 327   return true;
 328 WB_END
 329 
 330 
 331 WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
 332   Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true);
 333   Universe::heap()->collect(GCCause::_last_ditch_collection);
 334 WB_END
 335 
 336 //Some convenience methods to deal with objects from java
 337 int WhiteBox::offset_for_field(const char* field_name, oop object,
 338     Symbol* signature_symbol) {
 339   assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
 340   Thread* THREAD = Thread::current();
 341 
 342   //Get the class of our object
 343   Klass* arg_klass = object->klass();
 344   //Turn it into an instance-klass
 345   InstanceKlass* ik = InstanceKlass::cast(arg_klass);
 346 
 347   //Create symbols to look for in the class
 348   TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
 349       THREAD);
 350 
 351   //To be filled in with an offset of the field we're looking for
 352   fieldDescriptor fd;
 353 
 354   Klass* res = ik->find_field(name_symbol, signature_symbol, &fd);
 355   if (res == NULL) {
 356     tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
 357         name_symbol->as_C_string());
 358     fatal("Invalid layout of preloaded class");
 359   }
 360 
 361   //fetch the field at the offset we've found
 362   int dest_offset = fd.offset();
 363 
 364   return dest_offset;
 365 }
 366 
 367 
 368 const char* WhiteBox::lookup_jstring(const char* field_name, oop object) {
 369   int offset = offset_for_field(field_name, object,
 370       vmSymbols::string_signature());
 371   oop string = object->obj_field(offset);
 372   if (string == NULL) {
 373     return NULL;
 374   }
 375   const char* ret = java_lang_String::as_utf8_string(string);
 376   return ret;
 377 }
 378 
 379 bool WhiteBox::lookup_bool(const char* field_name, oop object) {
 380   int offset =
 381       offset_for_field(field_name, object, vmSymbols::bool_signature());
 382   bool ret = (object->bool_field(offset) == JNI_TRUE);
 383   return ret;
 384 }
 385 
 386 
 387 #define CC (char*)
 388 
 389 static JNINativeMethod methods[] = {
 390   {CC"getObjectAddress",   CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress  },
 391   {CC"getHeapOopSize",     CC"()I",                   (void*)&WB_GetHeapOopSize    },
 392   {CC"isClassAlive0",      CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive      },
 393   {CC"parseCommandLine",
 394       CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
 395       (void*) &WB_ParseCommandLine
 396   },
 397   {CC"printHeapSizes",     CC"()V",                   (void*)&WB_PrintHeapSizes    },
 398 #if INCLUDE_ALL_GCS
 399   {CC"g1InConcurrentMark", CC"()Z",                   (void*)&WB_G1InConcurrentMark},
 400   {CC"g1IsHumongous",      CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous     },
 401   {CC"g1NumFreeRegions",   CC"()J",                   (void*)&WB_G1NumFreeRegions  },
 402   {CC"g1RegionSize",       CC"()I",                   (void*)&WB_G1RegionSize      },
 403 #endif // INCLUDE_ALL_GCS
 404 #ifdef INCLUDE_NMT
 405   {CC"NMTMalloc",           CC"(J)J",                 (void*)&WB_NMTMalloc          },
 406   {CC"NMTFree",             CC"(J)V",                 (void*)&WB_NMTFree            },
 407   {CC"NMTReserveMemory",    CC"(J)J",                 (void*)&WB_NMTReserveMemory   },
 408   {CC"NMTCommitMemory",     CC"(JJ)V",                (void*)&WB_NMTCommitMemory    },
 409   {CC"NMTUncommitMemory",   CC"(JJ)V",                (void*)&WB_NMTUncommitMemory  },
 410   {CC"NMTReleaseMemory",    CC"(JJ)V",                (void*)&WB_NMTReleaseMemory   },
 411   {CC"NMTWaitForDataMerge", CC"()Z",                  (void*)&WB_NMTWaitForDataMerge},
 412 #endif // INCLUDE_NMT
 413   {CC"deoptimizeAll",      CC"()V",                   (void*)&WB_DeoptimizeAll     },
 414   {CC"deoptimizeMethod",   CC"(Ljava/lang/reflect/Executable;)I",
 415                                                       (void*)&WB_DeoptimizeMethod  },
 416   {CC"isMethodCompiled",   CC"(Ljava/lang/reflect/Executable;)Z",
 417                                                       (void*)&WB_IsMethodCompiled  },
 418   {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;I)Z",
 419                                                       (void*)&WB_IsMethodCompilable},
 420   {CC"isMethodQueuedForCompilation",
 421       CC"(Ljava/lang/reflect/Executable;)Z",          (void*)&WB_IsMethodQueuedForCompilation},
 422   {CC"makeMethodNotCompilable",
 423       CC"(Ljava/lang/reflect/Executable;I)V",         (void*)&WB_MakeMethodNotCompilable},
 424   {CC"testSetDontInlineMethod",
 425       CC"(Ljava/lang/reflect/Executable;Z)Z",         (void*)&WB_TestSetDontInlineMethod},
 426   {CC"getMethodCompilationLevel",
 427       CC"(Ljava/lang/reflect/Executable;)I",          (void*)&WB_GetMethodCompilationLevel},
 428   {CC"getCompileQueuesSize",
 429       CC"()I",                                        (void*)&WB_GetCompileQueuesSize},
 430   {CC"testSetForceInlineMethod",
 431       CC"(Ljava/lang/reflect/Executable;Z)Z",         (void*)&WB_TestSetForceInlineMethod},
 432   {CC"enqueueMethodForCompilation",
 433       CC"(Ljava/lang/reflect/Executable;I)Z",         (void*)&WB_EnqueueMethodForCompilation},
 434   {CC"clearMethodState",
 435       CC"(Ljava/lang/reflect/Executable;)V",          (void*)&WB_ClearMethodState},
 436   {CC"isInStringTable",   CC"(Ljava/lang/String;)Z",  (void*)&WB_IsInStringTable  },
 437   {CC"fullGC",   CC"()V",                             (void*)&WB_FullGC },
 438 };
 439 
 440 #undef CC
 441 
 442 JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass))
 443   {
 444     if (WhiteBoxAPI) {
 445       // Make sure that wbclass is loaded by the null classloader
 446       instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
 447       Handle loader(ikh->class_loader());
 448       if (loader.is_null()) {
 449         ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
 450         jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0]));
 451         if (result == 0) {
 452           WhiteBox::set_used();
 453         }
 454       }
 455     }
 456   }
 457 JVM_END
--- EOF ---