Mercurial > hg > truffle
comparison src/share/vm/jvmci/jvmciRuntime.cpp @ 21559:be896a1983c0
recast all Graal native code as JVMCI code (JBS:GRAAL-53)
author | Doug Simon <doug.simon@oracle.com> |
---|---|
date | Thu, 28 May 2015 15:36:48 +0200 |
parents | src/share/vm/graal/graalRuntime.cpp@b1530a6cce8c |
children | 47bebae7454f |
comparison
equal
deleted
inserted
replaced
21558:d563baeca9df | 21559:be896a1983c0 |
---|---|
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 #include "precompiled.hpp" | |
25 #include "asm/codeBuffer.hpp" | |
26 #include "compiler/compileBroker.hpp" | |
27 #include "compiler/disassembler.hpp" | |
28 #include "jvmci/jvmciRuntime.hpp" | |
29 #include "jvmci/jvmciCompilerToVM.hpp" | |
30 #include "jvmci/jvmciCompiler.hpp" | |
31 #include "jvmci/jvmciJavaAccess.hpp" | |
32 #include "jvmci/jvmciEnv.hpp" | |
33 #include "memory/oopFactory.hpp" | |
34 #include "prims/jvm.h" | |
35 #include "runtime/biasedLocking.hpp" | |
36 #include "runtime/interfaceSupport.hpp" | |
37 #include "runtime/arguments.hpp" | |
38 #include "runtime/reflection.hpp" | |
39 #include "utilities/debug.hpp" | |
40 | |
41 jobject JVMCIRuntime::_HotSpotJVMCIRuntime_instance = NULL; | |
42 bool JVMCIRuntime::_HotSpotJVMCIRuntime_initialized = false; | |
43 bool JVMCIRuntime::_shutdown_called = false; | |
44 | |
45 void JVMCIRuntime::initialize_natives(JNIEnv *env, jclass c2vmClass) { | |
46 uintptr_t heap_end = (uintptr_t) Universe::heap()->reserved_region().end(); | |
47 uintptr_t allocation_end = heap_end + ((uintptr_t)16) * 1024 * 1024 * 1024; | |
48 AMD64_ONLY(guarantee(heap_end < allocation_end, "heap end too close to end of address space (might lead to erroneous TLAB allocations)")); | |
49 NOT_LP64(error("check TLAB allocation code for address space conflicts")); | |
50 | |
51 ensure_jvmci_class_loader_is_initialized(); | |
52 | |
53 JavaThread* THREAD = JavaThread::current(); | |
54 { | |
55 ThreadToNativeFromVM trans(THREAD); | |
56 | |
57 ResourceMark rm; | |
58 HandleMark hm; | |
59 | |
60 jvmci_compute_offsets(); | |
61 | |
62 // Ensure _non_oop_bits is initialized | |
63 Universe::non_oop_word(); | |
64 | |
65 env->RegisterNatives(c2vmClass, CompilerToVM_methods, CompilerToVM_methods_count()); | |
66 } | |
67 if (HAS_PENDING_EXCEPTION) { | |
68 abort_on_pending_exception(PENDING_EXCEPTION, "Could not register natives"); | |
69 } | |
70 } | |
71 | |
72 BufferBlob* JVMCIRuntime::initialize_buffer_blob() { | |
73 JavaThread* THREAD = JavaThread::current(); | |
74 BufferBlob* buffer_blob = THREAD->get_buffer_blob(); | |
75 if (buffer_blob == NULL) { | |
76 buffer_blob = BufferBlob::create("JVMCI thread-local CodeBuffer", JVMCINMethodSizeLimit); | |
77 if (buffer_blob != NULL) { | |
78 THREAD->set_buffer_blob(buffer_blob); | |
79 } | |
80 } | |
81 return buffer_blob; | |
82 } | |
83 | |
84 BasicType JVMCIRuntime::kindToBasicType(jchar ch) { | |
85 switch(ch) { | |
86 case 'z': return T_BOOLEAN; | |
87 case 'b': return T_BYTE; | |
88 case 's': return T_SHORT; | |
89 case 'c': return T_CHAR; | |
90 case 'i': return T_INT; | |
91 case 'f': return T_FLOAT; | |
92 case 'j': return T_LONG; | |
93 case 'd': return T_DOUBLE; | |
94 case 'a': return T_OBJECT; | |
95 case '-': return T_ILLEGAL; | |
96 default: | |
97 fatal(err_msg("unexpected Kind: %c", ch)); | |
98 break; | |
99 } | |
100 return T_ILLEGAL; | |
101 } | |
102 | |
103 // Simple helper to see if the caller of a runtime stub which | |
104 // entered the VM has been deoptimized | |
105 | |
106 static bool caller_is_deopted() { | |
107 JavaThread* thread = JavaThread::current(); | |
108 RegisterMap reg_map(thread, false); | |
109 frame runtime_frame = thread->last_frame(); | |
110 frame caller_frame = runtime_frame.sender(®_map); | |
111 assert(caller_frame.is_compiled_frame(), "must be compiled"); | |
112 return caller_frame.is_deoptimized_frame(); | |
113 } | |
114 | |
115 // Stress deoptimization | |
116 static void deopt_caller() { | |
117 if ( !caller_is_deopted()) { | |
118 JavaThread* thread = JavaThread::current(); | |
119 RegisterMap reg_map(thread, false); | |
120 frame runtime_frame = thread->last_frame(); | |
121 frame caller_frame = runtime_frame.sender(®_map); | |
122 Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); | |
123 assert(caller_is_deopted(), "Must be deoptimized"); | |
124 } | |
125 } | |
126 | |
127 JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_instance(JavaThread* thread, Klass* klass)) | |
128 JRT_BLOCK; | |
129 assert(klass->is_klass(), "not a class"); | |
130 instanceKlassHandle h(thread, klass); | |
131 h->check_valid_for_instantiation(true, CHECK); | |
132 // make sure klass is initialized | |
133 h->initialize(CHECK); | |
134 // allocate instance and return via TLS | |
135 oop obj = h->allocate_instance(CHECK); | |
136 thread->set_vm_result(obj); | |
137 JRT_BLOCK_END; | |
138 | |
139 if (JVMCIDeferredInitBarriers) { | |
140 new_store_pre_barrier(thread); | |
141 } | |
142 JRT_END | |
143 | |
144 JRT_BLOCK_ENTRY(void, JVMCIRuntime::new_array(JavaThread* thread, Klass* array_klass, jint length)) | |
145 JRT_BLOCK; | |
146 // Note: no handle for klass needed since they are not used | |
147 // anymore after new_objArray() and no GC can happen before. | |
148 // (This may have to change if this code changes!) | |
149 assert(array_klass->is_klass(), "not a class"); | |
150 oop obj; | |
151 if (array_klass->oop_is_typeArray()) { | |
152 BasicType elt_type = TypeArrayKlass::cast(array_klass)->element_type(); | |
153 obj = oopFactory::new_typeArray(elt_type, length, CHECK); | |
154 } else { | |
155 Klass* elem_klass = ObjArrayKlass::cast(array_klass)->element_klass(); | |
156 obj = oopFactory::new_objArray(elem_klass, length, CHECK); | |
157 } | |
158 thread->set_vm_result(obj); | |
159 // This is pretty rare but this runtime patch is stressful to deoptimization | |
160 // if we deoptimize here so force a deopt to stress the path. | |
161 if (DeoptimizeALot) { | |
162 static int deopts = 0; | |
163 // Alternate between deoptimizing and raising an error (which will also cause a deopt) | |
164 if (deopts++ % 2 == 0) { | |
165 ResourceMark rm(THREAD); | |
166 THROW(vmSymbols::java_lang_OutOfMemoryError()); | |
167 } else { | |
168 deopt_caller(); | |
169 } | |
170 } | |
171 JRT_BLOCK_END; | |
172 | |
173 if (JVMCIDeferredInitBarriers) { | |
174 new_store_pre_barrier(thread); | |
175 } | |
176 JRT_END | |
177 | |
178 void JVMCIRuntime::new_store_pre_barrier(JavaThread* thread) { | |
179 // After any safepoint, just before going back to compiled code, | |
180 // we inform the GC that we will be doing initializing writes to | |
181 // this object in the future without emitting card-marks, so | |
182 // GC may take any compensating steps. | |
183 // NOTE: Keep this code consistent with GraphKit::store_barrier. | |
184 | |
185 oop new_obj = thread->vm_result(); | |
186 if (new_obj == NULL) return; | |
187 | |
188 assert(Universe::heap()->can_elide_tlab_store_barriers(), | |
189 "compiler must check this first"); | |
190 // GC may decide to give back a safer copy of new_obj. | |
191 new_obj = Universe::heap()->new_store_pre_barrier(thread, new_obj); | |
192 thread->set_vm_result(new_obj); | |
193 } | |
194 | |
195 JRT_ENTRY(void, JVMCIRuntime::new_multi_array(JavaThread* thread, Klass* klass, int rank, jint* dims)) | |
196 assert(klass->is_klass(), "not a class"); | |
197 assert(rank >= 1, "rank must be nonzero"); | |
198 oop obj = ArrayKlass::cast(klass)->multi_allocate(rank, dims, CHECK); | |
199 thread->set_vm_result(obj); | |
200 JRT_END | |
201 | |
202 JRT_ENTRY(void, JVMCIRuntime::dynamic_new_array(JavaThread* thread, oopDesc* element_mirror, jint length)) | |
203 oop obj = Reflection::reflect_new_array(element_mirror, length, CHECK); | |
204 thread->set_vm_result(obj); | |
205 JRT_END | |
206 | |
207 JRT_ENTRY(void, JVMCIRuntime::dynamic_new_instance(JavaThread* thread, oopDesc* type_mirror)) | |
208 instanceKlassHandle klass(THREAD, java_lang_Class::as_Klass(type_mirror)); | |
209 | |
210 if (klass == NULL) { | |
211 ResourceMark rm(THREAD); | |
212 THROW(vmSymbols::java_lang_InstantiationException()); | |
213 } | |
214 | |
215 // Create new instance (the receiver) | |
216 klass->check_valid_for_instantiation(false, CHECK); | |
217 | |
218 // Make sure klass gets initialized | |
219 klass->initialize(CHECK); | |
220 | |
221 oop obj = klass->allocate_instance(CHECK); | |
222 thread->set_vm_result(obj); | |
223 JRT_END | |
224 | |
225 extern void vm_exit(int code); | |
226 | |
227 // Enter this method from compiled code handler below. This is where we transition | |
228 // to VM mode. This is done as a helper routine so that the method called directly | |
229 // from compiled code does not have to transition to VM. This allows the entry | |
230 // method to see if the nmethod that we have just looked up a handler for has | |
231 // been deoptimized while we were in the vm. This simplifies the assembly code | |
232 // cpu directories. | |
233 // | |
234 // We are entering here from exception stub (via the entry method below) | |
235 // If there is a compiled exception handler in this method, we will continue there; | |
236 // otherwise we will unwind the stack and continue at the caller of top frame method | |
237 // Note: we enter in Java using a special JRT wrapper. This wrapper allows us to | |
238 // control the area where we can allow a safepoint. After we exit the safepoint area we can | |
239 // check to see if the handler we are going to return is now in a nmethod that has | |
240 // been deoptimized. If that is the case we return the deopt blob | |
241 // unpack_with_exception entry instead. This makes life for the exception blob easier | |
242 // because making that same check and diverting is painful from assembly language. | |
243 JRT_ENTRY_NO_ASYNC(static address, exception_handler_for_pc_helper(JavaThread* thread, oopDesc* ex, address pc, nmethod*& nm)) | |
244 // Reset method handle flag. | |
245 thread->set_is_method_handle_return(false); | |
246 | |
247 Handle exception(thread, ex); | |
248 nm = CodeCache::find_nmethod(pc); | |
249 assert(nm != NULL, "this is not an nmethod"); | |
250 // Adjust the pc as needed/ | |
251 if (nm->is_deopt_pc(pc)) { | |
252 RegisterMap map(thread, false); | |
253 frame exception_frame = thread->last_frame().sender(&map); | |
254 // if the frame isn't deopted then pc must not correspond to the caller of last_frame | |
255 assert(exception_frame.is_deoptimized_frame(), "must be deopted"); | |
256 pc = exception_frame.pc(); | |
257 } | |
258 #ifdef ASSERT | |
259 assert(exception.not_null(), "NULL exceptions should be handled by throw_exception"); | |
260 assert(exception->is_oop(), "just checking"); | |
261 // Check that exception is a subclass of Throwable, otherwise we have a VerifyError | |
262 if (!(exception->is_a(SystemDictionary::Throwable_klass()))) { | |
263 if (ExitVMOnVerifyError) vm_exit(-1); | |
264 ShouldNotReachHere(); | |
265 } | |
266 #endif | |
267 | |
268 // Check the stack guard pages and reenable them if necessary and there is | |
269 // enough space on the stack to do so. Use fast exceptions only if the guard | |
270 // pages are enabled. | |
271 bool guard_pages_enabled = thread->stack_yellow_zone_enabled(); | |
272 if (!guard_pages_enabled) guard_pages_enabled = thread->reguard_stack(); | |
273 | |
274 if (JvmtiExport::can_post_on_exceptions()) { | |
275 // To ensure correct notification of exception catches and throws | |
276 // we have to deoptimize here. If we attempted to notify the | |
277 // catches and throws during this exception lookup it's possible | |
278 // we could deoptimize on the way out of the VM and end back in | |
279 // the interpreter at the throw site. This would result in double | |
280 // notifications since the interpreter would also notify about | |
281 // these same catches and throws as it unwound the frame. | |
282 | |
283 RegisterMap reg_map(thread); | |
284 frame stub_frame = thread->last_frame(); | |
285 frame caller_frame = stub_frame.sender(®_map); | |
286 | |
287 // We don't really want to deoptimize the nmethod itself since we | |
288 // can actually continue in the exception handler ourselves but I | |
289 // don't see an easy way to have the desired effect. | |
290 Deoptimization::deoptimize_frame(thread, caller_frame.id(), Deoptimization::Reason_constraint); | |
291 assert(caller_is_deopted(), "Must be deoptimized"); | |
292 | |
293 return SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); | |
294 } | |
295 | |
296 // ExceptionCache is used only for exceptions at call sites and not for implicit exceptions | |
297 if (guard_pages_enabled) { | |
298 address fast_continuation = nm->handler_for_exception_and_pc(exception, pc); | |
299 if (fast_continuation != NULL) { | |
300 // Set flag if return address is a method handle call site. | |
301 thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); | |
302 return fast_continuation; | |
303 } | |
304 } | |
305 | |
306 // If the stack guard pages are enabled, check whether there is a handler in | |
307 // the current method. Otherwise (guard pages disabled), force an unwind and | |
308 // skip the exception cache update (i.e., just leave continuation==NULL). | |
309 address continuation = NULL; | |
310 if (guard_pages_enabled) { | |
311 | |
312 // New exception handling mechanism can support inlined methods | |
313 // with exception handlers since the mappings are from PC to PC | |
314 | |
315 // debugging support | |
316 // tracing | |
317 if (TraceExceptions) { | |
318 ttyLocker ttyl; | |
319 ResourceMark rm; | |
320 tty->print_cr("Exception <%s> (" INTPTR_FORMAT ") thrown in compiled method <%s> at PC " INTPTR_FORMAT " for thread " INTPTR_FORMAT "", | |
321 exception->print_value_string(), p2i((address)exception()), nm->method()->print_value_string(), p2i(pc), p2i(thread)); | |
322 } | |
323 // for AbortVMOnException flag | |
324 NOT_PRODUCT(Exceptions::debug_check_abort(exception)); | |
325 | |
326 // Clear out the exception oop and pc since looking up an | |
327 // exception handler can cause class loading, which might throw an | |
328 // exception and those fields are expected to be clear during | |
329 // normal bytecode execution. | |
330 thread->clear_exception_oop_and_pc(); | |
331 | |
332 continuation = SharedRuntime::compute_compiled_exc_handler(nm, pc, exception, false, false); | |
333 // If an exception was thrown during exception dispatch, the exception oop may have changed | |
334 thread->set_exception_oop(exception()); | |
335 thread->set_exception_pc(pc); | |
336 | |
337 // the exception cache is used only by non-implicit exceptions | |
338 if (continuation != NULL && !SharedRuntime::deopt_blob()->contains(continuation)) { | |
339 nm->add_handler_for_exception_and_pc(exception, pc, continuation); | |
340 } | |
341 } | |
342 | |
343 // Set flag if return address is a method handle call site. | |
344 thread->set_is_method_handle_return(nm->is_method_handle_return(pc)); | |
345 | |
346 if (TraceExceptions) { | |
347 ttyLocker ttyl; | |
348 ResourceMark rm; | |
349 tty->print_cr("Thread " PTR_FORMAT " continuing at PC " PTR_FORMAT " for exception thrown at PC " PTR_FORMAT, | |
350 p2i(thread), p2i(continuation), p2i(pc)); | |
351 } | |
352 | |
353 return continuation; | |
354 JRT_END | |
355 | |
356 // Enter this method from compiled code only if there is a Java exception handler | |
357 // in the method handling the exception. | |
358 // We are entering here from exception stub. We don't do a normal VM transition here. | |
359 // We do it in a helper. This is so we can check to see if the nmethod we have just | |
360 // searched for an exception handler has been deoptimized in the meantime. | |
361 address JVMCIRuntime::exception_handler_for_pc(JavaThread* thread) { | |
362 oop exception = thread->exception_oop(); | |
363 address pc = thread->exception_pc(); | |
364 // Still in Java mode | |
365 DEBUG_ONLY(ResetNoHandleMark rnhm); | |
366 nmethod* nm = NULL; | |
367 address continuation = NULL; | |
368 { | |
369 // Enter VM mode by calling the helper | |
370 ResetNoHandleMark rnhm; | |
371 continuation = exception_handler_for_pc_helper(thread, exception, pc, nm); | |
372 } | |
373 // Back in JAVA, use no oops DON'T safepoint | |
374 | |
375 // Now check to see if the nmethod we were called from is now deoptimized. | |
376 // If so we must return to the deopt blob and deoptimize the nmethod | |
377 if (nm != NULL && caller_is_deopted()) { | |
378 continuation = SharedRuntime::deopt_blob()->unpack_with_exception_in_tls(); | |
379 } | |
380 | |
381 assert(continuation != NULL, "no handler found"); | |
382 return continuation; | |
383 } | |
384 | |
385 JRT_ENTRY(void, JVMCIRuntime::create_null_exception(JavaThread* thread)) | |
386 SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_NullPointerException()); | |
387 thread->set_vm_result(PENDING_EXCEPTION); | |
388 CLEAR_PENDING_EXCEPTION; | |
389 JRT_END | |
390 | |
391 JRT_ENTRY(void, JVMCIRuntime::create_out_of_bounds_exception(JavaThread* thread, jint index)) | |
392 char message[jintAsStringSize]; | |
393 sprintf(message, "%d", index); | |
394 SharedRuntime::throw_and_post_jvmti_exception(thread, vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), message); | |
395 thread->set_vm_result(PENDING_EXCEPTION); | |
396 CLEAR_PENDING_EXCEPTION; | |
397 JRT_END | |
398 | |
399 JRT_ENTRY_NO_ASYNC(void, JVMCIRuntime::monitorenter(JavaThread* thread, oopDesc* obj, BasicLock* lock)) | |
400 if (TraceJVMCI >= 3) { | |
401 char type[O_BUFLEN]; | |
402 obj->klass()->name()->as_C_string(type, O_BUFLEN); | |
403 markOop mark = obj->mark(); | |
404 tty->print_cr("%s: entered locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(mark), p2i(lock)); | |
405 tty->flush(); | |
406 } | |
407 #ifdef ASSERT | |
408 if (PrintBiasedLockingStatistics) { | |
409 Atomic::inc(BiasedLocking::slow_path_entry_count_addr()); | |
410 } | |
411 #endif | |
412 Handle h_obj(thread, obj); | |
413 assert(h_obj()->is_oop(), "must be NULL or an object"); | |
414 if (UseBiasedLocking) { | |
415 // Retry fast entry if bias is revoked to avoid unnecessary inflation | |
416 ObjectSynchronizer::fast_enter(h_obj, lock, true, CHECK); | |
417 } else { | |
418 if (JVMCIUseFastLocking) { | |
419 // When using fast locking, the compiled code has already tried the fast case | |
420 ObjectSynchronizer::slow_enter(h_obj, lock, THREAD); | |
421 } else { | |
422 ObjectSynchronizer::fast_enter(h_obj, lock, false, THREAD); | |
423 } | |
424 } | |
425 if (TraceJVMCI >= 3) { | |
426 tty->print_cr("%s: exiting locking slow with obj=" INTPTR_FORMAT, thread->name(), p2i(obj)); | |
427 } | |
428 JRT_END | |
429 | |
430 JRT_LEAF(void, JVMCIRuntime::monitorexit(JavaThread* thread, oopDesc* obj, BasicLock* lock)) | |
431 assert(thread == JavaThread::current(), "threads must correspond"); | |
432 assert(thread->last_Java_sp(), "last_Java_sp must be set"); | |
433 // monitorexit is non-blocking (leaf routine) => no exceptions can be thrown | |
434 EXCEPTION_MARK; | |
435 | |
436 #ifdef DEBUG | |
437 if (!obj->is_oop()) { | |
438 ResetNoHandleMark rhm; | |
439 nmethod* method = thread->last_frame().cb()->as_nmethod_or_null(); | |
440 if (method != NULL) { | |
441 tty->print_cr("ERROR in monitorexit in method %s wrong obj " INTPTR_FORMAT, method->name(), p2i(obj)); | |
442 } | |
443 thread->print_stack_on(tty); | |
444 assert(false, "invalid lock object pointer dected"); | |
445 } | |
446 #endif | |
447 | |
448 if (JVMCIUseFastLocking) { | |
449 // When using fast locking, the compiled code has already tried the fast case | |
450 ObjectSynchronizer::slow_exit(obj, lock, THREAD); | |
451 } else { | |
452 ObjectSynchronizer::fast_exit(obj, lock, THREAD); | |
453 } | |
454 if (TraceJVMCI >= 3) { | |
455 char type[O_BUFLEN]; | |
456 obj->klass()->name()->as_C_string(type, O_BUFLEN); | |
457 tty->print_cr("%s: exited locking slow case with obj=" INTPTR_FORMAT ", type=%s, mark=" INTPTR_FORMAT ", lock=" INTPTR_FORMAT, thread->name(), p2i(obj), type, p2i(obj->mark()), p2i(lock)); | |
458 tty->flush(); | |
459 } | |
460 JRT_END | |
461 | |
462 JRT_LEAF(void, JVMCIRuntime::log_object(JavaThread* thread, oopDesc* obj, jint flags)) | |
463 bool string = mask_bits_are_true(flags, LOG_OBJECT_STRING); | |
464 bool addr = mask_bits_are_true(flags, LOG_OBJECT_ADDRESS); | |
465 bool newline = mask_bits_are_true(flags, LOG_OBJECT_NEWLINE); | |
466 if (!string) { | |
467 if (!addr && obj->is_oop_or_null(true)) { | |
468 char buf[O_BUFLEN]; | |
469 tty->print("%s@" INTPTR_FORMAT, obj->klass()->name()->as_C_string(buf, O_BUFLEN), p2i(obj)); | |
470 } else { | |
471 tty->print(INTPTR_FORMAT, p2i(obj)); | |
472 } | |
473 } else { | |
474 ResourceMark rm; | |
475 assert(obj != NULL && java_lang_String::is_instance(obj), "must be"); | |
476 char *buf = java_lang_String::as_utf8_string(obj); | |
477 tty->print_raw(buf); | |
478 } | |
479 if (newline) { | |
480 tty->cr(); | |
481 } | |
482 JRT_END | |
483 | |
484 JRT_LEAF(void, JVMCIRuntime::write_barrier_pre(JavaThread* thread, oopDesc* obj)) | |
485 thread->satb_mark_queue().enqueue(obj); | |
486 JRT_END | |
487 | |
488 JRT_LEAF(void, JVMCIRuntime::write_barrier_post(JavaThread* thread, void* card_addr)) | |
489 thread->dirty_card_queue().enqueue(card_addr); | |
490 JRT_END | |
491 | |
492 JRT_LEAF(jboolean, JVMCIRuntime::validate_object(JavaThread* thread, oopDesc* parent, oopDesc* child)) | |
493 bool ret = true; | |
494 if(!Universe::heap()->is_in_closed_subset(parent)) { | |
495 tty->print_cr("Parent Object "INTPTR_FORMAT" not in heap", p2i(parent)); | |
496 parent->print(); | |
497 ret=false; | |
498 } | |
499 if(!Universe::heap()->is_in_closed_subset(child)) { | |
500 tty->print_cr("Child Object "INTPTR_FORMAT" not in heap", p2i(child)); | |
501 child->print(); | |
502 ret=false; | |
503 } | |
504 return (jint)ret; | |
505 JRT_END | |
506 | |
507 JRT_ENTRY(void, JVMCIRuntime::vm_error(JavaThread* thread, jlong where, jlong format, jlong value)) | |
508 ResourceMark rm; | |
509 const char *error_msg = where == 0L ? "<internal JVMCI error>" : (char*) (address) where; | |
510 char *detail_msg = NULL; | |
511 if (format != 0L) { | |
512 const char* buf = (char*) (address) format; | |
513 size_t detail_msg_length = strlen(buf) * 2; | |
514 detail_msg = (char *) NEW_RESOURCE_ARRAY(u_char, detail_msg_length); | |
515 jio_snprintf(detail_msg, detail_msg_length, buf, value); | |
516 } | |
517 report_vm_error(__FILE__, __LINE__, error_msg, detail_msg); | |
518 JRT_END | |
519 | |
520 JRT_LEAF(oopDesc*, JVMCIRuntime::load_and_clear_exception(JavaThread* thread)) | |
521 oop exception = thread->exception_oop(); | |
522 assert(exception != NULL, "npe"); | |
523 thread->set_exception_oop(NULL); | |
524 thread->set_exception_pc(0); | |
525 return exception; | |
526 JRT_END | |
527 | |
528 JRT_LEAF(void, JVMCIRuntime::log_printf(JavaThread* thread, oopDesc* format, jlong v1, jlong v2, jlong v3)) | |
529 ResourceMark rm; | |
530 assert(format != NULL && java_lang_String::is_instance(format), "must be"); | |
531 char *buf = java_lang_String::as_utf8_string(format); | |
532 tty->print(buf, v1, v2, v3); | |
533 JRT_END | |
534 | |
535 static void decipher(jlong v, bool ignoreZero) { | |
536 if (v != 0 || !ignoreZero) { | |
537 void* p = (void *)(address) v; | |
538 CodeBlob* cb = CodeCache::find_blob(p); | |
539 if (cb) { | |
540 if (cb->is_nmethod()) { | |
541 char buf[O_BUFLEN]; | |
542 tty->print("%s [" INTPTR_FORMAT "+" JLONG_FORMAT "]", cb->as_nmethod_or_null()->method()->name_and_sig_as_C_string(buf, O_BUFLEN), p2i(cb->code_begin()), (jlong)((address)v - cb->code_begin())); | |
543 return; | |
544 } | |
545 cb->print_value_on(tty); | |
546 return; | |
547 } | |
548 if (Universe::heap()->is_in(p)) { | |
549 oop obj = oop(p); | |
550 obj->print_value_on(tty); | |
551 return; | |
552 } | |
553 tty->print(INTPTR_FORMAT " [long: " JLONG_FORMAT ", double %lf, char %c]",p2i((void *)v), (jlong)v, (jdouble)v, (char)v); | |
554 } | |
555 } | |
556 | |
557 JRT_LEAF(void, JVMCIRuntime::vm_message(jboolean vmError, jlong format, jlong v1, jlong v2, jlong v3)) | |
558 ResourceMark rm; | |
559 char *buf = (char*) (address) format; | |
560 if (vmError) { | |
561 if (buf != NULL) { | |
562 fatal(err_msg(buf, v1, v2, v3)); | |
563 } else { | |
564 fatal("<anonymous error>"); | |
565 } | |
566 } else if (buf != NULL) { | |
567 tty->print(buf, v1, v2, v3); | |
568 } else { | |
569 assert(v2 == 0, "v2 != 0"); | |
570 assert(v3 == 0, "v3 != 0"); | |
571 decipher(v1, false); | |
572 } | |
573 JRT_END | |
574 | |
575 JRT_LEAF(void, JVMCIRuntime::log_primitive(JavaThread* thread, jchar typeChar, jlong value, jboolean newline)) | |
576 union { | |
577 jlong l; | |
578 jdouble d; | |
579 jfloat f; | |
580 } uu; | |
581 uu.l = value; | |
582 switch (typeChar) { | |
583 case 'z': tty->print(value == 0 ? "false" : "true"); break; | |
584 case 'b': tty->print("%d", (jbyte) value); break; | |
585 case 'c': tty->print("%c", (jchar) value); break; | |
586 case 's': tty->print("%d", (jshort) value); break; | |
587 case 'i': tty->print("%d", (jint) value); break; | |
588 case 'f': tty->print("%f", uu.f); break; | |
589 case 'j': tty->print(JLONG_FORMAT, value); break; | |
590 case 'd': tty->print("%lf", uu.d); break; | |
591 default: assert(false, "unknown typeChar"); break; | |
592 } | |
593 if (newline) { | |
594 tty->cr(); | |
595 } | |
596 JRT_END | |
597 | |
598 JRT_ENTRY(jint, JVMCIRuntime::identity_hash_code(JavaThread* thread, oopDesc* obj)) | |
599 return (jint) obj->identity_hash(); | |
600 JRT_END | |
601 | |
602 JRT_ENTRY(jboolean, JVMCIRuntime::thread_is_interrupted(JavaThread* thread, oopDesc* receiver, jboolean clear_interrupted)) | |
603 // Ensure that the C++ Thread and OSThread structures aren't freed before we operate. | |
604 // This locking requires thread_in_vm which is why this method cannot be JRT_LEAF. | |
605 Handle receiverHandle(thread, receiver); | |
606 MutexLockerEx ml(thread->threadObj() == (void*)receiver ? NULL : Threads_lock); | |
607 JavaThread* receiverThread = java_lang_Thread::thread(receiverHandle()); | |
608 if (receiverThread == NULL) { | |
609 // The other thread may exit during this process, which is ok so return false. | |
610 return JNI_FALSE; | |
611 } else { | |
612 return (jint) Thread::is_interrupted(receiverThread, clear_interrupted != 0); | |
613 } | |
614 JRT_END | |
615 | |
616 JRT_ENTRY(jint, JVMCIRuntime::test_deoptimize_call_int(JavaThread* thread, int value)) | |
617 deopt_caller(); | |
618 return value; | |
619 JRT_END | |
620 | |
621 // private static void Factory.init() | |
622 JVM_ENTRY(void, JVM_InitJVMCIClassLoader(JNIEnv *env, jclass c, jobject loader_handle)) | |
623 SystemDictionary::init_jvmci_loader(JNIHandles::resolve(loader_handle)); | |
624 SystemDictionary::WKID scan = SystemDictionary::FIRST_JVMCI_WKID; | |
625 SystemDictionary::initialize_wk_klasses_through(SystemDictionary::LAST_JVMCI_WKID, scan, CHECK); | |
626 JVM_END | |
627 | |
628 // private static JVMCIRuntime JVMCI.initializeRuntime() | |
629 JVM_ENTRY(jobject, JVM_GetJVMCIRuntime(JNIEnv *env, jclass c)) | |
630 JVMCIRuntime::initialize_HotSpotJVMCIRuntime(); | |
631 return JVMCIRuntime::get_HotSpotJVMCIRuntime_jobject(); | |
632 JVM_END | |
633 | |
634 // private static String[] Services.getServiceImpls(Class service) | |
635 JVM_ENTRY(jobject, JVM_GetJVMCIServiceImpls(JNIEnv *env, jclass c, jclass serviceClass)) | |
636 HandleMark hm; | |
637 ResourceMark rm; | |
638 KlassHandle serviceKlass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(serviceClass))); | |
639 return JNIHandles::make_local(THREAD, JVMCIRuntime::get_service_impls(serviceKlass, THREAD)()); | |
640 JVM_END | |
641 | |
642 // private static TruffleRuntime Truffle.createRuntime() | |
643 JVM_ENTRY(jobject, JVM_CreateTruffleRuntime(JNIEnv *env, jclass c)) | |
644 JVMCIRuntime::ensure_jvmci_class_loader_is_initialized(); | |
645 TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime", CHECK_NULL); | |
646 KlassHandle klass = JVMCIRuntime::resolve_or_fail(name, CHECK_NULL); | |
647 | |
648 TempNewSymbol makeInstance = SymbolTable::new_symbol("makeInstance", CHECK_NULL); | |
649 TempNewSymbol sig = SymbolTable::new_symbol("()Lcom/oracle/truffle/api/TruffleRuntime;", CHECK_NULL); | |
650 JavaValue result(T_OBJECT); | |
651 JavaCalls::call_static(&result, klass, makeInstance, sig, CHECK_NULL); | |
652 return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); | |
653 JVM_END | |
654 | |
655 // private static NativeFunctionInterfaceRuntime.createInterface() | |
656 JVM_ENTRY(jobject, JVM_CreateNativeFunctionInterface(JNIEnv *env, jclass c)) | |
657 JVMCIRuntime::ensure_jvmci_class_loader_is_initialized(); | |
658 TempNewSymbol name = SymbolTable::new_symbol("com/oracle/graal/truffle/hotspot/HotSpotTruffleRuntime", CHECK_NULL); | |
659 KlassHandle klass = JVMCIRuntime::resolve_or_fail(name, CHECK_NULL); | |
660 | |
661 TempNewSymbol makeInstance = SymbolTable::new_symbol("createNativeFunctionInterface", CHECK_NULL); | |
662 TempNewSymbol sig = SymbolTable::new_symbol("()Lcom/oracle/nfi/api/NativeFunctionInterface;", CHECK_NULL); | |
663 JavaValue result(T_OBJECT); | |
664 JavaCalls::call_static(&result, klass, makeInstance, sig, CHECK_NULL); | |
665 return JNIHandles::make_local(THREAD, (oop) result.get_jobject()); | |
666 JVM_END | |
667 | |
668 void JVMCIRuntime::check_generated_sources_sha1(TRAPS) { | |
669 TempNewSymbol name = SymbolTable::new_symbol("com/oracle/jvmci/hotspot/sourcegen/GeneratedSourcesSha1", CHECK_ABORT); | |
670 KlassHandle klass = load_required_class(name); | |
671 fieldDescriptor fd; | |
672 if (!InstanceKlass::cast(klass())->find_field(vmSymbols::value_name(), vmSymbols::string_signature(), true, &fd)) { | |
673 THROW_MSG(vmSymbols::java_lang_NoSuchFieldError(), "GeneratedSourcesSha1.value"); | |
674 } | |
675 | |
676 Symbol* value = java_lang_String::as_symbol(klass->java_mirror()->obj_field(fd.offset()), CHECK); | |
677 if (!value->equals(_generated_sources_sha1)) { | |
678 char buf[200]; | |
679 jio_snprintf(buf, sizeof(buf), "Generated sources SHA1 check failed (%s != %s) - need to rebuild the VM", value->as_C_string(), _generated_sources_sha1); | |
680 THROW_MSG(vmSymbols::java_lang_InternalError(), buf); | |
681 } | |
682 } | |
683 | |
684 Handle JVMCIRuntime::callInitializer(const char* className, const char* methodName, const char* returnType) { | |
685 guarantee(!_HotSpotJVMCIRuntime_initialized, "cannot reinitialize HotSpotJVMCIRuntime"); | |
686 Thread* THREAD = Thread::current(); | |
687 check_generated_sources_sha1(CHECK_ABORT_(Handle())); | |
688 | |
689 TempNewSymbol name = SymbolTable::new_symbol(className, CHECK_ABORT_(Handle())); | |
690 KlassHandle klass = load_required_class(name); | |
691 TempNewSymbol runtime = SymbolTable::new_symbol(methodName, CHECK_ABORT_(Handle())); | |
692 TempNewSymbol sig = SymbolTable::new_symbol(returnType, CHECK_ABORT_(Handle())); | |
693 JavaValue result(T_OBJECT); | |
694 JavaCalls::call_static(&result, klass, runtime, sig, CHECK_ABORT_(Handle())); | |
695 return Handle((oop)result.get_jobject()); | |
696 } | |
697 | |
698 void JVMCIRuntime::initialize_HotSpotJVMCIRuntime() { | |
699 if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { | |
700 #ifdef ASSERT | |
701 // This should only be called in the context of the JVMCI class being initialized | |
702 Thread* THREAD = Thread::current(); | |
703 TempNewSymbol name = SymbolTable::new_symbol("com/oracle/jvmci/runtime/JVMCI", CHECK_ABORT); | |
704 instanceKlassHandle klass = InstanceKlass::cast(load_required_class(name)); | |
705 assert(klass->is_being_initialized() && klass->is_reentrant_initialization(THREAD), | |
706 "HotSpotJVMCIRuntime initialization should only be triggered through JVMCI initialization"); | |
707 #endif | |
708 | |
709 Handle result = callInitializer("com/oracle/jvmci/hotspot/HotSpotJVMCIRuntime", "runtime", | |
710 "()Lcom/oracle/jvmci/hotspot/HotSpotJVMCIRuntime;"); | |
711 _HotSpotJVMCIRuntime_initialized = true; | |
712 _HotSpotJVMCIRuntime_instance = JNIHandles::make_global(result()); | |
713 } | |
714 } | |
715 | |
716 void JVMCIRuntime::initialize_JVMCI() { | |
717 if (JNIHandles::resolve(_HotSpotJVMCIRuntime_instance) == NULL) { | |
718 callInitializer("com/oracle/jvmci/runtime/JVMCI", "getRuntime", "()Lcom/oracle/jvmci/runtime/JVMCIRuntime;"); | |
719 } | |
720 assert(_HotSpotJVMCIRuntime_initialized == true, "what?"); | |
721 } | |
722 | |
723 // private static void CompilerToVMImpl.init() | |
724 JVM_ENTRY(void, JVM_InitializeJVMCINatives(JNIEnv *env, jclass c2vmClass)) | |
725 JVMCIRuntime::initialize_natives(env, c2vmClass); | |
726 JVM_END | |
727 | |
728 // private static OptionsParsed[] HotSpotOptions.parseVMOptions(Class) | |
729 JVM_ENTRY(jobject, JVM_ParseJVMCIOptions(JNIEnv *env, jclass c, jobject optionsParsedClass_obj)) | |
730 HandleMark hm; | |
731 KlassHandle hotSpotOptionsClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(c))); | |
732 JVMCIRuntime::parse_arguments(hotSpotOptionsClass, CHECK_NULL); | |
733 KlassHandle optionsParsedClass(THREAD, java_lang_Class::as_Klass(JNIHandles::resolve_non_null(optionsParsedClass_obj))); | |
734 return JNIHandles::make_local(THREAD, JVMCIRuntime::get_service_impls(optionsParsedClass, THREAD)()); | |
735 JVM_END | |
736 | |
737 | |
738 void JVMCIRuntime::ensure_jvmci_class_loader_is_initialized() { | |
739 // This initialization code is guarded by a static pointer to the Factory class. | |
740 // Once it is non-null, the JVMCI class loader and well known JVMCI classes are | |
741 // guaranteed to have been initialized. By going through the static | |
742 // initializer of Factory, we can rely on class initialization semantics to | |
743 // synchronize threads racing to do the initialization. | |
744 static Klass* _FactoryKlass = NULL; | |
745 if (_FactoryKlass == NULL) { | |
746 Thread* THREAD = Thread::current(); | |
747 TempNewSymbol name = SymbolTable::new_symbol("com/oracle/jvmci/hotspot/loader/Factory", CHECK_ABORT); | |
748 KlassHandle klass = SystemDictionary::resolve_or_fail(name, true, THREAD); | |
749 if (HAS_PENDING_EXCEPTION) { | |
750 static volatile int seen_error = 0; | |
751 if (!seen_error && Atomic::cmpxchg(1, &seen_error, 0) == 0) { | |
752 // Only report the failure on the first thread that hits it | |
753 abort_on_pending_exception(PENDING_EXCEPTION, "JVMCI classes are not available"); | |
754 } else { | |
755 CLEAR_PENDING_EXCEPTION; | |
756 // Give first thread time to report the error. | |
757 os::sleep(THREAD, 100, false); | |
758 vm_abort(false); | |
759 } | |
760 } | |
761 | |
762 // We cannot use jvmciJavaAccess for this because we are currently in the | |
763 // process of initializing that mechanism. | |
764 TempNewSymbol field_name = SymbolTable::new_symbol("useJVMCIClassLoader", CHECK_ABORT); | |
765 fieldDescriptor field_desc; | |
766 if (klass->find_field(field_name, vmSymbols::bool_signature(), &field_desc) == NULL) { | |
767 ResourceMark rm; | |
768 fatal(err_msg("Invalid layout of %s at %s", field_name->as_C_string(), klass->external_name())); | |
769 } | |
770 | |
771 InstanceKlass* ik = InstanceKlass::cast(klass()); | |
772 address addr = ik->static_field_addr(field_desc.offset() - InstanceMirrorKlass::offset_of_static_fields()); | |
773 *((jboolean *) addr) = (jboolean) UseJVMCIClassLoader; | |
774 klass->initialize(CHECK_ABORT); | |
775 _FactoryKlass = klass(); | |
776 } | |
777 } | |
778 | |
779 jint JVMCIRuntime::check_arguments(TRAPS) { | |
780 KlassHandle nullHandle; | |
781 parse_arguments(nullHandle, THREAD); | |
782 if (HAS_PENDING_EXCEPTION) { | |
783 // Errors in parsing JVMCI arguments cause exceptions. | |
784 // We now load and initialize HotSpotOptions which in turn | |
785 // causes argument parsing to be redone with better error messages. | |
786 CLEAR_PENDING_EXCEPTION; | |
787 TempNewSymbol name = SymbolTable::new_symbol("Lcom/oracle/jvmci/hotspot/HotSpotOptions;", CHECK_ABORT_(JNI_ERR)); | |
788 instanceKlassHandle hotSpotOptionsClass = resolve_or_fail(name, CHECK_ABORT_(JNI_ERR)); | |
789 | |
790 parse_arguments(hotSpotOptionsClass, THREAD); | |
791 assert(HAS_PENDING_EXCEPTION, "must be"); | |
792 | |
793 ResourceMark rm; | |
794 Handle exception = PENDING_EXCEPTION; | |
795 CLEAR_PENDING_EXCEPTION; | |
796 oop message = java_lang_Throwable::message(exception); | |
797 if (message != NULL) { | |
798 tty->print_cr("Error parsing JVMCI options: %s", java_lang_String::as_utf8_string(message)); | |
799 } else { | |
800 call_printStackTrace(exception, THREAD); | |
801 } | |
802 return JNI_ERR; | |
803 } | |
804 return JNI_OK; | |
805 } | |
806 | |
807 void JVMCIRuntime::parse_arguments(KlassHandle hotSpotOptionsClass, TRAPS) { | |
808 ResourceMark rm(THREAD); | |
809 | |
810 // Process option overrides from jvmci.options first | |
811 parse_jvmci_options_file(hotSpotOptionsClass, CHECK); | |
812 | |
813 // Now process options on the command line | |
814 int numOptions = Arguments::num_jvmci_args(); | |
815 for (int i = 0; i < numOptions; i++) { | |
816 char* arg = Arguments::jvmci_args_array()[i]; | |
817 parse_argument(hotSpotOptionsClass, arg, CHECK); | |
818 } | |
819 } | |
820 | |
821 void JVMCIRuntime::check_required_value(const char* name, size_t name_len, const char* value, TRAPS) { | |
822 if (value == NULL) { | |
823 char buf[200]; | |
824 jio_snprintf(buf, sizeof(buf), "Must use '-G:%.*s=<value>' format for %.*s option", name_len, name, name_len, name); | |
825 THROW_MSG(vmSymbols::java_lang_InternalError(), buf); | |
826 } | |
827 } | |
828 | |
829 void JVMCIRuntime::parse_argument(KlassHandle hotSpotOptionsClass, char* arg, TRAPS) { | |
830 ensure_jvmci_class_loader_is_initialized(); | |
831 char first = arg[0]; | |
832 char* name; | |
833 size_t name_len; | |
834 bool recognized = true; | |
835 if (first == '+' || first == '-') { | |
836 name = arg + 1; | |
837 name_len = strlen(name); | |
838 recognized = set_option_bool(hotSpotOptionsClass, name, name_len, first, CHECK); | |
839 } else { | |
840 char* sep = strchr(arg, '='); | |
841 name = arg; | |
842 char* value = NULL; | |
843 if (sep != NULL) { | |
844 name_len = sep - name; | |
845 value = sep + 1; | |
846 } else { | |
847 name_len = strlen(name); | |
848 } | |
849 recognized = set_option(hotSpotOptionsClass, name, name_len, value, CHECK); | |
850 } | |
851 | |
852 if (!recognized) { | |
853 bool throw_err = hotSpotOptionsClass.is_null(); | |
854 if (!hotSpotOptionsClass.is_null()) { | |
855 set_option_helper(hotSpotOptionsClass, name, name_len, Handle(), ' ', Handle(), 0L); | |
856 if (!HAS_PENDING_EXCEPTION) { | |
857 throw_err = true; | |
858 } | |
859 } | |
860 | |
861 if (throw_err) { | |
862 char buf[200]; | |
863 jio_snprintf(buf, sizeof(buf), "Unrecognized JVMCI option %.*s", name_len, name); | |
864 THROW_MSG(vmSymbols::java_lang_InternalError(), buf); | |
865 } | |
866 } | |
867 } | |
868 | |
869 void JVMCIRuntime::parse_jvmci_options_file(KlassHandle hotSpotOptionsClass, TRAPS) { | |
870 const char* home = Arguments::get_java_home(); | |
871 size_t path_len = strlen(home) + strlen("/lib/jvmci.options") + 1; | |
872 char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len); | |
873 char sep = os::file_separator()[0]; | |
874 sprintf(path, "%s%clib%cjvmci.options", home, sep, sep); | |
875 | |
876 struct stat st; | |
877 if (os::stat(path, &st) == 0) { | |
878 int file_handle = os::open(path, 0, 0); | |
879 if (file_handle != -1) { | |
880 char* buffer = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, st.st_size); | |
881 int num_read = (int) os::read(file_handle, (char*) buffer, st.st_size); | |
882 if (num_read == -1) { | |
883 warning("Error reading file %s due to %s", path, strerror(errno)); | |
884 } else if (num_read != st.st_size) { | |
885 warning("Only read %d of " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path); | |
886 } | |
887 os::close(file_handle); | |
888 if (num_read == st.st_size) { | |
889 char* line = buffer; | |
890 int lineNo = 1; | |
891 while (line - buffer < num_read) { | |
892 char* nl = strchr(line, '\n'); | |
893 if (nl != NULL) { | |
894 *nl = '\0'; | |
895 } | |
896 parse_argument(hotSpotOptionsClass, line, THREAD); | |
897 if (HAS_PENDING_EXCEPTION) { | |
898 warning("Error in %s:%d", path, lineNo); | |
899 return; | |
900 } | |
901 if (nl != NULL) { | |
902 line = nl + 1; | |
903 lineNo++; | |
904 } else { | |
905 // File without newline at the end | |
906 break; | |
907 } | |
908 } | |
909 } | |
910 } else { | |
911 warning("Error opening file %s due to %s", path, strerror(errno)); | |
912 } | |
913 } | |
914 } | |
915 | |
916 jlong JVMCIRuntime::parse_primitive_option_value(char spec, const char* name, size_t name_len, const char* value, TRAPS) { | |
917 check_required_value(name, name_len, value, CHECK_(0L)); | |
918 union { | |
919 jint i; | |
920 jlong l; | |
921 double d; | |
922 } uu; | |
923 uu.l = 0L; | |
924 char dummy; | |
925 switch (spec) { | |
926 case 'd': | |
927 case 'f': { | |
928 if (sscanf(value, "%lf%c", &uu.d, &dummy) == 1) { | |
929 return uu.l; | |
930 } | |
931 break; | |
932 } | |
933 case 'i': { | |
934 if (sscanf(value, "%d%c", &uu.i, &dummy) == 1) { | |
935 return (jlong)uu.i; | |
936 } | |
937 break; | |
938 } | |
939 default: | |
940 ShouldNotReachHere(); | |
941 } | |
942 ResourceMark rm(THREAD); | |
943 char buf[200]; | |
944 bool missing = strlen(value) == 0; | |
945 if (missing) { | |
946 jio_snprintf(buf, sizeof(buf), "Missing %s value for JVMCI option %.*s", (spec == 'i' ? "numeric" : "float/double"), name_len, name); | |
947 } else { | |
948 jio_snprintf(buf, sizeof(buf), "Invalid %s value for JVMCI option %.*s: %s", (spec == 'i' ? "numeric" : "float/double"), name_len, name, value); | |
949 } | |
950 THROW_MSG_(vmSymbols::java_lang_InternalError(), buf, 0L); | |
951 } | |
952 | |
953 void JVMCIRuntime::set_option_helper(KlassHandle hotSpotOptionsClass, char* name, size_t name_len, Handle option, jchar spec, Handle stringValue, jlong primitiveValue) { | |
954 Thread* THREAD = Thread::current(); | |
955 Handle name_handle; | |
956 if (name != NULL) { | |
957 if (strlen(name) > name_len) { | |
958 // Temporarily replace '=' with NULL to create the Java string for the option name | |
959 char save = name[name_len]; | |
960 name[name_len] = '\0'; | |
961 name_handle = java_lang_String::create_from_str(name, THREAD); | |
962 name[name_len] = '='; | |
963 if (HAS_PENDING_EXCEPTION) { | |
964 return; | |
965 } | |
966 } else { | |
967 assert(strlen(name) == name_len, "must be"); | |
968 name_handle = java_lang_String::create_from_str(name, CHECK); | |
969 } | |
970 } | |
971 | |
972 TempNewSymbol setOption = SymbolTable::new_symbol("setOption", CHECK); | |
973 TempNewSymbol sig = SymbolTable::new_symbol("(Ljava/lang/String;Lcom/oracle/jvmci/options/OptionValue;CLjava/lang/String;J)V", CHECK); | |
974 JavaValue result(T_VOID); | |
975 JavaCallArguments args; | |
976 args.push_oop(name_handle()); | |
977 args.push_oop(option()); | |
978 args.push_int(spec); | |
979 args.push_oop(stringValue()); | |
980 args.push_long(primitiveValue); | |
981 JavaCalls::call_static(&result, hotSpotOptionsClass, setOption, sig, &args, CHECK); | |
982 } | |
983 | |
984 Handle JVMCIRuntime::get_OptionValue(const char* declaringClass, const char* fieldName, const char* fieldSig, TRAPS) { | |
985 TempNewSymbol name = SymbolTable::new_symbol(declaringClass, CHECK_NH); | |
986 Klass* klass = resolve_or_fail(name, CHECK_NH); | |
987 | |
988 // The class has been loaded so the field and signature should already be in the symbol | |
989 // table. If they're not there, the field doesn't exist. | |
990 TempNewSymbol fieldname = SymbolTable::probe(fieldName, (int)strlen(fieldName)); | |
991 TempNewSymbol signame = SymbolTable::probe(fieldSig, (int)strlen(fieldSig)); | |
992 if (fieldname == NULL || signame == NULL) { | |
993 THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), (char*) fieldName, Handle()); | |
994 } | |
995 // Make sure class is initialized before handing id's out to fields | |
996 klass->initialize(CHECK_NH); | |
997 | |
998 fieldDescriptor fd; | |
999 if (!InstanceKlass::cast(klass)->find_field(fieldname, signame, true, &fd)) { | |
1000 THROW_MSG_(vmSymbols::java_lang_NoSuchFieldError(), (char*) fieldName, Handle()); | |
1001 } | |
1002 | |
1003 Handle ret = klass->java_mirror()->obj_field(fd.offset()); | |
1004 return ret; | |
1005 } | |
1006 | |
1007 Handle JVMCIRuntime::create_Service(const char* name, TRAPS) { | |
1008 TempNewSymbol kname = SymbolTable::new_symbol(name, CHECK_NH); | |
1009 Klass* k = resolve_or_fail(kname, CHECK_NH); | |
1010 instanceKlassHandle klass(THREAD, k); | |
1011 klass->initialize(CHECK_NH); | |
1012 klass->check_valid_for_instantiation(true, CHECK_NH); | |
1013 JavaValue result(T_VOID); | |
1014 instanceHandle service = klass->allocate_instance_handle(CHECK_NH); | |
1015 JavaCalls::call_special(&result, service, klass, vmSymbols::object_initializer_name(), vmSymbols::void_method_signature(), THREAD); | |
1016 return service; | |
1017 } | |
1018 | |
1019 void JVMCIRuntime::shutdown() { | |
1020 if (_HotSpotJVMCIRuntime_instance != NULL) { | |
1021 _shutdown_called = true; | |
1022 JavaThread* THREAD = JavaThread::current(); | |
1023 HandleMark hm(THREAD); | |
1024 TempNewSymbol name = SymbolTable::new_symbol("com/oracle/jvmci/hotspot/HotSpotJVMCIRuntime", CHECK_ABORT); | |
1025 KlassHandle klass = load_required_class(name); | |
1026 JavaValue result(T_VOID); | |
1027 JavaCallArguments args; | |
1028 args.push_oop(get_HotSpotJVMCIRuntime()); | |
1029 JavaCalls::call_special(&result, klass, vmSymbols::shutdown_method_name(), vmSymbols::void_method_signature(), &args, CHECK_ABORT); | |
1030 | |
1031 JNIHandles::destroy_global(_HotSpotJVMCIRuntime_instance); | |
1032 _HotSpotJVMCIRuntime_instance = NULL; | |
1033 } | |
1034 } | |
1035 | |
1036 void JVMCIRuntime::call_printStackTrace(Handle exception, Thread* thread) { | |
1037 assert(exception->is_a(SystemDictionary::Throwable_klass()), "Throwable instance expected"); | |
1038 JavaValue result(T_VOID); | |
1039 JavaCalls::call_virtual(&result, | |
1040 exception, | |
1041 KlassHandle(thread, | |
1042 SystemDictionary::Throwable_klass()), | |
1043 vmSymbols::printStackTrace_name(), | |
1044 vmSymbols::void_method_signature(), | |
1045 thread); | |
1046 } | |
1047 | |
1048 void JVMCIRuntime::abort_on_pending_exception(Handle exception, const char* message, bool dump_core) { | |
1049 Thread* THREAD = Thread::current(); | |
1050 CLEAR_PENDING_EXCEPTION; | |
1051 tty->print_raw_cr(message); | |
1052 call_printStackTrace(exception, THREAD); | |
1053 | |
1054 // Give other aborting threads to also print their stack traces. | |
1055 // This can be very useful when debugging class initialization | |
1056 // failures. | |
1057 os::sleep(THREAD, 200, false); | |
1058 | |
1059 vm_abort(dump_core); | |
1060 } | |
1061 | |
1062 Klass* JVMCIRuntime::resolve_or_null(Symbol* name, TRAPS) { | |
1063 return SystemDictionary::resolve_or_null(name, SystemDictionary::jvmci_loader(), Handle(), CHECK_NULL); | |
1064 } | |
1065 | |
1066 Klass* JVMCIRuntime::resolve_or_fail(Symbol* name, TRAPS) { | |
1067 return SystemDictionary::resolve_or_fail(name, SystemDictionary::jvmci_loader(), Handle(), true, CHECK_NULL); | |
1068 } | |
1069 | |
1070 Klass* JVMCIRuntime::load_required_class(Symbol* name) { | |
1071 Klass* klass = resolve_or_null(name, Thread::current()); | |
1072 if (klass == NULL) { | |
1073 tty->print_cr("Could not load class %s", name->as_C_string()); | |
1074 vm_abort(false); | |
1075 } | |
1076 return klass; | |
1077 } | |
1078 | |
1079 Handle JVMCIRuntime::get_service_impls(KlassHandle serviceKlass, TRAPS) { | |
1080 const char* home = Arguments::get_java_home(); | |
1081 const char* serviceName = serviceKlass->external_name(); | |
1082 | |
1083 size_t path_len = strlen(home) + strlen("/lib/jvmci/services/") + strlen(serviceName) + 1; | |
1084 char* path = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, path_len); | |
1085 char sep = os::file_separator()[0]; | |
1086 sprintf(path, "%s%clib%cjvmci%cservices%c%s", home, sep, sep, sep, sep, serviceName); | |
1087 struct stat st; | |
1088 if (os::stat(path, &st) == 0) { | |
1089 int file_handle = os::open(path, 0, 0); | |
1090 if (file_handle != -1) { | |
1091 char* buffer = NEW_RESOURCE_ARRAY_IN_THREAD(THREAD, char, st.st_size + 1); | |
1092 int num_read = (int) os::read(file_handle, (char*) buffer, st.st_size); | |
1093 if (num_read == -1) { | |
1094 warning("Error reading file %s due to %s", path, strerror(errno)); | |
1095 } else if (num_read != st.st_size) { | |
1096 warning("Only read %d of " SIZE_FORMAT " bytes from %s", num_read, (size_t) st.st_size, path); | |
1097 } | |
1098 os::close(file_handle); | |
1099 if (num_read == st.st_size) { | |
1100 buffer[num_read] = '\0'; | |
1101 GrowableArray<char*>* implNames = new GrowableArray<char*>(); | |
1102 char* line = buffer; | |
1103 while (line - buffer < num_read) { | |
1104 // find line end (\r, \n or \r\n) | |
1105 char* nextline = NULL; | |
1106 char* cr = strchr(line, '\r'); | |
1107 char* lf = strchr(line, '\n'); | |
1108 if (cr != NULL && lf != NULL) { | |
1109 char* min = MIN2(cr, lf); | |
1110 *min = '\0'; | |
1111 if (lf == cr + 1) { | |
1112 nextline = lf + 1; | |
1113 } else { | |
1114 nextline = min + 1; | |
1115 } | |
1116 } else if (cr != NULL) { | |
1117 *cr = '\0'; | |
1118 nextline = cr + 1; | |
1119 } else if (lf != NULL) { | |
1120 *lf = '\0'; | |
1121 nextline = lf + 1; | |
1122 } | |
1123 // trim left | |
1124 while (*line == ' ' || *line == '\t') line++; | |
1125 char* end = line + strlen(line); | |
1126 // trim right | |
1127 while (end > line && (*(end -1) == ' ' || *(end -1) == '\t')) end--; | |
1128 *end = '\0'; | |
1129 // skip comments and empty lines | |
1130 if (*line != '#' && strlen(line) > 0) { | |
1131 // Turn all '.'s into '/'s | |
1132 for (size_t index = 0; line[index] != '\0'; index++) { | |
1133 if (line[index] == '.') { | |
1134 line[index] = '/'; | |
1135 } | |
1136 } | |
1137 implNames->append(line); | |
1138 } | |
1139 if (nextline != NULL) { | |
1140 line = nextline; | |
1141 } else { | |
1142 // File without newline at the end | |
1143 break; | |
1144 } | |
1145 } | |
1146 | |
1147 objArrayOop servicesOop = oopFactory::new_objArray(serviceKlass(), implNames->length(), CHECK_NH); | |
1148 objArrayHandle services(THREAD, servicesOop); | |
1149 for (int i = 0; i < implNames->length(); ++i) { | |
1150 char* implName = implNames->at(i); | |
1151 Handle service = create_Service(implName, CHECK_NH); | |
1152 services->obj_at_put(i, service()); | |
1153 } | |
1154 return services; | |
1155 } | |
1156 } else { | |
1157 warning("Error opening file %s due to %s", path, strerror(errno)); | |
1158 } | |
1159 } else { | |
1160 warning("Error opening file %s due to %s", path, strerror(errno)); | |
1161 } | |
1162 return Handle(); | |
1163 } | |
1164 | |
1165 #include "graalRuntime.inline.hpp" |