Mon, 29 Apr 2013 16:13:57 -0400
8011773: Some tests on Interned String crashed JVM with OOM
Summary: Instead of terminating the VM, throw OutOfMemoryError exceptions.
Reviewed-by: coleenp, dholmes
1 /*
2 * Copyright (c) 2012, 2013, 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 */
25 #include "precompiled.hpp"
27 #include "memory/universe.hpp"
28 #include "oops/oop.inline.hpp"
30 #include "classfile/symbolTable.hpp"
31 #include "classfile/classLoaderData.hpp"
33 #include "prims/whitebox.hpp"
34 #include "prims/wbtestmethods/parserTests.hpp"
36 #include "runtime/interfaceSupport.hpp"
37 #include "runtime/os.hpp"
38 #include "utilities/debug.hpp"
39 #include "utilities/macros.hpp"
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
47 #ifdef INCLUDE_NMT
48 #include "services/memTracker.hpp"
49 #endif // INCLUDE_NMT
51 #include "compiler/compileBroker.hpp"
52 #include "runtime/compilationPolicy.hpp"
54 bool WhiteBox::_used = false;
56 WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj))
57 return (jlong)(void*)JNIHandles::resolve(obj);
58 WB_END
60 WB_ENTRY(jint, WB_GetHeapOopSize(JNIEnv* env, jobject o))
61 return heapOopSize;
62 WB_END
65 class WBIsKlassAliveClosure : public KlassClosure {
66 Symbol* _name;
67 bool _found;
68 public:
69 WBIsKlassAliveClosure(Symbol* name) : _name(name), _found(false) {}
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 }
79 bool found() const {
80 return _found;
81 }
82 };
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
90 WBIsKlassAliveClosure closure(sym);
91 ClassLoaderDataGraph::classes_do(&closure);
93 return closure.found();
94 WB_END
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
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
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
116 WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
117 return (jint)HeapRegion::GrainBytes;
118 WB_END
119 #endif // INCLUDE_ALL_GCS
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;
127 if (MemTracker::is_on() && !MemTracker::shutdown_in_progress()) {
128 addr = (jlong)(uintptr_t)os::malloc(size, mtTest);
129 }
131 return addr;
132 WB_END
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
139 WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
140 jlong addr = 0;
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 }
147 return addr;
148 WB_END
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
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
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
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))
167 if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) {
168 return false;
169 }
171 return MemTracker::wbtest_wait_for_data_merge();
172 WB_END
174 #endif // INCLUDE_NMT
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 }
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
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
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
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
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
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
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
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
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
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
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
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();
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 }
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);
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
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, CHECK_false);
314 return (StringTable::lookup(name, len) != NULL);
315 WB_END
318 WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
319 Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true);
320 Universe::heap()->collect(GCCause::_last_ditch_collection);
321 WB_END
323 //Some convenience methods to deal with objects from java
324 int WhiteBox::offset_for_field(const char* field_name, oop object,
325 Symbol* signature_symbol) {
326 assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
327 Thread* THREAD = Thread::current();
329 //Get the class of our object
330 Klass* arg_klass = object->klass();
331 //Turn it into an instance-klass
332 InstanceKlass* ik = InstanceKlass::cast(arg_klass);
334 //Create symbols to look for in the class
335 TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
336 THREAD);
338 //To be filled in with an offset of the field we're looking for
339 fieldDescriptor fd;
341 Klass* res = ik->find_field(name_symbol, signature_symbol, &fd);
342 if (res == NULL) {
343 tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
344 name_symbol->as_C_string());
345 fatal("Invalid layout of preloaded class");
346 }
348 //fetch the field at the offset we've found
349 int dest_offset = fd.offset();
351 return dest_offset;
352 }
355 const char* WhiteBox::lookup_jstring(const char* field_name, oop object) {
356 int offset = offset_for_field(field_name, object,
357 vmSymbols::string_signature());
358 oop string = object->obj_field(offset);
359 if (string == NULL) {
360 return NULL;
361 }
362 const char* ret = java_lang_String::as_utf8_string(string);
363 return ret;
364 }
366 bool WhiteBox::lookup_bool(const char* field_name, oop object) {
367 int offset =
368 offset_for_field(field_name, object, vmSymbols::bool_signature());
369 bool ret = (object->bool_field(offset) == JNI_TRUE);
370 return ret;
371 }
374 #define CC (char*)
376 static JNINativeMethod methods[] = {
377 {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress },
378 {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize },
379 {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
380 {CC"parseCommandLine",
381 CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
382 (void*) &WB_ParseCommandLine
383 },
384 #if INCLUDE_ALL_GCS
385 {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark},
386 {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous },
387 {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions },
388 {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize },
389 #endif // INCLUDE_ALL_GCS
390 #ifdef INCLUDE_NMT
391 {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
392 {CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree },
393 {CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory },
394 {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory },
395 {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory },
396 {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory },
397 {CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge},
398 #endif // INCLUDE_NMT
399 {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll },
400 {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;)I",
401 (void*)&WB_DeoptimizeMethod },
402 {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;)Z",
403 (void*)&WB_IsMethodCompiled },
404 {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;I)Z",
405 (void*)&WB_IsMethodCompilable},
406 {CC"isMethodQueuedForCompilation",
407 CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation},
408 {CC"makeMethodNotCompilable",
409 CC"(Ljava/lang/reflect/Executable;I)V", (void*)&WB_MakeMethodNotCompilable},
410 {CC"testSetDontInlineMethod",
411 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod},
412 {CC"getMethodCompilationLevel",
413 CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodCompilationLevel},
414 {CC"getCompileQueuesSize",
415 CC"()I", (void*)&WB_GetCompileQueuesSize},
416 {CC"testSetForceInlineMethod",
417 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetForceInlineMethod},
418 {CC"enqueueMethodForCompilation",
419 CC"(Ljava/lang/reflect/Executable;I)Z", (void*)&WB_EnqueueMethodForCompilation},
420 {CC"clearMethodState",
421 CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
422 {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable },
423 {CC"fullGC", CC"()V", (void*)&WB_FullGC },
424 };
426 #undef CC
428 JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass))
429 {
430 if (WhiteBoxAPI) {
431 // Make sure that wbclass is loaded by the null classloader
432 instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
433 Handle loader(ikh->class_loader());
434 if (loader.is_null()) {
435 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
436 jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0]));
437 if (result == 0) {
438 WhiteBox::set_used();
439 }
440 }
441 }
442 }
443 JVM_END