Thu, 02 May 2013 18:50:05 -0700
Merge
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
324 WB_ENTRY(jlong, WB_ReserveMemory(JNIEnv* env, jobject o, jlong size))
325 return (jlong)os::reserve_memory(size, NULL, 0);
326 WB_END
328 //Some convenience methods to deal with objects from java
329 int WhiteBox::offset_for_field(const char* field_name, oop object,
330 Symbol* signature_symbol) {
331 assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
332 Thread* THREAD = Thread::current();
334 //Get the class of our object
335 Klass* arg_klass = object->klass();
336 //Turn it into an instance-klass
337 InstanceKlass* ik = InstanceKlass::cast(arg_klass);
339 //Create symbols to look for in the class
340 TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
341 THREAD);
343 //To be filled in with an offset of the field we're looking for
344 fieldDescriptor fd;
346 Klass* res = ik->find_field(name_symbol, signature_symbol, &fd);
347 if (res == NULL) {
348 tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
349 name_symbol->as_C_string());
350 fatal("Invalid layout of preloaded class");
351 }
353 //fetch the field at the offset we've found
354 int dest_offset = fd.offset();
356 return dest_offset;
357 }
360 const char* WhiteBox::lookup_jstring(const char* field_name, oop object) {
361 int offset = offset_for_field(field_name, object,
362 vmSymbols::string_signature());
363 oop string = object->obj_field(offset);
364 if (string == NULL) {
365 return NULL;
366 }
367 const char* ret = java_lang_String::as_utf8_string(string);
368 return ret;
369 }
371 bool WhiteBox::lookup_bool(const char* field_name, oop object) {
372 int offset =
373 offset_for_field(field_name, object, vmSymbols::bool_signature());
374 bool ret = (object->bool_field(offset) == JNI_TRUE);
375 return ret;
376 }
379 #define CC (char*)
381 static JNINativeMethod methods[] = {
382 {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress },
383 {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize },
384 {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
385 {CC"parseCommandLine",
386 CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
387 (void*) &WB_ParseCommandLine
388 },
389 #if INCLUDE_ALL_GCS
390 {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark},
391 {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous },
392 {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions },
393 {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize },
394 #endif // INCLUDE_ALL_GCS
395 #ifdef INCLUDE_NMT
396 {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
397 {CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree },
398 {CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory },
399 {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory },
400 {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory },
401 {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory },
402 {CC"NMTWaitForDataMerge", CC"()Z", (void*)&WB_NMTWaitForDataMerge},
403 #endif // INCLUDE_NMT
404 {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll },
405 {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;)I",
406 (void*)&WB_DeoptimizeMethod },
407 {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;)Z",
408 (void*)&WB_IsMethodCompiled },
409 {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;I)Z",
410 (void*)&WB_IsMethodCompilable},
411 {CC"isMethodQueuedForCompilation",
412 CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation},
413 {CC"makeMethodNotCompilable",
414 CC"(Ljava/lang/reflect/Executable;I)V", (void*)&WB_MakeMethodNotCompilable},
415 {CC"testSetDontInlineMethod",
416 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod},
417 {CC"getMethodCompilationLevel",
418 CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodCompilationLevel},
419 {CC"getCompileQueuesSize",
420 CC"()I", (void*)&WB_GetCompileQueuesSize},
421 {CC"testSetForceInlineMethod",
422 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetForceInlineMethod},
423 {CC"enqueueMethodForCompilation",
424 CC"(Ljava/lang/reflect/Executable;I)Z", (void*)&WB_EnqueueMethodForCompilation},
425 {CC"clearMethodState",
426 CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
427 {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable },
428 {CC"fullGC", CC"()V", (void*)&WB_FullGC },
430 {CC"reserveMemory", CC"(J)J", (void*)&WB_ReserveMemory },
431 };
433 #undef CC
435 JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass))
436 {
437 if (WhiteBoxAPI) {
438 // Make sure that wbclass is loaded by the null classloader
439 instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
440 Handle loader(ikh->class_loader());
441 if (loader.is_null()) {
442 ResourceMark rm;
443 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
444 bool result = true;
445 // one by one registration natives for exception catching
446 jclass exceptionKlass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string());
447 for (int i = 0, n = sizeof(methods) / sizeof(methods[0]); i < n; ++i) {
448 if (env->RegisterNatives(wbclass, methods + i, 1) != 0) {
449 result = false;
450 if (env->ExceptionCheck() && env->IsInstanceOf(env->ExceptionOccurred(), exceptionKlass)) {
451 // j.l.NoSuchMethodError is thrown when a method can't be found or a method is not native
452 // ignoring the exception
453 tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s", methods[i].name, methods[i].signature);
454 env->ExceptionClear();
455 } else {
456 // register is failed w/o exception or w/ unexpected exception
457 tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered", methods[i].name, methods[i].signature);
458 env->UnregisterNatives(wbclass);
459 break;
460 }
461 }
462 }
464 if (result) {
465 WhiteBox::set_used();
466 }
467 }
468 }
469 }
470 JVM_END