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 #if INCLUDE_ALL_GCS
  97 WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
  98   G1CollectedHeap* g1 = G1CollectedHeap::heap();
  99   oop result = JNIHandles::resolve(obj);
 100   const HeapRegion* hr = g1->heap_region_containing(result);
 101   return hr->isHumongous();
 102 WB_END
 103 
 104 WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o))
 105   G1CollectedHeap* g1 = G1CollectedHeap::heap();
 106   size_t nr = g1->free_regions();
 107   return (jlong)nr;
 108 WB_END
 109 
 110 WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o))
 111   G1CollectedHeap* g1 = G1CollectedHeap::heap();
 112   ConcurrentMark* cm = g1->concurrent_mark();
 113   return cm->concurrent_marking_in_progress();
 114 WB_END
 115 
 116 WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
 117   return (jint)HeapRegion::GrainBytes;
 118 WB_END
 119 #endif // INCLUDE_ALL_GCS
 120 
 121 #ifdef INCLUDE_NMT
 122 // Alloc memory using the test memory type so that we can use that to see if
 123 // NMT picks it up correctly
 124 WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size))
 125   jlong addr = 0;
 126 
 127   if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) {
 128     addr = (jlong)(uintptr_t)os::malloc(size, mtTest);
 129   }
 130 
 131   return addr;
 132 WB_END
 133 
 134 // Free the memory allocated by NMTAllocTest
 135 WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem))
 136   os::free((void*)(uintptr_t)mem, mtTest);
 137 WB_END
 138 
 139 WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
 140   jlong addr = 0;
 141 
 142   if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) {
 143     addr = (jlong)(uintptr_t)os::reserve_memory(size);
 144     MemTracker::record_virtual_memory_type((address)addr, mtTest);
 145   }
 146 
 147   return addr;
 148 WB_END
 149 
 150 
 151 WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
 152   os::commit_memory((char *)(uintptr_t)addr, size);
 153   MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest);
 154 WB_END
 155 
 156 WB_ENTRY(void, WB_NMTUncommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
 157   os::uncommit_memory((char *)(uintptr_t)addr, size);
 158 WB_END
 159 
 160 WB_ENTRY(void, WB_NMTReleaseMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
 161   os::release_memory((char *)(uintptr_t)addr, size);
 162 WB_END
 163 
 164 // Block until the current generation of NMT data to be merged, used to reliably test the NMT feature
 165 WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env))
 166 
 167   if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) {
 168     return false;
 169   }
 170 
 171   return MemTracker::wbtest_wait_for_data_merge();
 172 WB_END
 173 
 174 #endif // INCLUDE_NMT
 175 
 176 static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) {
 177   assert(method != NULL, "method should not be null");
 178   ThreadToNativeFromVM ttn(thread);
 179   return env->FromReflectedMethod(method);
 180 }
 181 
 182 WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o))
 183   MutexLockerEx mu(Compile_lock);
 184   CodeCache::mark_all_nmethods_for_deoptimization();
 185   VM_Deoptimize op;
 186   VMThread::execute(&op);
 187 WB_END
 188 
 189 WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method))
 190   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 191   MutexLockerEx mu(Compile_lock);
 192   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 193   int result = 0;
 194   nmethod* code = mh->code();
 195   if (code != NULL) {
 196     code->mark_for_deoptimization();
 197     ++result;
 198   }
 199   result += CodeCache::mark_for_deoptimization(mh());
 200   if (result > 0) {
 201     VM_Deoptimize op;
 202     VMThread::execute(&op);
 203   }
 204   return result;
 205 WB_END
 206 
 207 WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method))
 208   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 209   MutexLockerEx mu(Compile_lock);
 210   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 211   nmethod* code = mh->code();
 212   if (code == NULL) {
 213     return JNI_FALSE;
 214   }
 215   return (code->is_alive() && !code->is_marked_for_deoptimization());
 216 WB_END
 217 
 218 WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level))
 219   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 220   MutexLockerEx mu(Compile_lock);
 221   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 222   return CompilationPolicy::can_be_compiled(mh, comp_level);
 223 WB_END
 224 
 225 WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method))
 226   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 227   MutexLockerEx mu(Compile_lock);
 228   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 229   return mh->queued_for_compilation();
 230 WB_END
 231 
 232 WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method))
 233   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 234   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 235   nmethod* code = mh->code();
 236   return (code != NULL ? code->comp_level() : CompLevel_none);
 237 WB_END
 238 
 239 
 240 WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level))
 241   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 242   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 243   mh->set_not_compilable(comp_level, true /* report */, "WhiteBox");
 244 WB_END
 245 
 246 WB_ENTRY(jboolean, WB_TestSetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
 247   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 248   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 249   bool result = mh->dont_inline();
 250   mh->set_dont_inline(value == JNI_TRUE);
 251   return result;
 252 WB_END
 253 
 254 WB_ENTRY(jint, WB_GetCompileQueuesSize(JNIEnv* env, jobject o))
 255   return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ +
 256          CompileBroker::queue_size(CompLevel_full_profile) /* C1 */;
 257 WB_END
 258 
 259 
 260 WB_ENTRY(jboolean, WB_TestSetForceInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
 261   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 262   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 263   bool result = mh->force_inline();
 264   mh->set_force_inline(value == JNI_TRUE);
 265   return result;
 266 WB_END
 267 
 268 WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level))
 269   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 270   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 271   nmethod* nm = CompileBroker::compile_method(mh, InvocationEntryBci, comp_level, mh, mh->invocation_count(), "WhiteBox", THREAD);
 272   MutexLockerEx mu(Compile_lock);
 273   return (mh->queued_for_compilation() || nm != NULL);
 274 WB_END
 275 
 276 WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
 277   jmethodID jmid = reflected_method_to_jmid(thread, env, method);
 278   methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
 279   MutexLockerEx mu(Compile_lock);
 280   MethodData* mdo = mh->method_data();
 281   MethodCounters* mcs = mh->method_counters();
 282 
 283   if (mdo != NULL) {
 284     mdo->init();
 285     ResourceMark rm;
 286     int arg_count = mdo->method()->size_of_parameters();
 287     for (int i = 0; i < arg_count; i++) {
 288       mdo->set_arg_modified(i, 0);
 289     }
 290   }
 291 
 292   mh->clear_not_c1_compilable();
 293   mh->clear_not_c2_compilable();
 294   mh->clear_not_c2_osr_compilable();
 295   NOT_PRODUCT(mh->set_compiled_invocation_count(0));
 296   if (mcs != NULL) {
 297     mcs->backedge_counter()->init();
 298     mcs->invocation_counter()->init();
 299     mcs->set_interpreter_invocation_count(0);
 300     mcs->set_interpreter_throwout_count(0);
 301 
 302 #ifdef TIERED
 303     mcs->set_rate(0.0F);
 304     mh->set_prev_event_count(0, THREAD);
 305     mh->set_prev_time(0, THREAD);
 306 #endif
 307   }
 308 WB_END
 309 
 310 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
 311   ResourceMark rm(THREAD);
 312   int len;
 313   jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len);
 314   oop found_string = StringTable::the_table()->lookup(name, len);
 315   if (found_string == NULL) {
 316         return false;
 317   }
 318   return true;
 319 WB_END
 320 
 321 
 322 WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
 323   Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true);
 324   Universe::heap()->collect(GCCause::_last_ditch_collection);
 325 WB_END
 326 
 327 //Some convenience methods to deal with objects from java
 328 int WhiteBox::offset_for_field(const char* field_name, oop object,
 329     Symbol* signature_symbol) {
 330   assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
 331   Thread* THREAD = Thread::current();
 332 
 333   //Get the class of our object
 334   Klass* arg_klass = object->klass();
 335   //Turn it into an instance-klass
 336   InstanceKlass* ik = InstanceKlass::cast(arg_klass);
 337 
 338   //Create symbols to look for in the class
 339   TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
 340       THREAD);
 341 
 342   //To be filled in with an offset of the field we're looking for
 343   fieldDescriptor fd;
 344 
 345   Klass* res = ik->find_field(name_symbol, signature_symbol, &fd);
 346   if (res == NULL) {
 347     tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
 348         name_symbol->as_C_string());
 349     fatal("Invalid layout of preloaded class");
 350   }
 351 
 352   //fetch the field at the offset we've found
 353   int dest_offset = fd.offset();
 354 
 355   return dest_offset;
 356 }
 357 
 358 
 359 const char* WhiteBox::lookup_jstring(const char* field_name, oop object) {
 360   int offset = offset_for_field(field_name, object,
 361       vmSymbols::string_signature());
 362   oop string = object->obj_field(offset);
 363   if (string == NULL) {
 364     return NULL;
 365   }
 366   const char* ret = java_lang_String::as_utf8_string(string);
 367   return ret;
 368 }
 369 
 370 bool WhiteBox::lookup_bool(const char* field_name, oop object) {
 371   int offset =
 372       offset_for_field(field_name, object, vmSymbols::bool_signature());
 373   bool ret = (object->bool_field(offset) == JNI_TRUE);
 374   return ret;
 375 }
 376 
 377 
 378 #define CC (char*)
 379 
 380 static JNINativeMethod methods[] = {
 381   {CC"getObjectAddress",   CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress  },
 382   {CC"getHeapOopSize",     CC"()I",                   (void*)&WB_GetHeapOopSize    },
 383   {CC"isClassAlive0",      CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive      },
 384   {CC"parseCommandLine",
 385       CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
 386       (void*) &WB_ParseCommandLine
 387   },

 388 #if INCLUDE_ALL_GCS
 389   {CC"g1InConcurrentMark", CC"()Z",                   (void*)&WB_G1InConcurrentMark},
 390   {CC"g1IsHumongous",      CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous     },
 391   {CC"g1NumFreeRegions",   CC"()J",                   (void*)&WB_G1NumFreeRegions  },
 392   {CC"g1RegionSize",       CC"()I",                   (void*)&WB_G1RegionSize      },
 393 #endif // INCLUDE_ALL_GCS
 394 #ifdef INCLUDE_NMT
 395   {CC"NMTMalloc",           CC"(J)J",                 (void*)&WB_NMTMalloc          },
 396   {CC"NMTFree",             CC"(J)V",                 (void*)&WB_NMTFree            },
 397   {CC"NMTReserveMemory",    CC"(J)J",                 (void*)&WB_NMTReserveMemory   },
 398   {CC"NMTCommitMemory",     CC"(JJ)V",                (void*)&WB_NMTCommitMemory    },
 399   {CC"NMTUncommitMemory",   CC"(JJ)V",                (void*)&WB_NMTUncommitMemory  },
 400   {CC"NMTReleaseMemory",    CC"(JJ)V",                (void*)&WB_NMTReleaseMemory   },
 401   {CC"NMTWaitForDataMerge", CC"()Z",                  (void*)&WB_NMTWaitForDataMerge},
 402 #endif // INCLUDE_NMT
 403   {CC"deoptimizeAll",      CC"()V",                   (void*)&WB_DeoptimizeAll     },
 404   {CC"deoptimizeMethod",   CC"(Ljava/lang/reflect/Executable;)I",
 405                                                       (void*)&WB_DeoptimizeMethod  },
 406   {CC"isMethodCompiled",   CC"(Ljava/lang/reflect/Executable;)Z",
 407                                                       (void*)&WB_IsMethodCompiled  },
 408   {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;I)Z",
 409                                                       (void*)&WB_IsMethodCompilable},
 410   {CC"isMethodQueuedForCompilation",
 411       CC"(Ljava/lang/reflect/Executable;)Z",          (void*)&WB_IsMethodQueuedForCompilation},
 412   {CC"makeMethodNotCompilable",
 413       CC"(Ljava/lang/reflect/Executable;I)V",         (void*)&WB_MakeMethodNotCompilable},
 414   {CC"testSetDontInlineMethod",
 415       CC"(Ljava/lang/reflect/Executable;Z)Z",         (void*)&WB_TestSetDontInlineMethod},
 416   {CC"getMethodCompilationLevel",
 417       CC"(Ljava/lang/reflect/Executable;)I",          (void*)&WB_GetMethodCompilationLevel},
 418   {CC"getCompileQueuesSize",
 419       CC"()I",                                        (void*)&WB_GetCompileQueuesSize},
 420   {CC"testSetForceInlineMethod",
 421       CC"(Ljava/lang/reflect/Executable;Z)Z",         (void*)&WB_TestSetForceInlineMethod},
 422   {CC"enqueueMethodForCompilation",
 423       CC"(Ljava/lang/reflect/Executable;I)Z",         (void*)&WB_EnqueueMethodForCompilation},
 424   {CC"clearMethodState",
 425       CC"(Ljava/lang/reflect/Executable;)V",          (void*)&WB_ClearMethodState},
 426   {CC"isInStringTable",   CC"(Ljava/lang/String;)Z",  (void*)&WB_IsInStringTable  },
 427   {CC"fullGC",   CC"()V",                             (void*)&WB_FullGC },
 428 };
 429 
 430 #undef CC
 431 
 432 JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass))
 433   {
 434     if (WhiteBoxAPI) {
 435       // Make sure that wbclass is loaded by the null classloader
 436       instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
 437       Handle loader(ikh->class_loader());
 438       if (loader.is_null()) {
 439         ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
 440         jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0]));
 441         if (result == 0) {
 442           WhiteBox::set_used();
 443         }
 444       }
 445     }
 446   }
 447 JVM_END
--- EOF ---