Mon, 15 Apr 2013 21:25:23 -0400
Merge
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 */
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))
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();
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);
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
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
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();
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);
338 //Create symbols to look for in the class
339 TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
340 THREAD);
342 //To be filled in with an offset of the field we're looking for
343 fieldDescriptor fd;
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 }
352 //fetch the field at the offset we've found
353 int dest_offset = fd.offset();
355 return dest_offset;
356 }
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 }
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 }
378 #define CC (char*)
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/Method;)I",
405 (void*)&WB_DeoptimizeMethod },
406 {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Method;)Z",
407 (void*)&WB_IsMethodCompiled },
408 {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Method;I)Z",
409 (void*)&WB_IsMethodCompilable},
410 {CC"isMethodQueuedForCompilation",
411 CC"(Ljava/lang/reflect/Method;)Z", (void*)&WB_IsMethodQueuedForCompilation},
412 {CC"makeMethodNotCompilable",
413 CC"(Ljava/lang/reflect/Method;)V", (void*)&WB_MakeMethodNotCompilable},
414 {CC"testSetDontInlineMethod",
415 CC"(Ljava/lang/reflect/Method;Z)Z", (void*)&WB_TestSetDontInlineMethod},
416 {CC"getMethodCompilationLevel",
417 CC"(Ljava/lang/reflect/Method;)I", (void*)&WB_GetMethodCompilationLevel},
418 {CC"getCompileQueuesSize",
419 CC"()I", (void*)&WB_GetCompileQueuesSize},
420 {CC"testSetForceInlineMethod",
421 CC"(Ljava/lang/reflect/Method;Z)Z", (void*)&WB_TestSetForceInlineMethod},
422 {CC"enqueueMethodForCompilation",
423 CC"(Ljava/lang/reflect/Method;I)Z", (void*)&WB_EnqueueMethodForCompilation},
424 {CC"clearMethodState",
425 CC"(Ljava/lang/reflect/Method;)V", (void*)&WB_ClearMethodState},
426 {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable },
427 {CC"fullGC", CC"()V", (void*)&WB_FullGC },
428 };
430 #undef CC
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