| 1 | /* | 
|---|
| 2 | * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved. | 
|---|
| 3 | * Copyright (c) 2012 Red Hat, Inc. | 
|---|
| 4 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | 
|---|
| 5 | * | 
|---|
| 6 | * This code is free software; you can redistribute it and/or modify it | 
|---|
| 7 | * under the terms of the GNU General Public License version 2 only, as | 
|---|
| 8 | * published by the Free Software Foundation. | 
|---|
| 9 | * | 
|---|
| 10 | * This code is distributed in the hope that it will be useful, but WITHOUT | 
|---|
| 11 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | 
|---|
| 12 | * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License | 
|---|
| 13 | * version 2 for more details (a copy is included in the LICENSE file that | 
|---|
| 14 | * accompanied this code). | 
|---|
| 15 | * | 
|---|
| 16 | * You should have received a copy of the GNU General Public License version | 
|---|
| 17 | * 2 along with this work; if not, write to the Free Software Foundation, | 
|---|
| 18 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | 
|---|
| 19 | * | 
|---|
| 20 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | 
|---|
| 21 | * or visit www.oracle.com if you need additional information or have any | 
|---|
| 22 | * questions. | 
|---|
| 23 | * | 
|---|
| 24 | */ | 
|---|
| 25 |  | 
|---|
| 26 | #include "precompiled.hpp" | 
|---|
| 27 | #include "jni.h" | 
|---|
| 28 | #include "jvm.h" | 
|---|
| 29 | #include "ci/ciReplay.hpp" | 
|---|
| 30 | #include "classfile/altHashing.hpp" | 
|---|
| 31 | #include "classfile/classFileStream.hpp" | 
|---|
| 32 | #include "classfile/classLoader.hpp" | 
|---|
| 33 | #include "classfile/javaClasses.hpp" | 
|---|
| 34 | #include "classfile/javaClasses.inline.hpp" | 
|---|
| 35 | #include "classfile/modules.hpp" | 
|---|
| 36 | #include "classfile/symbolTable.hpp" | 
|---|
| 37 | #include "classfile/systemDictionary.hpp" | 
|---|
| 38 | #include "classfile/vmSymbols.hpp" | 
|---|
| 39 | #include "gc/shared/gcLocker.inline.hpp" | 
|---|
| 40 | #include "interpreter/linkResolver.hpp" | 
|---|
| 41 | #include "jfr/jfrEvents.hpp" | 
|---|
| 42 | #include "jfr/support/jfrThreadId.hpp" | 
|---|
| 43 | #include "logging/log.hpp" | 
|---|
| 44 | #include "memory/allocation.hpp" | 
|---|
| 45 | #include "memory/allocation.inline.hpp" | 
|---|
| 46 | #include "memory/oopFactory.hpp" | 
|---|
| 47 | #include "memory/resourceArea.hpp" | 
|---|
| 48 | #include "memory/universe.hpp" | 
|---|
| 49 | #include "oops/access.inline.hpp" | 
|---|
| 50 | #include "oops/arrayOop.inline.hpp" | 
|---|
| 51 | #include "oops/instanceKlass.hpp" | 
|---|
| 52 | #include "oops/instanceOop.hpp" | 
|---|
| 53 | #include "oops/markOop.hpp" | 
|---|
| 54 | #include "oops/method.hpp" | 
|---|
| 55 | #include "oops/objArrayKlass.hpp" | 
|---|
| 56 | #include "oops/objArrayOop.inline.hpp" | 
|---|
| 57 | #include "oops/oop.inline.hpp" | 
|---|
| 58 | #include "oops/symbol.hpp" | 
|---|
| 59 | #include "oops/typeArrayKlass.hpp" | 
|---|
| 60 | #include "oops/typeArrayOop.inline.hpp" | 
|---|
| 61 | #include "prims/jniCheck.hpp" | 
|---|
| 62 | #include "prims/jniExport.hpp" | 
|---|
| 63 | #include "prims/jniFastGetField.hpp" | 
|---|
| 64 | #include "prims/jvm_misc.hpp" | 
|---|
| 65 | #include "prims/jvmtiExport.hpp" | 
|---|
| 66 | #include "prims/jvmtiThreadState.hpp" | 
|---|
| 67 | #include "runtime/atomic.hpp" | 
|---|
| 68 | #include "runtime/compilationPolicy.hpp" | 
|---|
| 69 | #include "runtime/fieldDescriptor.inline.hpp" | 
|---|
| 70 | #include "runtime/handles.inline.hpp" | 
|---|
| 71 | #include "runtime/interfaceSupport.inline.hpp" | 
|---|
| 72 | #include "runtime/java.hpp" | 
|---|
| 73 | #include "runtime/javaCalls.hpp" | 
|---|
| 74 | #include "runtime/jfieldIDWorkaround.hpp" | 
|---|
| 75 | #include "runtime/jniHandles.inline.hpp" | 
|---|
| 76 | #include "runtime/orderAccess.hpp" | 
|---|
| 77 | #include "runtime/reflection.hpp" | 
|---|
| 78 | #include "runtime/safepointVerifiers.hpp" | 
|---|
| 79 | #include "runtime/sharedRuntime.hpp" | 
|---|
| 80 | #include "runtime/signature.hpp" | 
|---|
| 81 | #include "runtime/thread.inline.hpp" | 
|---|
| 82 | #include "runtime/vmOperations.hpp" | 
|---|
| 83 | #include "services/memTracker.hpp" | 
|---|
| 84 | #include "services/runtimeService.hpp" | 
|---|
| 85 | #include "utilities/defaultStream.hpp" | 
|---|
| 86 | #include "utilities/dtrace.hpp" | 
|---|
| 87 | #include "utilities/events.hpp" | 
|---|
| 88 | #include "utilities/histogram.hpp" | 
|---|
| 89 | #include "utilities/macros.hpp" | 
|---|
| 90 | #include "utilities/vmError.hpp" | 
|---|
| 91 |  | 
|---|
| 92 | static jint CurrentVersion = JNI_VERSION_10; | 
|---|
| 93 |  | 
|---|
| 94 | #ifdef _WIN32 | 
|---|
| 95 | extern LONG WINAPI topLevelExceptionFilter(_EXCEPTION_POINTERS* ); | 
|---|
| 96 | #endif | 
|---|
| 97 |  | 
|---|
| 98 | // The DT_RETURN_MARK macros create a scoped object to fire the dtrace | 
|---|
| 99 | // '-return' probe regardless of the return path is taken out of the function. | 
|---|
| 100 | // Methods that have multiple return paths use this to avoid having to | 
|---|
| 101 | // instrument each return path.  Methods that use CHECK or THROW must use this | 
|---|
| 102 | // since those macros can cause an immedate uninstrumented return. | 
|---|
| 103 | // | 
|---|
| 104 | // In order to get the return value, a reference to the variable containing | 
|---|
| 105 | // the return value must be passed to the contructor of the object, and | 
|---|
| 106 | // the return value must be set before return (since the mark object has | 
|---|
| 107 | // a reference to it). | 
|---|
| 108 | // | 
|---|
| 109 | // Example: | 
|---|
| 110 | // DT_RETURN_MARK_DECL(SomeFunc, int); | 
|---|
| 111 | // JNI_ENTRY(int, SomeFunc, ...) | 
|---|
| 112 | //   int return_value = 0; | 
|---|
| 113 | //   DT_RETURN_MARK(SomeFunc, int, (const int&)return_value); | 
|---|
| 114 | //   foo(CHECK_0) | 
|---|
| 115 | //   return_value = 5; | 
|---|
| 116 | //   return return_value; | 
|---|
| 117 | // JNI_END | 
|---|
| 118 | #define DT_RETURN_MARK_DECL(name, type, probe)                             \ | 
|---|
| 119 | DTRACE_ONLY(                                                             \ | 
|---|
| 120 | class DTraceReturnProbeMark_##name {                                   \ | 
|---|
| 121 | public:                                                               \ | 
|---|
| 122 | const type& _ret_ref;                                                \ | 
|---|
| 123 | DTraceReturnProbeMark_##name(const type& v) : _ret_ref(v) {}         \ | 
|---|
| 124 | ~DTraceReturnProbeMark_##name() {                                    \ | 
|---|
| 125 | probe;                                                             \ | 
|---|
| 126 | }                                                                    \ | 
|---|
| 127 | }                                                                      \ | 
|---|
| 128 | ) | 
|---|
| 129 | // Void functions are simpler since there's no return value | 
|---|
| 130 | #define DT_VOID_RETURN_MARK_DECL(name, probe)                              \ | 
|---|
| 131 | DTRACE_ONLY(                                                             \ | 
|---|
| 132 | class DTraceReturnProbeMark_##name {                                   \ | 
|---|
| 133 | public:                                                               \ | 
|---|
| 134 | ~DTraceReturnProbeMark_##name() {                                    \ | 
|---|
| 135 | probe;                                                             \ | 
|---|
| 136 | }                                                                    \ | 
|---|
| 137 | }                                                                      \ | 
|---|
| 138 | ) | 
|---|
| 139 |  | 
|---|
| 140 | // Place these macros in the function to mark the return.  Non-void | 
|---|
| 141 | // functions need the type and address of the return value. | 
|---|
| 142 | #define DT_RETURN_MARK(name, type, ref) \ | 
|---|
| 143 | DTRACE_ONLY( DTraceReturnProbeMark_##name dtrace_return_mark(ref) ) | 
|---|
| 144 | #define DT_VOID_RETURN_MARK(name) \ | 
|---|
| 145 | DTRACE_ONLY( DTraceReturnProbeMark_##name dtrace_return_mark ) | 
|---|
| 146 |  | 
|---|
| 147 |  | 
|---|
| 148 | // Use these to select distinct code for floating-point vs. non-floating point | 
|---|
| 149 | // situations.  Used from within common macros where we need slightly | 
|---|
| 150 | // different behavior for Float/Double | 
|---|
| 151 | #define FP_SELECT_Boolean(intcode, fpcode) intcode | 
|---|
| 152 | #define FP_SELECT_Byte(intcode, fpcode)    intcode | 
|---|
| 153 | #define FP_SELECT_Char(intcode, fpcode)    intcode | 
|---|
| 154 | #define FP_SELECT_Short(intcode, fpcode)   intcode | 
|---|
| 155 | #define FP_SELECT_Object(intcode, fpcode)  intcode | 
|---|
| 156 | #define FP_SELECT_Int(intcode, fpcode)     intcode | 
|---|
| 157 | #define FP_SELECT_Long(intcode, fpcode)    intcode | 
|---|
| 158 | #define FP_SELECT_Float(intcode, fpcode)   fpcode | 
|---|
| 159 | #define FP_SELECT_Double(intcode, fpcode)  fpcode | 
|---|
| 160 | #define FP_SELECT(TypeName, intcode, fpcode) \ | 
|---|
| 161 | FP_SELECT_##TypeName(intcode, fpcode) | 
|---|
| 162 |  | 
|---|
| 163 | // Choose DT_RETURN_MARK macros  based on the type: float/double -> void | 
|---|
| 164 | // (dtrace doesn't do FP yet) | 
|---|
| 165 | #define DT_RETURN_MARK_DECL_FOR(TypeName, name, type, probe)    \ | 
|---|
| 166 | FP_SELECT(TypeName, \ | 
|---|
| 167 | DT_RETURN_MARK_DECL(name, type, probe), DT_VOID_RETURN_MARK_DECL(name, probe) ) | 
|---|
| 168 | #define DT_RETURN_MARK_FOR(TypeName, name, type, ref) \ | 
|---|
| 169 | FP_SELECT(TypeName, \ | 
|---|
| 170 | DT_RETURN_MARK(name, type, ref), DT_VOID_RETURN_MARK(name) ) | 
|---|
| 171 |  | 
|---|
| 172 |  | 
|---|
| 173 | // out-of-line helpers for class jfieldIDWorkaround: | 
|---|
| 174 |  | 
|---|
| 175 | bool jfieldIDWorkaround::is_valid_jfieldID(Klass* k, jfieldID id) { | 
|---|
| 176 | if (jfieldIDWorkaround::is_instance_jfieldID(k, id)) { | 
|---|
| 177 | uintptr_t as_uint = (uintptr_t) id; | 
|---|
| 178 | intptr_t offset = raw_instance_offset(id); | 
|---|
| 179 | if (is_checked_jfieldID(id)) { | 
|---|
| 180 | if (!klass_hash_ok(k, id)) { | 
|---|
| 181 | return false; | 
|---|
| 182 | } | 
|---|
| 183 | } | 
|---|
| 184 | return InstanceKlass::cast(k)->contains_field_offset(offset); | 
|---|
| 185 | } else { | 
|---|
| 186 | JNIid* result = (JNIid*) id; | 
|---|
| 187 | #ifdef ASSERT | 
|---|
| 188 | return result != NULL && result->is_static_field_id(); | 
|---|
| 189 | #else | 
|---|
| 190 | return result != NULL; | 
|---|
| 191 | #endif | 
|---|
| 192 | } | 
|---|
| 193 | } | 
|---|
| 194 |  | 
|---|
| 195 |  | 
|---|
| 196 | intptr_t jfieldIDWorkaround::encode_klass_hash(Klass* k, intptr_t offset) { | 
|---|
| 197 | if (offset <= small_offset_mask) { | 
|---|
| 198 | Klass* field_klass = k; | 
|---|
| 199 | Klass* super_klass = field_klass->super(); | 
|---|
| 200 | // With compressed oops the most super class with nonstatic fields would | 
|---|
| 201 | // be the owner of fields embedded in the header. | 
|---|
| 202 | while (InstanceKlass::cast(super_klass)->has_nonstatic_fields() && | 
|---|
| 203 | InstanceKlass::cast(super_klass)->contains_field_offset(offset)) { | 
|---|
| 204 | field_klass = super_klass;   // super contains the field also | 
|---|
| 205 | super_klass = field_klass->super(); | 
|---|
| 206 | } | 
|---|
| 207 | debug_only(NoSafepointVerifier nosafepoint;) | 
|---|
| 208 | uintptr_t klass_hash = field_klass->identity_hash(); | 
|---|
| 209 | return ((klass_hash & klass_mask) << klass_shift) | checked_mask_in_place; | 
|---|
| 210 | } else { | 
|---|
| 211 | #if 0 | 
|---|
| 212 | #ifndef PRODUCT | 
|---|
| 213 | { | 
|---|
| 214 | ResourceMark rm; | 
|---|
| 215 | warning( "VerifyJNIFields: long offset %d in %s", offset, k->external_name()); | 
|---|
| 216 | } | 
|---|
| 217 | #endif | 
|---|
| 218 | #endif | 
|---|
| 219 | return 0; | 
|---|
| 220 | } | 
|---|
| 221 | } | 
|---|
| 222 |  | 
|---|
| 223 | bool jfieldIDWorkaround::klass_hash_ok(Klass* k, jfieldID id) { | 
|---|
| 224 | uintptr_t as_uint = (uintptr_t) id; | 
|---|
| 225 | intptr_t klass_hash = (as_uint >> klass_shift) & klass_mask; | 
|---|
| 226 | do { | 
|---|
| 227 | debug_only(NoSafepointVerifier nosafepoint;) | 
|---|
| 228 | // Could use a non-blocking query for identity_hash here... | 
|---|
| 229 | if ((k->identity_hash() & klass_mask) == klass_hash) | 
|---|
| 230 | return true; | 
|---|
| 231 | k = k->super(); | 
|---|
| 232 | } while (k != NULL); | 
|---|
| 233 | return false; | 
|---|
| 234 | } | 
|---|
| 235 |  | 
|---|
| 236 | void jfieldIDWorkaround::verify_instance_jfieldID(Klass* k, jfieldID id) { | 
|---|
| 237 | guarantee(jfieldIDWorkaround::is_instance_jfieldID(k, id), "must be an instance field"); | 
|---|
| 238 | uintptr_t as_uint = (uintptr_t) id; | 
|---|
| 239 | intptr_t offset = raw_instance_offset(id); | 
|---|
| 240 | if (VerifyJNIFields) { | 
|---|
| 241 | if (is_checked_jfieldID(id)) { | 
|---|
| 242 | guarantee(klass_hash_ok(k, id), | 
|---|
| 243 | "Bug in native code: jfieldID class must match object"); | 
|---|
| 244 | } else { | 
|---|
| 245 | #if 0 | 
|---|
| 246 | #ifndef PRODUCT | 
|---|
| 247 | if (Verbose) { | 
|---|
| 248 | ResourceMark rm; | 
|---|
| 249 | warning( "VerifyJNIFields: unverified offset %d for %s", offset, k->external_name()); | 
|---|
| 250 | } | 
|---|
| 251 | #endif | 
|---|
| 252 | #endif | 
|---|
| 253 | } | 
|---|
| 254 | } | 
|---|
| 255 | guarantee(InstanceKlass::cast(k)->contains_field_offset(offset), | 
|---|
| 256 | "Bug in native code: jfieldID offset must address interior of object"); | 
|---|
| 257 | } | 
|---|
| 258 |  | 
|---|
| 259 | // Wrapper to trace JNI functions | 
|---|
| 260 |  | 
|---|
| 261 | #ifdef ASSERT | 
|---|
| 262 | Histogram* JNIHistogram; | 
|---|
| 263 | static volatile int JNIHistogram_lock = 0; | 
|---|
| 264 |  | 
|---|
| 265 | class JNIHistogramElement : public HistogramElement { | 
|---|
| 266 | public: | 
|---|
| 267 | JNIHistogramElement(const char* name); | 
|---|
| 268 | }; | 
|---|
| 269 |  | 
|---|
| 270 | JNIHistogramElement::JNIHistogramElement(const char* elementName) { | 
|---|
| 271 | _name = elementName; | 
|---|
| 272 | uintx count = 0; | 
|---|
| 273 |  | 
|---|
| 274 | while (Atomic::cmpxchg(1, &JNIHistogram_lock, 0) != 0) { | 
|---|
| 275 | while (OrderAccess::load_acquire(&JNIHistogram_lock) != 0) { | 
|---|
| 276 | count +=1; | 
|---|
| 277 | if ( (WarnOnStalledSpinLock > 0) | 
|---|
| 278 | && (count % WarnOnStalledSpinLock == 0)) { | 
|---|
| 279 | warning( "JNIHistogram_lock seems to be stalled"); | 
|---|
| 280 | } | 
|---|
| 281 | } | 
|---|
| 282 | } | 
|---|
| 283 |  | 
|---|
| 284 |  | 
|---|
| 285 | if(JNIHistogram == NULL) | 
|---|
| 286 | JNIHistogram = new Histogram( "JNI Call Counts",100); | 
|---|
| 287 |  | 
|---|
| 288 | JNIHistogram->add_element(this); | 
|---|
| 289 | Atomic::dec(&JNIHistogram_lock); | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | #define JNICountWrapper(arg)                                     \ | 
|---|
| 293 | static JNIHistogramElement* e = new JNIHistogramElement(arg); \ | 
|---|
| 294 | /* There is a MT-race condition in VC++. So we need to make sure that that e has been initialized */ \ | 
|---|
| 295 | if (e != NULL) e->increment_count() | 
|---|
| 296 | #define JNIWrapper(arg) JNICountWrapper(arg); | 
|---|
| 297 | #else | 
|---|
| 298 | #define JNIWrapper(arg) | 
|---|
| 299 | #endif | 
|---|
| 300 |  | 
|---|
| 301 |  | 
|---|
| 302 | // Implementation of JNI entries | 
|---|
| 303 |  | 
|---|
| 304 | DT_RETURN_MARK_DECL(DefineClass, jclass | 
|---|
| 305 | , HOTSPOT_JNI_DEFINECLASS_RETURN(_ret_ref)); | 
|---|
| 306 |  | 
|---|
| 307 | JNI_ENTRY(jclass, jni_DefineClass(JNIEnv *env, const char *name, jobject loaderRef, | 
|---|
| 308 | const jbyte *buf, jsize bufLen)) | 
|---|
| 309 | JNIWrapper( "DefineClass"); | 
|---|
| 310 |  | 
|---|
| 311 | HOTSPOT_JNI_DEFINECLASS_ENTRY( | 
|---|
| 312 | env, (char*) name, loaderRef, (char*) buf, bufLen); | 
|---|
| 313 |  | 
|---|
| 314 | jclass cls = NULL; | 
|---|
| 315 | DT_RETURN_MARK(DefineClass, jclass, (const jclass&)cls); | 
|---|
| 316 |  | 
|---|
| 317 | TempNewSymbol class_name = NULL; | 
|---|
| 318 | // Since exceptions can be thrown, class initialization can take place | 
|---|
| 319 | // if name is NULL no check for class name in .class stream has to be made. | 
|---|
| 320 | if (name != NULL) { | 
|---|
| 321 | const int str_len = (int)strlen(name); | 
|---|
| 322 | if (str_len > Symbol::max_length()) { | 
|---|
| 323 | // It's impossible to create this class;  the name cannot fit | 
|---|
| 324 | // into the constant pool. | 
|---|
| 325 | Exceptions::fthrow(THREAD_AND_LOCATION, | 
|---|
| 326 | vmSymbols::java_lang_NoClassDefFoundError(), | 
|---|
| 327 | "Class name exceeds maximum length of %d: %s", | 
|---|
| 328 | Symbol::max_length(), | 
|---|
| 329 | name); | 
|---|
| 330 | return 0; | 
|---|
| 331 | } | 
|---|
| 332 | class_name = SymbolTable::new_symbol(name); | 
|---|
| 333 | } | 
|---|
| 334 | ResourceMark rm(THREAD); | 
|---|
| 335 | ClassFileStream st((u1*)buf, bufLen, NULL, ClassFileStream::verify); | 
|---|
| 336 | Handle class_loader (THREAD, JNIHandles::resolve(loaderRef)); | 
|---|
| 337 |  | 
|---|
| 338 | if (UsePerfData && !class_loader.is_null()) { | 
|---|
| 339 | // check whether the current caller thread holds the lock or not. | 
|---|
| 340 | // If not, increment the corresponding counter | 
|---|
| 341 | if (ObjectSynchronizer:: | 
|---|
| 342 | query_lock_ownership((JavaThread*)THREAD, class_loader) != | 
|---|
| 343 | ObjectSynchronizer::owner_self) { | 
|---|
| 344 | ClassLoader::sync_JNIDefineClassLockFreeCounter()->inc(); | 
|---|
| 345 | } | 
|---|
| 346 | } | 
|---|
| 347 | Klass* k = SystemDictionary::resolve_from_stream(class_name, | 
|---|
| 348 | class_loader, | 
|---|
| 349 | Handle(), | 
|---|
| 350 | &st, | 
|---|
| 351 | CHECK_NULL); | 
|---|
| 352 |  | 
|---|
| 353 | if (log_is_enabled(Debug, class, resolve) && k != NULL) { | 
|---|
| 354 | trace_class_resolution(k); | 
|---|
| 355 | } | 
|---|
| 356 |  | 
|---|
| 357 | cls = (jclass)JNIHandles::make_local( | 
|---|
| 358 | env, k->java_mirror()); | 
|---|
| 359 | return cls; | 
|---|
| 360 | JNI_END | 
|---|
| 361 |  | 
|---|
| 362 |  | 
|---|
| 363 |  | 
|---|
| 364 | DT_RETURN_MARK_DECL(FindClass, jclass | 
|---|
| 365 | , HOTSPOT_JNI_FINDCLASS_RETURN(_ret_ref)); | 
|---|
| 366 |  | 
|---|
| 367 | JNI_ENTRY(jclass, jni_FindClass(JNIEnv *env, const char *name)) | 
|---|
| 368 | JNIWrapper( "FindClass"); | 
|---|
| 369 |  | 
|---|
| 370 | HOTSPOT_JNI_FINDCLASS_ENTRY(env, (char *)name); | 
|---|
| 371 |  | 
|---|
| 372 | jclass result = NULL; | 
|---|
| 373 | DT_RETURN_MARK(FindClass, jclass, (const jclass&)result); | 
|---|
| 374 |  | 
|---|
| 375 | // Sanity check the name:  it cannot be null or larger than the maximum size | 
|---|
| 376 | // name we can fit in the constant pool. | 
|---|
| 377 | if (name == NULL) { | 
|---|
| 378 | THROW_MSG_0(vmSymbols::java_lang_NoClassDefFoundError(), "No class name given"); | 
|---|
| 379 | } | 
|---|
| 380 | if ((int)strlen(name) > Symbol::max_length()) { | 
|---|
| 381 | Exceptions::fthrow(THREAD_AND_LOCATION, | 
|---|
| 382 | vmSymbols::java_lang_NoClassDefFoundError(), | 
|---|
| 383 | "Class name exceeds maximum length of %d: %s", | 
|---|
| 384 | Symbol::max_length(), | 
|---|
| 385 | name); | 
|---|
| 386 | return 0; | 
|---|
| 387 | } | 
|---|
| 388 |  | 
|---|
| 389 | //%note jni_3 | 
|---|
| 390 | Handle protection_domain; | 
|---|
| 391 | // Find calling class | 
|---|
| 392 | Klass* k = thread->security_get_caller_class(0); | 
|---|
| 393 | // default to the system loader when no context | 
|---|
| 394 | Handle loader(THREAD, SystemDictionary::java_system_loader()); | 
|---|
| 395 | if (k != NULL) { | 
|---|
| 396 | // Special handling to make sure JNI_OnLoad and JNI_OnUnload are executed | 
|---|
| 397 | // in the correct class context. | 
|---|
| 398 | if (k->class_loader() == NULL && | 
|---|
| 399 | k->name() == vmSymbols::java_lang_ClassLoader_NativeLibrary()) { | 
|---|
| 400 | JavaValue result(T_OBJECT); | 
|---|
| 401 | JavaCalls::call_static(&result, k, | 
|---|
| 402 | vmSymbols::getFromClass_name(), | 
|---|
| 403 | vmSymbols::void_class_signature(), | 
|---|
| 404 | CHECK_NULL); | 
|---|
| 405 | // When invoked from JNI_OnLoad, NativeLibrary::getFromClass returns | 
|---|
| 406 | // a non-NULL Class object.  When invoked from JNI_OnUnload, | 
|---|
| 407 | // it will return NULL to indicate no context. | 
|---|
| 408 | oop mirror = (oop) result.get_jobject(); | 
|---|
| 409 | if (mirror != NULL) { | 
|---|
| 410 | Klass* fromClass = java_lang_Class::as_Klass(mirror); | 
|---|
| 411 | loader = Handle(THREAD, fromClass->class_loader()); | 
|---|
| 412 | protection_domain = Handle(THREAD, fromClass->protection_domain()); | 
|---|
| 413 | } | 
|---|
| 414 | } else { | 
|---|
| 415 | loader = Handle(THREAD, k->class_loader()); | 
|---|
| 416 | } | 
|---|
| 417 | } | 
|---|
| 418 |  | 
|---|
| 419 | TempNewSymbol sym = SymbolTable::new_symbol(name); | 
|---|
| 420 | result = find_class_from_class_loader(env, sym, true, loader, | 
|---|
| 421 | protection_domain, true, thread); | 
|---|
| 422 |  | 
|---|
| 423 | if (log_is_enabled(Debug, class, resolve) && result != NULL) { | 
|---|
| 424 | trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); | 
|---|
| 425 | } | 
|---|
| 426 |  | 
|---|
| 427 | return result; | 
|---|
| 428 | JNI_END | 
|---|
| 429 |  | 
|---|
| 430 | DT_RETURN_MARK_DECL(FromReflectedMethod, jmethodID | 
|---|
| 431 | , HOTSPOT_JNI_FROMREFLECTEDMETHOD_RETURN((uintptr_t)_ret_ref)); | 
|---|
| 432 |  | 
|---|
| 433 | JNI_ENTRY(jmethodID, jni_FromReflectedMethod(JNIEnv *env, jobject method)) | 
|---|
| 434 | JNIWrapper( "FromReflectedMethod"); | 
|---|
| 435 |  | 
|---|
| 436 | HOTSPOT_JNI_FROMREFLECTEDMETHOD_ENTRY(env, method); | 
|---|
| 437 |  | 
|---|
| 438 | jmethodID ret = NULL; | 
|---|
| 439 | DT_RETURN_MARK(FromReflectedMethod, jmethodID, (const jmethodID&)ret); | 
|---|
| 440 |  | 
|---|
| 441 | // method is a handle to a java.lang.reflect.Method object | 
|---|
| 442 | oop reflected  = JNIHandles::resolve_non_null(method); | 
|---|
| 443 | oop mirror     = NULL; | 
|---|
| 444 | int slot       = 0; | 
|---|
| 445 |  | 
|---|
| 446 | if (reflected->klass() == SystemDictionary::reflect_Constructor_klass()) { | 
|---|
| 447 | mirror = java_lang_reflect_Constructor::clazz(reflected); | 
|---|
| 448 | slot   = java_lang_reflect_Constructor::slot(reflected); | 
|---|
| 449 | } else { | 
|---|
| 450 | assert(reflected->klass() == SystemDictionary::reflect_Method_klass(), "wrong type"); | 
|---|
| 451 | mirror = java_lang_reflect_Method::clazz(reflected); | 
|---|
| 452 | slot   = java_lang_reflect_Method::slot(reflected); | 
|---|
| 453 | } | 
|---|
| 454 | Klass* k1 = java_lang_Class::as_Klass(mirror); | 
|---|
| 455 |  | 
|---|
| 456 | // Make sure class is initialized before handing id's out to methods | 
|---|
| 457 | k1->initialize(CHECK_NULL); | 
|---|
| 458 | Method* m = InstanceKlass::cast(k1)->method_with_idnum(slot); | 
|---|
| 459 | ret = m==NULL? NULL : m->jmethod_id();  // return NULL if reflected method deleted | 
|---|
| 460 | return ret; | 
|---|
| 461 | JNI_END | 
|---|
| 462 |  | 
|---|
| 463 | DT_RETURN_MARK_DECL(FromReflectedField, jfieldID | 
|---|
| 464 | , HOTSPOT_JNI_FROMREFLECTEDFIELD_RETURN((uintptr_t)_ret_ref)); | 
|---|
| 465 |  | 
|---|
| 466 | JNI_ENTRY(jfieldID, jni_FromReflectedField(JNIEnv *env, jobject field)) | 
|---|
| 467 | JNIWrapper( "FromReflectedField"); | 
|---|
| 468 |  | 
|---|
| 469 | HOTSPOT_JNI_FROMREFLECTEDFIELD_ENTRY(env, field); | 
|---|
| 470 |  | 
|---|
| 471 | jfieldID ret = NULL; | 
|---|
| 472 | DT_RETURN_MARK(FromReflectedField, jfieldID, (const jfieldID&)ret); | 
|---|
| 473 |  | 
|---|
| 474 | // field is a handle to a java.lang.reflect.Field object | 
|---|
| 475 | oop reflected   = JNIHandles::resolve_non_null(field); | 
|---|
| 476 | oop mirror      = java_lang_reflect_Field::clazz(reflected); | 
|---|
| 477 | Klass* k1       = java_lang_Class::as_Klass(mirror); | 
|---|
| 478 | int slot        = java_lang_reflect_Field::slot(reflected); | 
|---|
| 479 | int modifiers   = java_lang_reflect_Field::modifiers(reflected); | 
|---|
| 480 |  | 
|---|
| 481 | // Make sure class is initialized before handing id's out to fields | 
|---|
| 482 | k1->initialize(CHECK_NULL); | 
|---|
| 483 |  | 
|---|
| 484 | // First check if this is a static field | 
|---|
| 485 | if (modifiers & JVM_ACC_STATIC) { | 
|---|
| 486 | intptr_t offset = InstanceKlass::cast(k1)->field_offset( slot ); | 
|---|
| 487 | JNIid* id = InstanceKlass::cast(k1)->jni_id_for(offset); | 
|---|
| 488 | assert(id != NULL, "corrupt Field object"); | 
|---|
| 489 | debug_only(id->set_is_static_field_id();) | 
|---|
| 490 | // A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass* | 
|---|
| 491 | ret = jfieldIDWorkaround::to_static_jfieldID(id); | 
|---|
| 492 | return ret; | 
|---|
| 493 | } | 
|---|
| 494 |  | 
|---|
| 495 | // The slot is the index of the field description in the field-array | 
|---|
| 496 | // The jfieldID is the offset of the field within the object | 
|---|
| 497 | // It may also have hash bits for k, if VerifyJNIFields is turned on. | 
|---|
| 498 | intptr_t offset = InstanceKlass::cast(k1)->field_offset( slot ); | 
|---|
| 499 | assert(InstanceKlass::cast(k1)->contains_field_offset(offset), "stay within object"); | 
|---|
| 500 | ret = jfieldIDWorkaround::to_instance_jfieldID(k1, offset); | 
|---|
| 501 | return ret; | 
|---|
| 502 | JNI_END | 
|---|
| 503 |  | 
|---|
| 504 |  | 
|---|
| 505 | DT_RETURN_MARK_DECL(ToReflectedMethod, jobject | 
|---|
| 506 | , HOTSPOT_JNI_TOREFLECTEDMETHOD_RETURN(_ret_ref)); | 
|---|
| 507 |  | 
|---|
| 508 | JNI_ENTRY(jobject, jni_ToReflectedMethod(JNIEnv *env, jclass cls, jmethodID method_id, jboolean isStatic)) | 
|---|
| 509 | JNIWrapper( "ToReflectedMethod"); | 
|---|
| 510 |  | 
|---|
| 511 | HOTSPOT_JNI_TOREFLECTEDMETHOD_ENTRY(env, cls, (uintptr_t) method_id, isStatic); | 
|---|
| 512 |  | 
|---|
| 513 | jobject ret = NULL; | 
|---|
| 514 | DT_RETURN_MARK(ToReflectedMethod, jobject, (const jobject&)ret); | 
|---|
| 515 |  | 
|---|
| 516 | methodHandle m (THREAD, Method::resolve_jmethod_id(method_id)); | 
|---|
| 517 | assert(m->is_static() == (isStatic != 0), "jni_ToReflectedMethod access flags doesn't match"); | 
|---|
| 518 | oop reflection_method; | 
|---|
| 519 | if (m->is_initializer()) { | 
|---|
| 520 | reflection_method = Reflection::new_constructor(m, CHECK_NULL); | 
|---|
| 521 | } else { | 
|---|
| 522 | reflection_method = Reflection::new_method(m, false, CHECK_NULL); | 
|---|
| 523 | } | 
|---|
| 524 | ret = JNIHandles::make_local(env, reflection_method); | 
|---|
| 525 | return ret; | 
|---|
| 526 | JNI_END | 
|---|
| 527 |  | 
|---|
| 528 | DT_RETURN_MARK_DECL(GetSuperclass, jclass | 
|---|
| 529 | , HOTSPOT_JNI_GETSUPERCLASS_RETURN(_ret_ref)); | 
|---|
| 530 |  | 
|---|
| 531 | JNI_ENTRY(jclass, jni_GetSuperclass(JNIEnv *env, jclass sub)) | 
|---|
| 532 | JNIWrapper( "GetSuperclass"); | 
|---|
| 533 |  | 
|---|
| 534 | HOTSPOT_JNI_GETSUPERCLASS_ENTRY(env, sub); | 
|---|
| 535 |  | 
|---|
| 536 | jclass obj = NULL; | 
|---|
| 537 | DT_RETURN_MARK(GetSuperclass, jclass, (const jclass&)obj); | 
|---|
| 538 |  | 
|---|
| 539 | oop mirror = JNIHandles::resolve_non_null(sub); | 
|---|
| 540 | // primitive classes return NULL | 
|---|
| 541 | if (java_lang_Class::is_primitive(mirror)) return NULL; | 
|---|
| 542 |  | 
|---|
| 543 | // Rules of Class.getSuperClass as implemented by KLass::java_super: | 
|---|
| 544 | // arrays return Object | 
|---|
| 545 | // interfaces return NULL | 
|---|
| 546 | // proper classes return Klass::super() | 
|---|
| 547 | Klass* k = java_lang_Class::as_Klass(mirror); | 
|---|
| 548 | if (k->is_interface()) return NULL; | 
|---|
| 549 |  | 
|---|
| 550 | // return mirror for superclass | 
|---|
| 551 | Klass* super = k->java_super(); | 
|---|
| 552 | // super2 is the value computed by the compiler's getSuperClass intrinsic: | 
|---|
| 553 | debug_only(Klass* super2 = ( k->is_array_klass() | 
|---|
| 554 | ? SystemDictionary::Object_klass() | 
|---|
| 555 | : k->super() ) ); | 
|---|
| 556 | assert(super == super2, | 
|---|
| 557 | "java_super computation depends on interface, array, other super"); | 
|---|
| 558 | obj = (super == NULL) ? NULL : (jclass) JNIHandles::make_local(super->java_mirror()); | 
|---|
| 559 | return obj; | 
|---|
| 560 | JNI_END | 
|---|
| 561 |  | 
|---|
| 562 | JNI_QUICK_ENTRY(jboolean, jni_IsAssignableFrom(JNIEnv *env, jclass sub, jclass super)) | 
|---|
| 563 | JNIWrapper( "IsSubclassOf"); | 
|---|
| 564 |  | 
|---|
| 565 | HOTSPOT_JNI_ISASSIGNABLEFROM_ENTRY(env, sub, super); | 
|---|
| 566 |  | 
|---|
| 567 | oop sub_mirror   = JNIHandles::resolve_non_null(sub); | 
|---|
| 568 | oop super_mirror = JNIHandles::resolve_non_null(super); | 
|---|
| 569 | if (java_lang_Class::is_primitive(sub_mirror) || | 
|---|
| 570 | java_lang_Class::is_primitive(super_mirror)) { | 
|---|
| 571 | jboolean ret = oopDesc::equals(sub_mirror, super_mirror); | 
|---|
| 572 |  | 
|---|
| 573 | HOTSPOT_JNI_ISASSIGNABLEFROM_RETURN(ret); | 
|---|
| 574 | return ret; | 
|---|
| 575 | } | 
|---|
| 576 | Klass* sub_klass   = java_lang_Class::as_Klass(sub_mirror); | 
|---|
| 577 | Klass* super_klass = java_lang_Class::as_Klass(super_mirror); | 
|---|
| 578 | assert(sub_klass != NULL && super_klass != NULL, "invalid arguments to jni_IsAssignableFrom"); | 
|---|
| 579 | jboolean ret = sub_klass->is_subtype_of(super_klass) ? | 
|---|
| 580 | JNI_TRUE : JNI_FALSE; | 
|---|
| 581 |  | 
|---|
| 582 | HOTSPOT_JNI_ISASSIGNABLEFROM_RETURN(ret); | 
|---|
| 583 | return ret; | 
|---|
| 584 | JNI_END | 
|---|
| 585 |  | 
|---|
| 586 |  | 
|---|
| 587 | DT_RETURN_MARK_DECL(Throw, jint | 
|---|
| 588 | , HOTSPOT_JNI_THROW_RETURN(_ret_ref)); | 
|---|
| 589 |  | 
|---|
| 590 | JNI_ENTRY(jint, jni_Throw(JNIEnv *env, jthrowable obj)) | 
|---|
| 591 | JNIWrapper( "Throw"); | 
|---|
| 592 |  | 
|---|
| 593 | HOTSPOT_JNI_THROW_ENTRY(env, obj); | 
|---|
| 594 |  | 
|---|
| 595 | jint ret = JNI_OK; | 
|---|
| 596 | DT_RETURN_MARK(Throw, jint, (const jint&)ret); | 
|---|
| 597 |  | 
|---|
| 598 | THROW_OOP_(JNIHandles::resolve(obj), JNI_OK); | 
|---|
| 599 | ShouldNotReachHere(); | 
|---|
| 600 | return 0;  // Mute compiler. | 
|---|
| 601 | JNI_END | 
|---|
| 602 |  | 
|---|
| 603 |  | 
|---|
| 604 | DT_RETURN_MARK_DECL(ThrowNew, jint | 
|---|
| 605 | , HOTSPOT_JNI_THROWNEW_RETURN(_ret_ref)); | 
|---|
| 606 |  | 
|---|
| 607 | JNI_ENTRY(jint, jni_ThrowNew(JNIEnv *env, jclass clazz, const char *message)) | 
|---|
| 608 | JNIWrapper( "ThrowNew"); | 
|---|
| 609 |  | 
|---|
| 610 | HOTSPOT_JNI_THROWNEW_ENTRY(env, clazz, (char *) message); | 
|---|
| 611 |  | 
|---|
| 612 | jint ret = JNI_OK; | 
|---|
| 613 | DT_RETURN_MARK(ThrowNew, jint, (const jint&)ret); | 
|---|
| 614 |  | 
|---|
| 615 | InstanceKlass* k = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz))); | 
|---|
| 616 | Symbol*  name = k->name(); | 
|---|
| 617 | Handle class_loader (THREAD,  k->class_loader()); | 
|---|
| 618 | Handle protection_domain (THREAD, k->protection_domain()); | 
|---|
| 619 | THROW_MSG_LOADER_(name, (char *)message, class_loader, protection_domain, JNI_OK); | 
|---|
| 620 | ShouldNotReachHere(); | 
|---|
| 621 | return 0;  // Mute compiler. | 
|---|
| 622 | JNI_END | 
|---|
| 623 |  | 
|---|
| 624 |  | 
|---|
| 625 | // JNI functions only transform a pending async exception to a synchronous | 
|---|
| 626 | // exception in ExceptionOccurred and ExceptionCheck calls, since | 
|---|
| 627 | // delivering an async exception in other places won't change the native | 
|---|
| 628 | // code's control flow and would be harmful when native code further calls | 
|---|
| 629 | // JNI functions with a pending exception. Async exception is also checked | 
|---|
| 630 | // during the call, so ExceptionOccurred/ExceptionCheck won't return | 
|---|
| 631 | // false but deliver the async exception at the very end during | 
|---|
| 632 | // state transition. | 
|---|
| 633 |  | 
|---|
| 634 | static void jni_check_async_exceptions(JavaThread *thread) { | 
|---|
| 635 | assert(thread == Thread::current(), "must be itself"); | 
|---|
| 636 | thread->check_and_handle_async_exceptions(); | 
|---|
| 637 | } | 
|---|
| 638 |  | 
|---|
| 639 | JNI_ENTRY_NO_PRESERVE(jthrowable, jni_ExceptionOccurred(JNIEnv *env)) | 
|---|
| 640 | JNIWrapper( "ExceptionOccurred"); | 
|---|
| 641 |  | 
|---|
| 642 | HOTSPOT_JNI_EXCEPTIONOCCURRED_ENTRY(env); | 
|---|
| 643 |  | 
|---|
| 644 | jni_check_async_exceptions(thread); | 
|---|
| 645 | oop exception = thread->pending_exception(); | 
|---|
| 646 | jthrowable ret = (jthrowable) JNIHandles::make_local(env, exception); | 
|---|
| 647 |  | 
|---|
| 648 | HOTSPOT_JNI_EXCEPTIONOCCURRED_RETURN(ret); | 
|---|
| 649 | return ret; | 
|---|
| 650 | JNI_END | 
|---|
| 651 |  | 
|---|
| 652 |  | 
|---|
| 653 | JNI_ENTRY_NO_PRESERVE(void, jni_ExceptionDescribe(JNIEnv *env)) | 
|---|
| 654 | JNIWrapper( "ExceptionDescribe"); | 
|---|
| 655 |  | 
|---|
| 656 | HOTSPOT_JNI_EXCEPTIONDESCRIBE_ENTRY(env); | 
|---|
| 657 |  | 
|---|
| 658 | if (thread->has_pending_exception()) { | 
|---|
| 659 | Handle ex(thread, thread->pending_exception()); | 
|---|
| 660 | thread->clear_pending_exception(); | 
|---|
| 661 | if (ex->is_a(SystemDictionary::ThreadDeath_klass())) { | 
|---|
| 662 | // Don't print anything if we are being killed. | 
|---|
| 663 | } else { | 
|---|
| 664 | jio_fprintf(defaultStream::error_stream(), "Exception "); | 
|---|
| 665 | if (thread != NULL && thread->threadObj() != NULL) { | 
|---|
| 666 | ResourceMark rm(THREAD); | 
|---|
| 667 | jio_fprintf(defaultStream::error_stream(), | 
|---|
| 668 | "in thread \"%s\" ", thread->get_thread_name()); | 
|---|
| 669 | } | 
|---|
| 670 | if (ex->is_a(SystemDictionary::Throwable_klass())) { | 
|---|
| 671 | JavaValue result(T_VOID); | 
|---|
| 672 | JavaCalls::call_virtual(&result, | 
|---|
| 673 | ex, | 
|---|
| 674 | SystemDictionary::Throwable_klass(), | 
|---|
| 675 | vmSymbols::printStackTrace_name(), | 
|---|
| 676 | vmSymbols::void_method_signature(), | 
|---|
| 677 | THREAD); | 
|---|
| 678 | // If an exception is thrown in the call it gets thrown away. Not much | 
|---|
| 679 | // we can do with it. The native code that calls this, does not check | 
|---|
| 680 | // for the exception - hence, it might still be in the thread when DestroyVM gets | 
|---|
| 681 | // called, potentially causing a few asserts to trigger - since no pending exception | 
|---|
| 682 | // is expected. | 
|---|
| 683 | CLEAR_PENDING_EXCEPTION; | 
|---|
| 684 | } else { | 
|---|
| 685 | ResourceMark rm(THREAD); | 
|---|
| 686 | jio_fprintf(defaultStream::error_stream(), | 
|---|
| 687 | ". Uncaught exception of type %s.", | 
|---|
| 688 | ex->klass()->external_name()); | 
|---|
| 689 | } | 
|---|
| 690 | } | 
|---|
| 691 | } | 
|---|
| 692 |  | 
|---|
| 693 | HOTSPOT_JNI_EXCEPTIONDESCRIBE_RETURN(); | 
|---|
| 694 | JNI_END | 
|---|
| 695 |  | 
|---|
| 696 |  | 
|---|
| 697 | JNI_QUICK_ENTRY(void, jni_ExceptionClear(JNIEnv *env)) | 
|---|
| 698 | JNIWrapper( "ExceptionClear"); | 
|---|
| 699 |  | 
|---|
| 700 | HOTSPOT_JNI_EXCEPTIONCLEAR_ENTRY(env); | 
|---|
| 701 |  | 
|---|
| 702 | // The jni code might be using this API to clear java thrown exception. | 
|---|
| 703 | // So just mark jvmti thread exception state as exception caught. | 
|---|
| 704 | JvmtiThreadState *state = JavaThread::current()->jvmti_thread_state(); | 
|---|
| 705 | if (state != NULL && state->is_exception_detected()) { | 
|---|
| 706 | state->set_exception_caught(); | 
|---|
| 707 | } | 
|---|
| 708 | thread->clear_pending_exception(); | 
|---|
| 709 |  | 
|---|
| 710 | HOTSPOT_JNI_EXCEPTIONCLEAR_RETURN(); | 
|---|
| 711 | JNI_END | 
|---|
| 712 |  | 
|---|
| 713 |  | 
|---|
| 714 | JNI_ENTRY(void, jni_FatalError(JNIEnv *env, const char *msg)) | 
|---|
| 715 | JNIWrapper( "FatalError"); | 
|---|
| 716 |  | 
|---|
| 717 | HOTSPOT_JNI_FATALERROR_ENTRY(env, (char *) msg); | 
|---|
| 718 |  | 
|---|
| 719 | tty->print_cr( "FATAL ERROR in native method: %s", msg); | 
|---|
| 720 | thread->print_stack(); | 
|---|
| 721 | os::abort(); // Dump core and abort | 
|---|
| 722 | JNI_END | 
|---|
| 723 |  | 
|---|
| 724 |  | 
|---|
| 725 | JNI_ENTRY(jint, jni_PushLocalFrame(JNIEnv *env, jint capacity)) | 
|---|
| 726 | JNIWrapper( "PushLocalFrame"); | 
|---|
| 727 |  | 
|---|
| 728 | HOTSPOT_JNI_PUSHLOCALFRAME_ENTRY(env, capacity); | 
|---|
| 729 |  | 
|---|
| 730 | //%note jni_11 | 
|---|
| 731 | if (capacity < 0 || | 
|---|
| 732 | ((MaxJNILocalCapacity > 0) && (capacity > MaxJNILocalCapacity))) { | 
|---|
| 733 | HOTSPOT_JNI_PUSHLOCALFRAME_RETURN((uint32_t)JNI_ERR); | 
|---|
| 734 | return JNI_ERR; | 
|---|
| 735 | } | 
|---|
| 736 | JNIHandleBlock* old_handles = thread->active_handles(); | 
|---|
| 737 | JNIHandleBlock* new_handles = JNIHandleBlock::allocate_block(thread); | 
|---|
| 738 | assert(new_handles != NULL, "should not be NULL"); | 
|---|
| 739 | new_handles->set_pop_frame_link(old_handles); | 
|---|
| 740 | thread->set_active_handles(new_handles); | 
|---|
| 741 | jint ret = JNI_OK; | 
|---|
| 742 | HOTSPOT_JNI_PUSHLOCALFRAME_RETURN(ret); | 
|---|
| 743 | return ret; | 
|---|
| 744 | JNI_END | 
|---|
| 745 |  | 
|---|
| 746 |  | 
|---|
| 747 | JNI_ENTRY(jobject, jni_PopLocalFrame(JNIEnv *env, jobject result)) | 
|---|
| 748 | JNIWrapper( "PopLocalFrame"); | 
|---|
| 749 |  | 
|---|
| 750 | HOTSPOT_JNI_POPLOCALFRAME_ENTRY(env, result); | 
|---|
| 751 |  | 
|---|
| 752 | //%note jni_11 | 
|---|
| 753 | Handle result_handle(thread, JNIHandles::resolve(result)); | 
|---|
| 754 | JNIHandleBlock* old_handles = thread->active_handles(); | 
|---|
| 755 | JNIHandleBlock* new_handles = old_handles->pop_frame_link(); | 
|---|
| 756 | if (new_handles != NULL) { | 
|---|
| 757 | // As a sanity check we only release the handle blocks if the pop_frame_link is not NULL. | 
|---|
| 758 | // This way code will still work if PopLocalFrame is called without a corresponding | 
|---|
| 759 | // PushLocalFrame call. Note that we set the pop_frame_link to NULL explicitly, otherwise | 
|---|
| 760 | // the release_block call will release the blocks. | 
|---|
| 761 | thread->set_active_handles(new_handles); | 
|---|
| 762 | old_handles->set_pop_frame_link(NULL);              // clear link we won't release new_handles below | 
|---|
| 763 | JNIHandleBlock::release_block(old_handles, thread); // may block | 
|---|
| 764 | result = JNIHandles::make_local(thread, result_handle()); | 
|---|
| 765 | } | 
|---|
| 766 | HOTSPOT_JNI_POPLOCALFRAME_RETURN(result); | 
|---|
| 767 | return result; | 
|---|
| 768 | JNI_END | 
|---|
| 769 |  | 
|---|
| 770 |  | 
|---|
| 771 | JNI_ENTRY(jobject, jni_NewGlobalRef(JNIEnv *env, jobject ref)) | 
|---|
| 772 | JNIWrapper( "NewGlobalRef"); | 
|---|
| 773 |  | 
|---|
| 774 | HOTSPOT_JNI_NEWGLOBALREF_ENTRY(env, ref); | 
|---|
| 775 |  | 
|---|
| 776 | Handle ref_handle(thread, JNIHandles::resolve(ref)); | 
|---|
| 777 | jobject ret = JNIHandles::make_global(ref_handle); | 
|---|
| 778 |  | 
|---|
| 779 | HOTSPOT_JNI_NEWGLOBALREF_RETURN(ret); | 
|---|
| 780 | return ret; | 
|---|
| 781 | JNI_END | 
|---|
| 782 |  | 
|---|
| 783 | // Must be JNI_ENTRY (with HandleMark) | 
|---|
| 784 | JNI_ENTRY_NO_PRESERVE(void, jni_DeleteGlobalRef(JNIEnv *env, jobject ref)) | 
|---|
| 785 | JNIWrapper( "DeleteGlobalRef"); | 
|---|
| 786 |  | 
|---|
| 787 | HOTSPOT_JNI_DELETEGLOBALREF_ENTRY(env, ref); | 
|---|
| 788 |  | 
|---|
| 789 | JNIHandles::destroy_global(ref); | 
|---|
| 790 |  | 
|---|
| 791 | HOTSPOT_JNI_DELETEGLOBALREF_RETURN(); | 
|---|
| 792 | JNI_END | 
|---|
| 793 |  | 
|---|
| 794 | JNI_QUICK_ENTRY(void, jni_DeleteLocalRef(JNIEnv *env, jobject obj)) | 
|---|
| 795 | JNIWrapper( "DeleteLocalRef"); | 
|---|
| 796 |  | 
|---|
| 797 | HOTSPOT_JNI_DELETELOCALREF_ENTRY(env, obj); | 
|---|
| 798 |  | 
|---|
| 799 | JNIHandles::destroy_local(obj); | 
|---|
| 800 |  | 
|---|
| 801 | HOTSPOT_JNI_DELETELOCALREF_RETURN(); | 
|---|
| 802 | JNI_END | 
|---|
| 803 |  | 
|---|
| 804 | JNI_QUICK_ENTRY(jboolean, jni_IsSameObject(JNIEnv *env, jobject r1, jobject r2)) | 
|---|
| 805 | JNIWrapper( "IsSameObject"); | 
|---|
| 806 |  | 
|---|
| 807 | HOTSPOT_JNI_ISSAMEOBJECT_ENTRY(env, r1, r2); | 
|---|
| 808 |  | 
|---|
| 809 | jboolean ret = JNIHandles::is_same_object(r1, r2) ? JNI_TRUE : JNI_FALSE; | 
|---|
| 810 |  | 
|---|
| 811 | HOTSPOT_JNI_ISSAMEOBJECT_RETURN(ret); | 
|---|
| 812 | return ret; | 
|---|
| 813 | JNI_END | 
|---|
| 814 |  | 
|---|
| 815 |  | 
|---|
| 816 | JNI_ENTRY(jobject, jni_NewLocalRef(JNIEnv *env, jobject ref)) | 
|---|
| 817 | JNIWrapper( "NewLocalRef"); | 
|---|
| 818 |  | 
|---|
| 819 | HOTSPOT_JNI_NEWLOCALREF_ENTRY(env, ref); | 
|---|
| 820 |  | 
|---|
| 821 | jobject ret = JNIHandles::make_local(env, JNIHandles::resolve(ref)); | 
|---|
| 822 |  | 
|---|
| 823 | HOTSPOT_JNI_NEWLOCALREF_RETURN(ret); | 
|---|
| 824 | return ret; | 
|---|
| 825 | JNI_END | 
|---|
| 826 |  | 
|---|
| 827 | JNI_LEAF(jint, jni_EnsureLocalCapacity(JNIEnv *env, jint capacity)) | 
|---|
| 828 | JNIWrapper( "EnsureLocalCapacity"); | 
|---|
| 829 |  | 
|---|
| 830 | HOTSPOT_JNI_ENSURELOCALCAPACITY_ENTRY(env, capacity); | 
|---|
| 831 |  | 
|---|
| 832 | jint ret; | 
|---|
| 833 | if (capacity >= 0 && | 
|---|
| 834 | ((MaxJNILocalCapacity <= 0) || (capacity <= MaxJNILocalCapacity))) { | 
|---|
| 835 | ret = JNI_OK; | 
|---|
| 836 | } else { | 
|---|
| 837 | ret = JNI_ERR; | 
|---|
| 838 | } | 
|---|
| 839 |  | 
|---|
| 840 | HOTSPOT_JNI_ENSURELOCALCAPACITY_RETURN(ret); | 
|---|
| 841 | return ret; | 
|---|
| 842 | JNI_END | 
|---|
| 843 |  | 
|---|
| 844 | // Return the Handle Type | 
|---|
| 845 | JNI_LEAF(jobjectRefType, jni_GetObjectRefType(JNIEnv *env, jobject obj)) | 
|---|
| 846 | JNIWrapper( "GetObjectRefType"); | 
|---|
| 847 |  | 
|---|
| 848 | HOTSPOT_JNI_GETOBJECTREFTYPE_ENTRY(env, obj); | 
|---|
| 849 |  | 
|---|
| 850 | jobjectRefType ret = JNIInvalidRefType; | 
|---|
| 851 | if (obj != NULL) { | 
|---|
| 852 | ret = JNIHandles::handle_type(thread, obj); | 
|---|
| 853 | } | 
|---|
| 854 |  | 
|---|
| 855 | HOTSPOT_JNI_GETOBJECTREFTYPE_RETURN((void *) ret); | 
|---|
| 856 | return ret; | 
|---|
| 857 | JNI_END | 
|---|
| 858 |  | 
|---|
| 859 |  | 
|---|
| 860 | class JNI_ArgumentPusher : public SignatureIterator { | 
|---|
| 861 | protected: | 
|---|
| 862 | JavaCallArguments*  _arguments; | 
|---|
| 863 |  | 
|---|
| 864 | virtual void get_bool   () = 0; | 
|---|
| 865 | virtual void get_char   () = 0; | 
|---|
| 866 | virtual void get_short  () = 0; | 
|---|
| 867 | virtual void get_byte   () = 0; | 
|---|
| 868 | virtual void get_int    () = 0; | 
|---|
| 869 | virtual void get_long   () = 0; | 
|---|
| 870 | virtual void get_float  () = 0; | 
|---|
| 871 | virtual void get_double () = 0; | 
|---|
| 872 | virtual void get_object () = 0; | 
|---|
| 873 |  | 
|---|
| 874 | JNI_ArgumentPusher(Symbol* signature) : SignatureIterator(signature) { | 
|---|
| 875 | this->_return_type = T_ILLEGAL; | 
|---|
| 876 | _arguments = NULL; | 
|---|
| 877 | } | 
|---|
| 878 |  | 
|---|
| 879 | public: | 
|---|
| 880 | virtual void iterate( uint64_t fingerprint ) = 0; | 
|---|
| 881 |  | 
|---|
| 882 | void set_java_argument_object(JavaCallArguments *arguments) { _arguments = arguments; } | 
|---|
| 883 |  | 
|---|
| 884 | inline void do_bool()                     { if (!is_return_type()) get_bool();   } | 
|---|
| 885 | inline void do_char()                     { if (!is_return_type()) get_char();   } | 
|---|
| 886 | inline void do_short()                    { if (!is_return_type()) get_short();  } | 
|---|
| 887 | inline void do_byte()                     { if (!is_return_type()) get_byte();   } | 
|---|
| 888 | inline void do_int()                      { if (!is_return_type()) get_int();    } | 
|---|
| 889 | inline void do_long()                     { if (!is_return_type()) get_long();   } | 
|---|
| 890 | inline void do_float()                    { if (!is_return_type()) get_float();  } | 
|---|
| 891 | inline void do_double()                   { if (!is_return_type()) get_double(); } | 
|---|
| 892 | inline void do_object(int begin, int end) { if (!is_return_type()) get_object(); } | 
|---|
| 893 | inline void do_array(int begin, int end)  { if (!is_return_type()) get_object(); } // do_array uses get_object -- there is no get_array | 
|---|
| 894 | inline void do_void()                     { } | 
|---|
| 895 |  | 
|---|
| 896 | JavaCallArguments* arguments()     { return _arguments; } | 
|---|
| 897 | void push_receiver(Handle h)       { _arguments->push_oop(h); } | 
|---|
| 898 | }; | 
|---|
| 899 |  | 
|---|
| 900 |  | 
|---|
| 901 | class JNI_ArgumentPusherVaArg : public JNI_ArgumentPusher { | 
|---|
| 902 | protected: | 
|---|
| 903 | va_list _ap; | 
|---|
| 904 |  | 
|---|
| 905 | inline void get_bool()   { | 
|---|
| 906 | // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and | 
|---|
| 907 | // 0 to JNI_FALSE.  Boolean return values from native are normalized the same in | 
|---|
| 908 | // TemplateInterpreterGenerator::generate_result_handler_for and | 
|---|
| 909 | // SharedRuntime::generate_native_wrapper. | 
|---|
| 910 | jboolean b = va_arg(_ap, jint); | 
|---|
| 911 | _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE)); | 
|---|
| 912 | } | 
|---|
| 913 | inline void get_char()   { _arguments->push_int(va_arg(_ap, jint)); } // char is coerced to int when using va_arg | 
|---|
| 914 | inline void get_short()  { _arguments->push_int(va_arg(_ap, jint)); } // short is coerced to int when using va_arg | 
|---|
| 915 | inline void get_byte()   { _arguments->push_int(va_arg(_ap, jint)); } // byte is coerced to int when using va_arg | 
|---|
| 916 | inline void get_int()    { _arguments->push_int(va_arg(_ap, jint)); } | 
|---|
| 917 |  | 
|---|
| 918 | // each of these paths is exercized by the various jck Call[Static,Nonvirtual,][Void,Int,..]Method[A,V,] tests | 
|---|
| 919 |  | 
|---|
| 920 | inline void get_long()   { _arguments->push_long(va_arg(_ap, jlong)); } | 
|---|
| 921 | inline void get_float()  { _arguments->push_float((jfloat)va_arg(_ap, jdouble)); } // float is coerced to double w/ va_arg | 
|---|
| 922 | inline void get_double() { _arguments->push_double(va_arg(_ap, jdouble)); } | 
|---|
| 923 | inline void get_object() { _arguments->push_jobject(va_arg(_ap, jobject)); } | 
|---|
| 924 |  | 
|---|
| 925 | inline void set_ap(va_list rap) { | 
|---|
| 926 | va_copy(_ap, rap); | 
|---|
| 927 | } | 
|---|
| 928 |  | 
|---|
| 929 | public: | 
|---|
| 930 | JNI_ArgumentPusherVaArg(Symbol* signature, va_list rap) | 
|---|
| 931 | : JNI_ArgumentPusher(signature) { | 
|---|
| 932 | set_ap(rap); | 
|---|
| 933 | } | 
|---|
| 934 | JNI_ArgumentPusherVaArg(jmethodID method_id, va_list rap) | 
|---|
| 935 | : JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)->signature()) { | 
|---|
| 936 | set_ap(rap); | 
|---|
| 937 | } | 
|---|
| 938 |  | 
|---|
| 939 | // Optimized path if we have the bitvector form of signature | 
|---|
| 940 | void iterate( uint64_t fingerprint ) { | 
|---|
| 941 | if (fingerprint == (uint64_t)CONST64(-1)) { | 
|---|
| 942 | SignatureIterator::iterate(); // Must be too many arguments | 
|---|
| 943 | } else { | 
|---|
| 944 | _return_type = (BasicType)((fingerprint >> static_feature_size) & | 
|---|
| 945 | result_feature_mask); | 
|---|
| 946 |  | 
|---|
| 947 | assert(fingerprint, "Fingerprint should not be 0"); | 
|---|
| 948 | fingerprint = fingerprint >> (static_feature_size + result_feature_size); | 
|---|
| 949 | while ( 1 ) { | 
|---|
| 950 | switch ( fingerprint & parameter_feature_mask ) { | 
|---|
| 951 | case bool_parm: | 
|---|
| 952 | get_bool(); | 
|---|
| 953 | break; | 
|---|
| 954 | case char_parm: | 
|---|
| 955 | get_char(); | 
|---|
| 956 | break; | 
|---|
| 957 | case short_parm: | 
|---|
| 958 | get_short(); | 
|---|
| 959 | break; | 
|---|
| 960 | case byte_parm: | 
|---|
| 961 | get_byte(); | 
|---|
| 962 | break; | 
|---|
| 963 | case int_parm: | 
|---|
| 964 | get_int(); | 
|---|
| 965 | break; | 
|---|
| 966 | case obj_parm: | 
|---|
| 967 | get_object(); | 
|---|
| 968 | break; | 
|---|
| 969 | case long_parm: | 
|---|
| 970 | get_long(); | 
|---|
| 971 | break; | 
|---|
| 972 | case float_parm: | 
|---|
| 973 | get_float(); | 
|---|
| 974 | break; | 
|---|
| 975 | case double_parm: | 
|---|
| 976 | get_double(); | 
|---|
| 977 | break; | 
|---|
| 978 | case done_parm: | 
|---|
| 979 | return; | 
|---|
| 980 | break; | 
|---|
| 981 | default: | 
|---|
| 982 | ShouldNotReachHere(); | 
|---|
| 983 | break; | 
|---|
| 984 | } | 
|---|
| 985 | fingerprint >>= parameter_feature_size; | 
|---|
| 986 | } | 
|---|
| 987 | } | 
|---|
| 988 | } | 
|---|
| 989 | }; | 
|---|
| 990 |  | 
|---|
| 991 |  | 
|---|
| 992 | class JNI_ArgumentPusherArray : public JNI_ArgumentPusher { | 
|---|
| 993 | protected: | 
|---|
| 994 | const jvalue *_ap; | 
|---|
| 995 |  | 
|---|
| 996 | inline void get_bool()   { | 
|---|
| 997 | // Normalize boolean arguments from native code by converting 1-255 to JNI_TRUE and | 
|---|
| 998 | // 0 to JNI_FALSE.  Boolean return values from native are normalized the same in | 
|---|
| 999 | // TemplateInterpreterGenerator::generate_result_handler_for and | 
|---|
| 1000 | // SharedRuntime::generate_native_wrapper. | 
|---|
| 1001 | jboolean b = (_ap++)->z; | 
|---|
| 1002 | _arguments->push_int((jint)(b == 0 ? JNI_FALSE : JNI_TRUE)); | 
|---|
| 1003 | } | 
|---|
| 1004 | inline void get_char()   { _arguments->push_int((jint)(_ap++)->c); } | 
|---|
| 1005 | inline void get_short()  { _arguments->push_int((jint)(_ap++)->s); } | 
|---|
| 1006 | inline void get_byte()   { _arguments->push_int((jint)(_ap++)->b); } | 
|---|
| 1007 | inline void get_int()    { _arguments->push_int((jint)(_ap++)->i); } | 
|---|
| 1008 |  | 
|---|
| 1009 | inline void get_long()   { _arguments->push_long((_ap++)->j);  } | 
|---|
| 1010 | inline void get_float()  { _arguments->push_float((_ap++)->f); } | 
|---|
| 1011 | inline void get_double() { _arguments->push_double((_ap++)->d);} | 
|---|
| 1012 | inline void get_object() { _arguments->push_jobject((_ap++)->l); } | 
|---|
| 1013 |  | 
|---|
| 1014 | inline void set_ap(const jvalue *rap) { _ap = rap; } | 
|---|
| 1015 |  | 
|---|
| 1016 | public: | 
|---|
| 1017 | JNI_ArgumentPusherArray(Symbol* signature, const jvalue *rap) | 
|---|
| 1018 | : JNI_ArgumentPusher(signature) { | 
|---|
| 1019 | set_ap(rap); | 
|---|
| 1020 | } | 
|---|
| 1021 | JNI_ArgumentPusherArray(jmethodID method_id, const jvalue *rap) | 
|---|
| 1022 | : JNI_ArgumentPusher(Method::resolve_jmethod_id(method_id)->signature()) { | 
|---|
| 1023 | set_ap(rap); | 
|---|
| 1024 | } | 
|---|
| 1025 |  | 
|---|
| 1026 | // Optimized path if we have the bitvector form of signature | 
|---|
| 1027 | void iterate( uint64_t fingerprint ) { | 
|---|
| 1028 | if (fingerprint == (uint64_t)CONST64(-1)) { | 
|---|
| 1029 | SignatureIterator::iterate(); // Must be too many arguments | 
|---|
| 1030 | } else { | 
|---|
| 1031 | _return_type = (BasicType)((fingerprint >> static_feature_size) & | 
|---|
| 1032 | result_feature_mask); | 
|---|
| 1033 | assert(fingerprint, "Fingerprint should not be 0"); | 
|---|
| 1034 | fingerprint = fingerprint >> (static_feature_size + result_feature_size); | 
|---|
| 1035 | while ( 1 ) { | 
|---|
| 1036 | switch ( fingerprint & parameter_feature_mask ) { | 
|---|
| 1037 | case bool_parm: | 
|---|
| 1038 | get_bool(); | 
|---|
| 1039 | break; | 
|---|
| 1040 | case char_parm: | 
|---|
| 1041 | get_char(); | 
|---|
| 1042 | break; | 
|---|
| 1043 | case short_parm: | 
|---|
| 1044 | get_short(); | 
|---|
| 1045 | break; | 
|---|
| 1046 | case byte_parm: | 
|---|
| 1047 | get_byte(); | 
|---|
| 1048 | break; | 
|---|
| 1049 | case int_parm: | 
|---|
| 1050 | get_int(); | 
|---|
| 1051 | break; | 
|---|
| 1052 | case obj_parm: | 
|---|
| 1053 | get_object(); | 
|---|
| 1054 | break; | 
|---|
| 1055 | case long_parm: | 
|---|
| 1056 | get_long(); | 
|---|
| 1057 | break; | 
|---|
| 1058 | case float_parm: | 
|---|
| 1059 | get_float(); | 
|---|
| 1060 | break; | 
|---|
| 1061 | case double_parm: | 
|---|
| 1062 | get_double(); | 
|---|
| 1063 | break; | 
|---|
| 1064 | case done_parm: | 
|---|
| 1065 | return; | 
|---|
| 1066 | break; | 
|---|
| 1067 | default: | 
|---|
| 1068 | ShouldNotReachHere(); | 
|---|
| 1069 | break; | 
|---|
| 1070 | } | 
|---|
| 1071 | fingerprint >>= parameter_feature_size; | 
|---|
| 1072 | } | 
|---|
| 1073 | } | 
|---|
| 1074 | } | 
|---|
| 1075 | }; | 
|---|
| 1076 |  | 
|---|
| 1077 |  | 
|---|
| 1078 | enum JNICallType { | 
|---|
| 1079 | JNI_STATIC, | 
|---|
| 1080 | JNI_VIRTUAL, | 
|---|
| 1081 | JNI_NONVIRTUAL | 
|---|
| 1082 | }; | 
|---|
| 1083 |  | 
|---|
| 1084 |  | 
|---|
| 1085 |  | 
|---|
| 1086 | static void jni_invoke_static(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) { | 
|---|
| 1087 | methodHandle method(THREAD, Method::resolve_jmethod_id(method_id)); | 
|---|
| 1088 |  | 
|---|
| 1089 | // Create object to hold arguments for the JavaCall, and associate it with | 
|---|
| 1090 | // the jni parser | 
|---|
| 1091 | ResourceMark rm(THREAD); | 
|---|
| 1092 | int number_of_parameters = method->size_of_parameters(); | 
|---|
| 1093 | JavaCallArguments java_args(number_of_parameters); | 
|---|
| 1094 | args->set_java_argument_object(&java_args); | 
|---|
| 1095 |  | 
|---|
| 1096 | assert(method->is_static(), "method should be static"); | 
|---|
| 1097 |  | 
|---|
| 1098 | // Fill out JavaCallArguments object | 
|---|
| 1099 | args->iterate( Fingerprinter(method).fingerprint() ); | 
|---|
| 1100 | // Initialize result type | 
|---|
| 1101 | result->set_type(args->get_ret_type()); | 
|---|
| 1102 |  | 
|---|
| 1103 | // Invoke the method. Result is returned as oop. | 
|---|
| 1104 | JavaCalls::call(result, method, &java_args, CHECK); | 
|---|
| 1105 |  | 
|---|
| 1106 | // Convert result | 
|---|
| 1107 | if (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY) { | 
|---|
| 1108 | result->set_jobject(JNIHandles::make_local(env, (oop) result->get_jobject())); | 
|---|
| 1109 | } | 
|---|
| 1110 | } | 
|---|
| 1111 |  | 
|---|
| 1112 |  | 
|---|
| 1113 | static void jni_invoke_nonstatic(JNIEnv *env, JavaValue* result, jobject receiver, JNICallType call_type, jmethodID method_id, JNI_ArgumentPusher *args, TRAPS) { | 
|---|
| 1114 | oop recv = JNIHandles::resolve(receiver); | 
|---|
| 1115 | if (recv == NULL) { | 
|---|
| 1116 | THROW(vmSymbols::java_lang_NullPointerException()); | 
|---|
| 1117 | } | 
|---|
| 1118 | Handle h_recv(THREAD, recv); | 
|---|
| 1119 |  | 
|---|
| 1120 | int number_of_parameters; | 
|---|
| 1121 | Method* selected_method; | 
|---|
| 1122 | { | 
|---|
| 1123 | Method* m = Method::resolve_jmethod_id(method_id); | 
|---|
| 1124 | number_of_parameters = m->size_of_parameters(); | 
|---|
| 1125 | Klass* holder = m->method_holder(); | 
|---|
| 1126 | if (call_type != JNI_VIRTUAL) { | 
|---|
| 1127 | selected_method = m; | 
|---|
| 1128 | } else if (!m->has_itable_index()) { | 
|---|
| 1129 | // non-interface call -- for that little speed boost, don't handlize | 
|---|
| 1130 | debug_only(NoSafepointVerifier nosafepoint;) | 
|---|
| 1131 | // jni_GetMethodID makes sure class is linked and initialized | 
|---|
| 1132 | // so m should have a valid vtable index. | 
|---|
| 1133 | assert(m->valid_vtable_index(), "no valid vtable index"); | 
|---|
| 1134 | int vtbl_index = m->vtable_index(); | 
|---|
| 1135 | if (vtbl_index != Method::nonvirtual_vtable_index) { | 
|---|
| 1136 | selected_method = h_recv->klass()->method_at_vtable(vtbl_index); | 
|---|
| 1137 | } else { | 
|---|
| 1138 | // final method | 
|---|
| 1139 | selected_method = m; | 
|---|
| 1140 | } | 
|---|
| 1141 | } else { | 
|---|
| 1142 | // interface call | 
|---|
| 1143 | int itbl_index = m->itable_index(); | 
|---|
| 1144 | Klass* k = h_recv->klass(); | 
|---|
| 1145 | selected_method = InstanceKlass::cast(k)->method_at_itable(holder, itbl_index, CHECK); | 
|---|
| 1146 | } | 
|---|
| 1147 | } | 
|---|
| 1148 |  | 
|---|
| 1149 | methodHandle method(THREAD, selected_method); | 
|---|
| 1150 |  | 
|---|
| 1151 | // Create object to hold arguments for the JavaCall, and associate it with | 
|---|
| 1152 | // the jni parser | 
|---|
| 1153 | ResourceMark rm(THREAD); | 
|---|
| 1154 | JavaCallArguments java_args(number_of_parameters); | 
|---|
| 1155 | args->set_java_argument_object(&java_args); | 
|---|
| 1156 |  | 
|---|
| 1157 | // handle arguments | 
|---|
| 1158 | assert(!method->is_static(), "method %s should not be static", method->name_and_sig_as_C_string()); | 
|---|
| 1159 | args->push_receiver(h_recv); // Push jobject handle | 
|---|
| 1160 |  | 
|---|
| 1161 | // Fill out JavaCallArguments object | 
|---|
| 1162 | args->iterate( Fingerprinter(method).fingerprint() ); | 
|---|
| 1163 | // Initialize result type | 
|---|
| 1164 | result->set_type(args->get_ret_type()); | 
|---|
| 1165 |  | 
|---|
| 1166 | // Invoke the method. Result is returned as oop. | 
|---|
| 1167 | JavaCalls::call(result, method, &java_args, CHECK); | 
|---|
| 1168 |  | 
|---|
| 1169 | // Convert result | 
|---|
| 1170 | if (result->get_type() == T_OBJECT || result->get_type() == T_ARRAY) { | 
|---|
| 1171 | result->set_jobject(JNIHandles::make_local(env, (oop) result->get_jobject())); | 
|---|
| 1172 | } | 
|---|
| 1173 | } | 
|---|
| 1174 |  | 
|---|
| 1175 |  | 
|---|
| 1176 | static instanceOop alloc_object(jclass clazz, TRAPS) { | 
|---|
| 1177 | Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); | 
|---|
| 1178 | if (k == NULL) { | 
|---|
| 1179 | ResourceMark rm(THREAD); | 
|---|
| 1180 | THROW_(vmSymbols::java_lang_InstantiationException(), NULL); | 
|---|
| 1181 | } | 
|---|
| 1182 | k->check_valid_for_instantiation(false, CHECK_NULL); | 
|---|
| 1183 | k->initialize(CHECK_NULL); | 
|---|
| 1184 | instanceOop ih = InstanceKlass::cast(k)->allocate_instance(THREAD); | 
|---|
| 1185 | return ih; | 
|---|
| 1186 | } | 
|---|
| 1187 |  | 
|---|
| 1188 | DT_RETURN_MARK_DECL(AllocObject, jobject | 
|---|
| 1189 | , HOTSPOT_JNI_ALLOCOBJECT_RETURN(_ret_ref)); | 
|---|
| 1190 |  | 
|---|
| 1191 | JNI_ENTRY(jobject, jni_AllocObject(JNIEnv *env, jclass clazz)) | 
|---|
| 1192 | JNIWrapper( "AllocObject"); | 
|---|
| 1193 |  | 
|---|
| 1194 | HOTSPOT_JNI_ALLOCOBJECT_ENTRY(env, clazz); | 
|---|
| 1195 |  | 
|---|
| 1196 | jobject ret = NULL; | 
|---|
| 1197 | DT_RETURN_MARK(AllocObject, jobject, (const jobject&)ret); | 
|---|
| 1198 |  | 
|---|
| 1199 | instanceOop i = alloc_object(clazz, CHECK_NULL); | 
|---|
| 1200 | ret = JNIHandles::make_local(env, i); | 
|---|
| 1201 | return ret; | 
|---|
| 1202 | JNI_END | 
|---|
| 1203 |  | 
|---|
| 1204 | DT_RETURN_MARK_DECL(NewObjectA, jobject | 
|---|
| 1205 | , HOTSPOT_JNI_NEWOBJECTA_RETURN(_ret_ref)); | 
|---|
| 1206 |  | 
|---|
| 1207 | JNI_ENTRY(jobject, jni_NewObjectA(JNIEnv *env, jclass clazz, jmethodID methodID, const jvalue *args)) | 
|---|
| 1208 | JNIWrapper( "NewObjectA"); | 
|---|
| 1209 |  | 
|---|
| 1210 | HOTSPOT_JNI_NEWOBJECTA_ENTRY(env, clazz, (uintptr_t) methodID); | 
|---|
| 1211 |  | 
|---|
| 1212 | jobject obj = NULL; | 
|---|
| 1213 | DT_RETURN_MARK(NewObjectA, jobject, (const jobject)obj); | 
|---|
| 1214 |  | 
|---|
| 1215 | instanceOop i = alloc_object(clazz, CHECK_NULL); | 
|---|
| 1216 | obj = JNIHandles::make_local(env, i); | 
|---|
| 1217 | JavaValue jvalue(T_VOID); | 
|---|
| 1218 | JNI_ArgumentPusherArray ap(methodID, args); | 
|---|
| 1219 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL); | 
|---|
| 1220 | return obj; | 
|---|
| 1221 | JNI_END | 
|---|
| 1222 |  | 
|---|
| 1223 |  | 
|---|
| 1224 | DT_RETURN_MARK_DECL(NewObjectV, jobject | 
|---|
| 1225 | , HOTSPOT_JNI_NEWOBJECTV_RETURN(_ret_ref)); | 
|---|
| 1226 |  | 
|---|
| 1227 | JNI_ENTRY(jobject, jni_NewObjectV(JNIEnv *env, jclass clazz, jmethodID methodID, va_list args)) | 
|---|
| 1228 | JNIWrapper( "NewObjectV"); | 
|---|
| 1229 |  | 
|---|
| 1230 | HOTSPOT_JNI_NEWOBJECTV_ENTRY(env, clazz, (uintptr_t) methodID); | 
|---|
| 1231 |  | 
|---|
| 1232 | jobject obj = NULL; | 
|---|
| 1233 | DT_RETURN_MARK(NewObjectV, jobject, (const jobject&)obj); | 
|---|
| 1234 |  | 
|---|
| 1235 | instanceOop i = alloc_object(clazz, CHECK_NULL); | 
|---|
| 1236 | obj = JNIHandles::make_local(env, i); | 
|---|
| 1237 | JavaValue jvalue(T_VOID); | 
|---|
| 1238 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1239 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL); | 
|---|
| 1240 | return obj; | 
|---|
| 1241 | JNI_END | 
|---|
| 1242 |  | 
|---|
| 1243 |  | 
|---|
| 1244 | DT_RETURN_MARK_DECL(NewObject, jobject | 
|---|
| 1245 | , HOTSPOT_JNI_NEWOBJECT_RETURN(_ret_ref)); | 
|---|
| 1246 |  | 
|---|
| 1247 | JNI_ENTRY(jobject, jni_NewObject(JNIEnv *env, jclass clazz, jmethodID methodID, ...)) | 
|---|
| 1248 | JNIWrapper( "NewObject"); | 
|---|
| 1249 |  | 
|---|
| 1250 | HOTSPOT_JNI_NEWOBJECT_ENTRY(env, clazz, (uintptr_t) methodID); | 
|---|
| 1251 |  | 
|---|
| 1252 | jobject obj = NULL; | 
|---|
| 1253 | DT_RETURN_MARK(NewObject, jobject, (const jobject&)obj); | 
|---|
| 1254 |  | 
|---|
| 1255 | instanceOop i = alloc_object(clazz, CHECK_NULL); | 
|---|
| 1256 | obj = JNIHandles::make_local(env, i); | 
|---|
| 1257 | va_list args; | 
|---|
| 1258 | va_start(args, methodID); | 
|---|
| 1259 | JavaValue jvalue(T_VOID); | 
|---|
| 1260 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1261 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_NULL); | 
|---|
| 1262 | va_end(args); | 
|---|
| 1263 | return obj; | 
|---|
| 1264 | JNI_END | 
|---|
| 1265 |  | 
|---|
| 1266 |  | 
|---|
| 1267 | JNI_ENTRY(jclass, jni_GetObjectClass(JNIEnv *env, jobject obj)) | 
|---|
| 1268 | JNIWrapper( "GetObjectClass"); | 
|---|
| 1269 |  | 
|---|
| 1270 | HOTSPOT_JNI_GETOBJECTCLASS_ENTRY(env, obj); | 
|---|
| 1271 |  | 
|---|
| 1272 | Klass* k = JNIHandles::resolve_non_null(obj)->klass(); | 
|---|
| 1273 | jclass ret = | 
|---|
| 1274 | (jclass) JNIHandles::make_local(env, k->java_mirror()); | 
|---|
| 1275 |  | 
|---|
| 1276 | HOTSPOT_JNI_GETOBJECTCLASS_RETURN(ret); | 
|---|
| 1277 | return ret; | 
|---|
| 1278 | JNI_END | 
|---|
| 1279 |  | 
|---|
| 1280 | JNI_QUICK_ENTRY(jboolean, jni_IsInstanceOf(JNIEnv *env, jobject obj, jclass clazz)) | 
|---|
| 1281 | JNIWrapper( "IsInstanceOf"); | 
|---|
| 1282 |  | 
|---|
| 1283 | HOTSPOT_JNI_ISINSTANCEOF_ENTRY(env, obj, clazz); | 
|---|
| 1284 |  | 
|---|
| 1285 | jboolean ret = JNI_TRUE; | 
|---|
| 1286 | if (obj != NULL) { | 
|---|
| 1287 | ret = JNI_FALSE; | 
|---|
| 1288 | Klass* k = java_lang_Class::as_Klass( | 
|---|
| 1289 | JNIHandles::resolve_non_null(clazz)); | 
|---|
| 1290 | if (k != NULL) { | 
|---|
| 1291 | ret = JNIHandles::resolve_non_null(obj)->is_a(k) ? JNI_TRUE : JNI_FALSE; | 
|---|
| 1292 | } | 
|---|
| 1293 | } | 
|---|
| 1294 |  | 
|---|
| 1295 | HOTSPOT_JNI_ISINSTANCEOF_RETURN(ret); | 
|---|
| 1296 | return ret; | 
|---|
| 1297 | JNI_END | 
|---|
| 1298 |  | 
|---|
| 1299 |  | 
|---|
| 1300 | static jmethodID get_method_id(JNIEnv *env, jclass clazz, const char *name_str, | 
|---|
| 1301 | const char *sig, bool is_static, TRAPS) { | 
|---|
| 1302 | // %%%% This code should probably just call into a method in the LinkResolver | 
|---|
| 1303 | // | 
|---|
| 1304 | // The class should have been loaded (we have an instance of the class | 
|---|
| 1305 | // passed in) so the method and signature should already be in the symbol | 
|---|
| 1306 | // table.  If they're not there, the method doesn't exist. | 
|---|
| 1307 | const char *name_to_probe = (name_str == NULL) | 
|---|
| 1308 | ? vmSymbols::object_initializer_name()->as_C_string() | 
|---|
| 1309 | : name_str; | 
|---|
| 1310 | TempNewSymbol name = SymbolTable::probe(name_to_probe, (int)strlen(name_to_probe)); | 
|---|
| 1311 | TempNewSymbol signature = SymbolTable::probe(sig, (int)strlen(sig)); | 
|---|
| 1312 |  | 
|---|
| 1313 | if (name == NULL || signature == NULL) { | 
|---|
| 1314 | THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), name_str); | 
|---|
| 1315 | } | 
|---|
| 1316 |  | 
|---|
| 1317 | Klass* klass = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); | 
|---|
| 1318 |  | 
|---|
| 1319 | // Throw a NoSuchMethodError exception if we have an instance of a | 
|---|
| 1320 | // primitive java.lang.Class | 
|---|
| 1321 | if (java_lang_Class::is_primitive(JNIHandles::resolve_non_null(clazz))) { | 
|---|
| 1322 | ResourceMark rm; | 
|---|
| 1323 | THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg( "%s%s.%s%s", is_static ? "static ": "", klass->signature_name(), name_str, sig)); | 
|---|
| 1324 | } | 
|---|
| 1325 |  | 
|---|
| 1326 | // Make sure class is linked and initialized before handing id's out to | 
|---|
| 1327 | // Method*s. | 
|---|
| 1328 | klass->initialize(CHECK_NULL); | 
|---|
| 1329 |  | 
|---|
| 1330 | Method* m; | 
|---|
| 1331 | if (name == vmSymbols::object_initializer_name() || | 
|---|
| 1332 | name == vmSymbols::class_initializer_name()) { | 
|---|
| 1333 | // Never search superclasses for constructors | 
|---|
| 1334 | if (klass->is_instance_klass()) { | 
|---|
| 1335 | m = InstanceKlass::cast(klass)->find_method(name, signature); | 
|---|
| 1336 | } else { | 
|---|
| 1337 | m = NULL; | 
|---|
| 1338 | } | 
|---|
| 1339 | } else { | 
|---|
| 1340 | m = klass->lookup_method(name, signature); | 
|---|
| 1341 | if (m == NULL &&  klass->is_instance_klass()) { | 
|---|
| 1342 | m = InstanceKlass::cast(klass)->lookup_method_in_ordered_interfaces(name, signature); | 
|---|
| 1343 | } | 
|---|
| 1344 | } | 
|---|
| 1345 | if (m == NULL || (m->is_static() != is_static)) { | 
|---|
| 1346 | ResourceMark rm; | 
|---|
| 1347 | THROW_MSG_0(vmSymbols::java_lang_NoSuchMethodError(), err_msg( "%s%s.%s%s", is_static ? "static ": "", klass->signature_name(), name_str, sig)); | 
|---|
| 1348 | } | 
|---|
| 1349 | return m->jmethod_id(); | 
|---|
| 1350 | } | 
|---|
| 1351 |  | 
|---|
| 1352 |  | 
|---|
| 1353 | JNI_ENTRY(jmethodID, jni_GetMethodID(JNIEnv *env, jclass clazz, | 
|---|
| 1354 | const char *name, const char *sig)) | 
|---|
| 1355 | JNIWrapper( "GetMethodID"); | 
|---|
| 1356 | HOTSPOT_JNI_GETMETHODID_ENTRY(env, clazz, (char *) name, (char *) sig); | 
|---|
| 1357 | jmethodID ret = get_method_id(env, clazz, name, sig, false, thread); | 
|---|
| 1358 | HOTSPOT_JNI_GETMETHODID_RETURN((uintptr_t) ret); | 
|---|
| 1359 | return ret; | 
|---|
| 1360 | JNI_END | 
|---|
| 1361 |  | 
|---|
| 1362 |  | 
|---|
| 1363 | JNI_ENTRY(jmethodID, jni_GetStaticMethodID(JNIEnv *env, jclass clazz, | 
|---|
| 1364 | const char *name, const char *sig)) | 
|---|
| 1365 | JNIWrapper( "GetStaticMethodID"); | 
|---|
| 1366 | HOTSPOT_JNI_GETSTATICMETHODID_ENTRY(env, (char *) clazz, (char *) name, (char *)sig); | 
|---|
| 1367 | jmethodID ret = get_method_id(env, clazz, name, sig, true, thread); | 
|---|
| 1368 | HOTSPOT_JNI_GETSTATICMETHODID_RETURN((uintptr_t) ret); | 
|---|
| 1369 | return ret; | 
|---|
| 1370 | JNI_END | 
|---|
| 1371 |  | 
|---|
| 1372 |  | 
|---|
| 1373 |  | 
|---|
| 1374 | // | 
|---|
| 1375 | // Calling Methods | 
|---|
| 1376 | // | 
|---|
| 1377 |  | 
|---|
| 1378 |  | 
|---|
| 1379 | #define DEFINE_CALLMETHOD(ResultType, Result, Tag \ | 
|---|
| 1380 | , EntryProbe, ReturnProbe)    \ | 
|---|
| 1381 | \ | 
|---|
| 1382 | DT_RETURN_MARK_DECL_FOR(Result, Call##Result##Method, ResultType \ | 
|---|
| 1383 | , ReturnProbe);                          \ | 
|---|
| 1384 | \ | 
|---|
| 1385 | JNI_ENTRY(ResultType, \ | 
|---|
| 1386 | jni_Call##Result##Method(JNIEnv *env, jobject obj, jmethodID methodID, ...)) \ | 
|---|
| 1387 | JNIWrapper("Call" XSTR(Result) "Method"); \ | 
|---|
| 1388 | \ | 
|---|
| 1389 | EntryProbe; \ | 
|---|
| 1390 | ResultType ret = 0;\ | 
|---|
| 1391 | DT_RETURN_MARK_FOR(Result, Call##Result##Method, ResultType, \ | 
|---|
| 1392 | (const ResultType&)ret);\ | 
|---|
| 1393 | \ | 
|---|
| 1394 | va_list args; \ | 
|---|
| 1395 | va_start(args, methodID); \ | 
|---|
| 1396 | JavaValue jvalue(Tag); \ | 
|---|
| 1397 | JNI_ArgumentPusherVaArg ap(methodID, args); \ | 
|---|
| 1398 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ | 
|---|
| 1399 | va_end(args); \ | 
|---|
| 1400 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1401 | return ret;\ | 
|---|
| 1402 | JNI_END | 
|---|
| 1403 |  | 
|---|
| 1404 | // the runtime type of subword integral basic types is integer | 
|---|
| 1405 | DEFINE_CALLMETHOD(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1406 | , HOTSPOT_JNI_CALLBOOLEANMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1407 | HOTSPOT_JNI_CALLBOOLEANMETHOD_RETURN(_ret_ref)) | 
|---|
| 1408 | DEFINE_CALLMETHOD(jbyte,    Byte,    T_BYTE | 
|---|
| 1409 | , HOTSPOT_JNI_CALLBYTEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1410 | HOTSPOT_JNI_CALLBYTEMETHOD_RETURN(_ret_ref)) | 
|---|
| 1411 | DEFINE_CALLMETHOD(jchar,    Char,    T_CHAR | 
|---|
| 1412 | , HOTSPOT_JNI_CALLCHARMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1413 | HOTSPOT_JNI_CALLCHARMETHOD_RETURN(_ret_ref)) | 
|---|
| 1414 | DEFINE_CALLMETHOD(jshort,   Short,   T_SHORT | 
|---|
| 1415 | , HOTSPOT_JNI_CALLSHORTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1416 | HOTSPOT_JNI_CALLSHORTMETHOD_RETURN(_ret_ref)) | 
|---|
| 1417 |  | 
|---|
| 1418 | DEFINE_CALLMETHOD(jobject,  Object,  T_OBJECT | 
|---|
| 1419 | , HOTSPOT_JNI_CALLOBJECTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1420 | HOTSPOT_JNI_CALLOBJECTMETHOD_RETURN(_ret_ref)) | 
|---|
| 1421 | DEFINE_CALLMETHOD(jint,     Int,     T_INT, | 
|---|
| 1422 | HOTSPOT_JNI_CALLINTMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1423 | HOTSPOT_JNI_CALLINTMETHOD_RETURN(_ret_ref)) | 
|---|
| 1424 | DEFINE_CALLMETHOD(jlong,    Long,    T_LONG | 
|---|
| 1425 | , HOTSPOT_JNI_CALLLONGMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1426 | HOTSPOT_JNI_CALLLONGMETHOD_RETURN(_ret_ref)) | 
|---|
| 1427 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1428 | DEFINE_CALLMETHOD(jfloat,   Float,   T_FLOAT | 
|---|
| 1429 | , HOTSPOT_JNI_CALLFLOATMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1430 | HOTSPOT_JNI_CALLFLOATMETHOD_RETURN()) | 
|---|
| 1431 | DEFINE_CALLMETHOD(jdouble,  Double,  T_DOUBLE | 
|---|
| 1432 | , HOTSPOT_JNI_CALLDOUBLEMETHOD_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1433 | HOTSPOT_JNI_CALLDOUBLEMETHOD_RETURN()) | 
|---|
| 1434 |  | 
|---|
| 1435 | #define DEFINE_CALLMETHODV(ResultType, Result, Tag \ | 
|---|
| 1436 | , EntryProbe, ReturnProbe)    \ | 
|---|
| 1437 | \ | 
|---|
| 1438 | DT_RETURN_MARK_DECL_FOR(Result, Call##Result##MethodV, ResultType \ | 
|---|
| 1439 | , ReturnProbe);                          \ | 
|---|
| 1440 | \ | 
|---|
| 1441 | JNI_ENTRY(ResultType, \ | 
|---|
| 1442 | jni_Call##Result##MethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)) \ | 
|---|
| 1443 | JNIWrapper("Call" XSTR(Result) "MethodV"); \ | 
|---|
| 1444 | \ | 
|---|
| 1445 | EntryProbe;\ | 
|---|
| 1446 | ResultType ret = 0;\ | 
|---|
| 1447 | DT_RETURN_MARK_FOR(Result, Call##Result##MethodV, ResultType, \ | 
|---|
| 1448 | (const ResultType&)ret);\ | 
|---|
| 1449 | \ | 
|---|
| 1450 | JavaValue jvalue(Tag); \ | 
|---|
| 1451 | JNI_ArgumentPusherVaArg ap(methodID, args); \ | 
|---|
| 1452 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ | 
|---|
| 1453 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1454 | return ret;\ | 
|---|
| 1455 | JNI_END | 
|---|
| 1456 |  | 
|---|
| 1457 | // the runtime type of subword integral basic types is integer | 
|---|
| 1458 | DEFINE_CALLMETHODV(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1459 | , HOTSPOT_JNI_CALLBOOLEANMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1460 | HOTSPOT_JNI_CALLBOOLEANMETHODV_RETURN(_ret_ref)) | 
|---|
| 1461 | DEFINE_CALLMETHODV(jbyte,    Byte,    T_BYTE | 
|---|
| 1462 | , HOTSPOT_JNI_CALLBYTEMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1463 | HOTSPOT_JNI_CALLBYTEMETHODV_RETURN(_ret_ref)) | 
|---|
| 1464 | DEFINE_CALLMETHODV(jchar,    Char,    T_CHAR | 
|---|
| 1465 | , HOTSPOT_JNI_CALLCHARMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1466 | HOTSPOT_JNI_CALLCHARMETHODV_RETURN(_ret_ref)) | 
|---|
| 1467 | DEFINE_CALLMETHODV(jshort,   Short,   T_SHORT | 
|---|
| 1468 | , HOTSPOT_JNI_CALLSHORTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1469 | HOTSPOT_JNI_CALLSHORTMETHODV_RETURN(_ret_ref)) | 
|---|
| 1470 |  | 
|---|
| 1471 | DEFINE_CALLMETHODV(jobject,  Object,  T_OBJECT | 
|---|
| 1472 | , HOTSPOT_JNI_CALLOBJECTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1473 | HOTSPOT_JNI_CALLOBJECTMETHODV_RETURN(_ret_ref)) | 
|---|
| 1474 | DEFINE_CALLMETHODV(jint,     Int,     T_INT, | 
|---|
| 1475 | HOTSPOT_JNI_CALLINTMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1476 | HOTSPOT_JNI_CALLINTMETHODV_RETURN(_ret_ref)) | 
|---|
| 1477 | DEFINE_CALLMETHODV(jlong,    Long,    T_LONG | 
|---|
| 1478 | , HOTSPOT_JNI_CALLLONGMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1479 | HOTSPOT_JNI_CALLLONGMETHODV_RETURN(_ret_ref)) | 
|---|
| 1480 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1481 | DEFINE_CALLMETHODV(jfloat,   Float,   T_FLOAT | 
|---|
| 1482 | , HOTSPOT_JNI_CALLFLOATMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1483 | HOTSPOT_JNI_CALLFLOATMETHODV_RETURN()) | 
|---|
| 1484 | DEFINE_CALLMETHODV(jdouble,  Double,  T_DOUBLE | 
|---|
| 1485 | , HOTSPOT_JNI_CALLDOUBLEMETHODV_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1486 | HOTSPOT_JNI_CALLDOUBLEMETHODV_RETURN()) | 
|---|
| 1487 |  | 
|---|
| 1488 | #define DEFINE_CALLMETHODA(ResultType, Result, Tag \ | 
|---|
| 1489 | , EntryProbe, ReturnProbe)    \ | 
|---|
| 1490 | \ | 
|---|
| 1491 | DT_RETURN_MARK_DECL_FOR(Result, Call##Result##MethodA, ResultType \ | 
|---|
| 1492 | , ReturnProbe);                          \ | 
|---|
| 1493 | \ | 
|---|
| 1494 | JNI_ENTRY(ResultType, \ | 
|---|
| 1495 | jni_Call##Result##MethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args)) \ | 
|---|
| 1496 | JNIWrapper("Call" XSTR(Result) "MethodA"); \ | 
|---|
| 1497 | EntryProbe; \ | 
|---|
| 1498 | ResultType ret = 0;\ | 
|---|
| 1499 | DT_RETURN_MARK_FOR(Result, Call##Result##MethodA, ResultType, \ | 
|---|
| 1500 | (const ResultType&)ret);\ | 
|---|
| 1501 | \ | 
|---|
| 1502 | JavaValue jvalue(Tag); \ | 
|---|
| 1503 | JNI_ArgumentPusherArray ap(methodID, args); \ | 
|---|
| 1504 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK_0); \ | 
|---|
| 1505 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1506 | return ret;\ | 
|---|
| 1507 | JNI_END | 
|---|
| 1508 |  | 
|---|
| 1509 | // the runtime type of subword integral basic types is integer | 
|---|
| 1510 | DEFINE_CALLMETHODA(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1511 | , HOTSPOT_JNI_CALLBOOLEANMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1512 | HOTSPOT_JNI_CALLBOOLEANMETHODA_RETURN(_ret_ref)) | 
|---|
| 1513 | DEFINE_CALLMETHODA(jbyte,    Byte,    T_BYTE | 
|---|
| 1514 | , HOTSPOT_JNI_CALLBYTEMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1515 | HOTSPOT_JNI_CALLBYTEMETHODA_RETURN(_ret_ref)) | 
|---|
| 1516 | DEFINE_CALLMETHODA(jchar,    Char,    T_CHAR | 
|---|
| 1517 | , HOTSPOT_JNI_CALLCHARMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1518 | HOTSPOT_JNI_CALLCHARMETHODA_RETURN(_ret_ref)) | 
|---|
| 1519 | DEFINE_CALLMETHODA(jshort,   Short,   T_SHORT | 
|---|
| 1520 | , HOTSPOT_JNI_CALLSHORTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1521 | HOTSPOT_JNI_CALLSHORTMETHODA_RETURN(_ret_ref)) | 
|---|
| 1522 |  | 
|---|
| 1523 | DEFINE_CALLMETHODA(jobject,  Object,  T_OBJECT | 
|---|
| 1524 | , HOTSPOT_JNI_CALLOBJECTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1525 | HOTSPOT_JNI_CALLOBJECTMETHODA_RETURN(_ret_ref)) | 
|---|
| 1526 | DEFINE_CALLMETHODA(jint,     Int,     T_INT, | 
|---|
| 1527 | HOTSPOT_JNI_CALLINTMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1528 | HOTSPOT_JNI_CALLINTMETHODA_RETURN(_ret_ref)) | 
|---|
| 1529 | DEFINE_CALLMETHODA(jlong,    Long,    T_LONG | 
|---|
| 1530 | , HOTSPOT_JNI_CALLLONGMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1531 | HOTSPOT_JNI_CALLLONGMETHODA_RETURN(_ret_ref)) | 
|---|
| 1532 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1533 | DEFINE_CALLMETHODA(jfloat,   Float,   T_FLOAT | 
|---|
| 1534 | , HOTSPOT_JNI_CALLFLOATMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1535 | HOTSPOT_JNI_CALLFLOATMETHODA_RETURN()) | 
|---|
| 1536 | DEFINE_CALLMETHODA(jdouble,  Double,  T_DOUBLE | 
|---|
| 1537 | , HOTSPOT_JNI_CALLDOUBLEMETHODA_ENTRY(env, obj, (uintptr_t)methodID), | 
|---|
| 1538 | HOTSPOT_JNI_CALLDOUBLEMETHODA_RETURN()) | 
|---|
| 1539 |  | 
|---|
| 1540 | DT_VOID_RETURN_MARK_DECL(CallVoidMethod, HOTSPOT_JNI_CALLVOIDMETHOD_RETURN()); | 
|---|
| 1541 | DT_VOID_RETURN_MARK_DECL(CallVoidMethodV, HOTSPOT_JNI_CALLVOIDMETHODV_RETURN()); | 
|---|
| 1542 | DT_VOID_RETURN_MARK_DECL(CallVoidMethodA, HOTSPOT_JNI_CALLVOIDMETHODA_RETURN()); | 
|---|
| 1543 |  | 
|---|
| 1544 |  | 
|---|
| 1545 | JNI_ENTRY(void, jni_CallVoidMethod(JNIEnv *env, jobject obj, jmethodID methodID, ...)) | 
|---|
| 1546 | JNIWrapper( "CallVoidMethod"); | 
|---|
| 1547 | HOTSPOT_JNI_CALLVOIDMETHOD_ENTRY(env, obj, (uintptr_t) methodID); | 
|---|
| 1548 | DT_VOID_RETURN_MARK(CallVoidMethod); | 
|---|
| 1549 |  | 
|---|
| 1550 | va_list args; | 
|---|
| 1551 | va_start(args, methodID); | 
|---|
| 1552 | JavaValue jvalue(T_VOID); | 
|---|
| 1553 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1554 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK); | 
|---|
| 1555 | va_end(args); | 
|---|
| 1556 | JNI_END | 
|---|
| 1557 |  | 
|---|
| 1558 |  | 
|---|
| 1559 | JNI_ENTRY(void, jni_CallVoidMethodV(JNIEnv *env, jobject obj, jmethodID methodID, va_list args)) | 
|---|
| 1560 | JNIWrapper( "CallVoidMethodV"); | 
|---|
| 1561 | HOTSPOT_JNI_CALLVOIDMETHODV_ENTRY(env, obj, (uintptr_t) methodID); | 
|---|
| 1562 | DT_VOID_RETURN_MARK(CallVoidMethodV); | 
|---|
| 1563 |  | 
|---|
| 1564 | JavaValue jvalue(T_VOID); | 
|---|
| 1565 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1566 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK); | 
|---|
| 1567 | JNI_END | 
|---|
| 1568 |  | 
|---|
| 1569 |  | 
|---|
| 1570 | JNI_ENTRY(void, jni_CallVoidMethodA(JNIEnv *env, jobject obj, jmethodID methodID, const jvalue *args)) | 
|---|
| 1571 | JNIWrapper( "CallVoidMethodA"); | 
|---|
| 1572 | HOTSPOT_JNI_CALLVOIDMETHODA_ENTRY(env, obj, (uintptr_t) methodID); | 
|---|
| 1573 | DT_VOID_RETURN_MARK(CallVoidMethodA); | 
|---|
| 1574 |  | 
|---|
| 1575 | JavaValue jvalue(T_VOID); | 
|---|
| 1576 | JNI_ArgumentPusherArray ap(methodID, args); | 
|---|
| 1577 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_VIRTUAL, methodID, &ap, CHECK); | 
|---|
| 1578 | JNI_END | 
|---|
| 1579 |  | 
|---|
| 1580 |  | 
|---|
| 1581 |  | 
|---|
| 1582 | #define DEFINE_CALLNONVIRTUALMETHOD(ResultType, Result, Tag \ | 
|---|
| 1583 | , EntryProbe, ReturnProbe)      \ | 
|---|
| 1584 | \ | 
|---|
| 1585 | DT_RETURN_MARK_DECL_FOR(Result, CallNonvirtual##Result##Method, ResultType \ | 
|---|
| 1586 | , ReturnProbe);\ | 
|---|
| 1587 | \ | 
|---|
| 1588 | JNI_ENTRY(ResultType, \ | 
|---|
| 1589 | jni_CallNonvirtual##Result##Method(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, ...)) \ | 
|---|
| 1590 | JNIWrapper("CallNonvitual" XSTR(Result) "Method"); \ | 
|---|
| 1591 | \ | 
|---|
| 1592 | EntryProbe;\ | 
|---|
| 1593 | ResultType ret;\ | 
|---|
| 1594 | DT_RETURN_MARK_FOR(Result, CallNonvirtual##Result##Method, ResultType, \ | 
|---|
| 1595 | (const ResultType&)ret);\ | 
|---|
| 1596 | \ | 
|---|
| 1597 | va_list args; \ | 
|---|
| 1598 | va_start(args, methodID); \ | 
|---|
| 1599 | JavaValue jvalue(Tag); \ | 
|---|
| 1600 | JNI_ArgumentPusherVaArg ap(methodID, args); \ | 
|---|
| 1601 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ | 
|---|
| 1602 | va_end(args); \ | 
|---|
| 1603 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1604 | return ret;\ | 
|---|
| 1605 | JNI_END | 
|---|
| 1606 |  | 
|---|
| 1607 | // the runtime type of subword integral basic types is integer | 
|---|
| 1608 | DEFINE_CALLNONVIRTUALMETHOD(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1609 | , HOTSPOT_JNI_CALLNONVIRTUALBOOLEANMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1610 | HOTSPOT_JNI_CALLNONVIRTUALBOOLEANMETHOD_RETURN(_ret_ref)) | 
|---|
| 1611 | DEFINE_CALLNONVIRTUALMETHOD(jbyte,    Byte,    T_BYTE | 
|---|
| 1612 | , HOTSPOT_JNI_CALLNONVIRTUALBYTEMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1613 | HOTSPOT_JNI_CALLNONVIRTUALBYTEMETHOD_RETURN(_ret_ref)) | 
|---|
| 1614 | DEFINE_CALLNONVIRTUALMETHOD(jchar,    Char,    T_CHAR | 
|---|
| 1615 | , HOTSPOT_JNI_CALLNONVIRTUALCHARMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1616 | HOTSPOT_JNI_CALLNONVIRTUALCHARMETHOD_RETURN(_ret_ref)) | 
|---|
| 1617 | DEFINE_CALLNONVIRTUALMETHOD(jshort,   Short,   T_SHORT | 
|---|
| 1618 | , HOTSPOT_JNI_CALLNONVIRTUALSHORTMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1619 | HOTSPOT_JNI_CALLNONVIRTUALSHORTMETHOD_RETURN(_ret_ref)) | 
|---|
| 1620 |  | 
|---|
| 1621 | DEFINE_CALLNONVIRTUALMETHOD(jobject,  Object,  T_OBJECT | 
|---|
| 1622 | , HOTSPOT_JNI_CALLNONVIRTUALOBJECTMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1623 | HOTSPOT_JNI_CALLNONVIRTUALOBJECTMETHOD_RETURN(_ret_ref)) | 
|---|
| 1624 | DEFINE_CALLNONVIRTUALMETHOD(jint,     Int,     T_INT | 
|---|
| 1625 | , HOTSPOT_JNI_CALLNONVIRTUALINTMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1626 | HOTSPOT_JNI_CALLNONVIRTUALINTMETHOD_RETURN(_ret_ref)) | 
|---|
| 1627 | DEFINE_CALLNONVIRTUALMETHOD(jlong,    Long,    T_LONG | 
|---|
| 1628 | , HOTSPOT_JNI_CALLNONVIRTUALLONGMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1629 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1630 | HOTSPOT_JNI_CALLNONVIRTUALLONGMETHOD_RETURN(_ret_ref)) | 
|---|
| 1631 | DEFINE_CALLNONVIRTUALMETHOD(jfloat,   Float,   T_FLOAT | 
|---|
| 1632 | , HOTSPOT_JNI_CALLNONVIRTUALFLOATMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1633 | HOTSPOT_JNI_CALLNONVIRTUALFLOATMETHOD_RETURN()) | 
|---|
| 1634 | DEFINE_CALLNONVIRTUALMETHOD(jdouble,  Double,  T_DOUBLE | 
|---|
| 1635 | , HOTSPOT_JNI_CALLNONVIRTUALDOUBLEMETHOD_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1636 | HOTSPOT_JNI_CALLNONVIRTUALDOUBLEMETHOD_RETURN()) | 
|---|
| 1637 |  | 
|---|
| 1638 | #define DEFINE_CALLNONVIRTUALMETHODV(ResultType, Result, Tag \ | 
|---|
| 1639 | , EntryProbe, ReturnProbe)      \ | 
|---|
| 1640 | \ | 
|---|
| 1641 | DT_RETURN_MARK_DECL_FOR(Result, CallNonvirtual##Result##MethodV, ResultType \ | 
|---|
| 1642 | , ReturnProbe);\ | 
|---|
| 1643 | \ | 
|---|
| 1644 | JNI_ENTRY(ResultType, \ | 
|---|
| 1645 | jni_CallNonvirtual##Result##MethodV(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, va_list args)) \ | 
|---|
| 1646 | JNIWrapper("CallNonvitual" XSTR(Result) "MethodV"); \ | 
|---|
| 1647 | \ | 
|---|
| 1648 | EntryProbe;\ | 
|---|
| 1649 | ResultType ret;\ | 
|---|
| 1650 | DT_RETURN_MARK_FOR(Result, CallNonvirtual##Result##MethodV, ResultType, \ | 
|---|
| 1651 | (const ResultType&)ret);\ | 
|---|
| 1652 | \ | 
|---|
| 1653 | JavaValue jvalue(Tag); \ | 
|---|
| 1654 | JNI_ArgumentPusherVaArg ap(methodID, args); \ | 
|---|
| 1655 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ | 
|---|
| 1656 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1657 | return ret;\ | 
|---|
| 1658 | JNI_END | 
|---|
| 1659 |  | 
|---|
| 1660 | // the runtime type of subword integral basic types is integer | 
|---|
| 1661 | DEFINE_CALLNONVIRTUALMETHODV(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1662 | , HOTSPOT_JNI_CALLNONVIRTUALBOOLEANMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1663 | HOTSPOT_JNI_CALLNONVIRTUALBOOLEANMETHODV_RETURN(_ret_ref)) | 
|---|
| 1664 | DEFINE_CALLNONVIRTUALMETHODV(jbyte,    Byte,    T_BYTE | 
|---|
| 1665 | , HOTSPOT_JNI_CALLNONVIRTUALBYTEMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1666 | HOTSPOT_JNI_CALLNONVIRTUALBYTEMETHODV_RETURN(_ret_ref)) | 
|---|
| 1667 | DEFINE_CALLNONVIRTUALMETHODV(jchar,    Char,    T_CHAR | 
|---|
| 1668 | , HOTSPOT_JNI_CALLNONVIRTUALCHARMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1669 | HOTSPOT_JNI_CALLNONVIRTUALCHARMETHODV_RETURN(_ret_ref)) | 
|---|
| 1670 | DEFINE_CALLNONVIRTUALMETHODV(jshort,   Short,   T_SHORT | 
|---|
| 1671 | , HOTSPOT_JNI_CALLNONVIRTUALSHORTMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1672 | HOTSPOT_JNI_CALLNONVIRTUALSHORTMETHODV_RETURN(_ret_ref)) | 
|---|
| 1673 |  | 
|---|
| 1674 | DEFINE_CALLNONVIRTUALMETHODV(jobject,  Object,  T_OBJECT | 
|---|
| 1675 | , HOTSPOT_JNI_CALLNONVIRTUALOBJECTMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1676 | HOTSPOT_JNI_CALLNONVIRTUALOBJECTMETHODV_RETURN(_ret_ref)) | 
|---|
| 1677 | DEFINE_CALLNONVIRTUALMETHODV(jint,     Int,     T_INT | 
|---|
| 1678 | , HOTSPOT_JNI_CALLNONVIRTUALINTMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1679 | HOTSPOT_JNI_CALLNONVIRTUALINTMETHODV_RETURN(_ret_ref)) | 
|---|
| 1680 | DEFINE_CALLNONVIRTUALMETHODV(jlong,    Long,    T_LONG | 
|---|
| 1681 | , HOTSPOT_JNI_CALLNONVIRTUALLONGMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1682 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1683 | HOTSPOT_JNI_CALLNONVIRTUALLONGMETHODV_RETURN(_ret_ref)) | 
|---|
| 1684 | DEFINE_CALLNONVIRTUALMETHODV(jfloat,   Float,   T_FLOAT | 
|---|
| 1685 | , HOTSPOT_JNI_CALLNONVIRTUALFLOATMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1686 | HOTSPOT_JNI_CALLNONVIRTUALFLOATMETHODV_RETURN()) | 
|---|
| 1687 | DEFINE_CALLNONVIRTUALMETHODV(jdouble,  Double,  T_DOUBLE | 
|---|
| 1688 | , HOTSPOT_JNI_CALLNONVIRTUALDOUBLEMETHODV_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1689 | HOTSPOT_JNI_CALLNONVIRTUALDOUBLEMETHODV_RETURN()) | 
|---|
| 1690 |  | 
|---|
| 1691 | #define DEFINE_CALLNONVIRTUALMETHODA(ResultType, Result, Tag \ | 
|---|
| 1692 | , EntryProbe, ReturnProbe)      \ | 
|---|
| 1693 | \ | 
|---|
| 1694 | DT_RETURN_MARK_DECL_FOR(Result, CallNonvirtual##Result##MethodA, ResultType \ | 
|---|
| 1695 | , ReturnProbe);\ | 
|---|
| 1696 | \ | 
|---|
| 1697 | JNI_ENTRY(ResultType, \ | 
|---|
| 1698 | jni_CallNonvirtual##Result##MethodA(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, const jvalue *args)) \ | 
|---|
| 1699 | JNIWrapper("CallNonvitual" XSTR(Result) "MethodA"); \ | 
|---|
| 1700 | \ | 
|---|
| 1701 | EntryProbe;\ | 
|---|
| 1702 | ResultType ret;\ | 
|---|
| 1703 | DT_RETURN_MARK_FOR(Result, CallNonvirtual##Result##MethodA, ResultType, \ | 
|---|
| 1704 | (const ResultType&)ret);\ | 
|---|
| 1705 | \ | 
|---|
| 1706 | JavaValue jvalue(Tag); \ | 
|---|
| 1707 | JNI_ArgumentPusherArray ap(methodID, args); \ | 
|---|
| 1708 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK_0); \ | 
|---|
| 1709 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1710 | return ret;\ | 
|---|
| 1711 | JNI_END | 
|---|
| 1712 |  | 
|---|
| 1713 | // the runtime type of subword integral basic types is integer | 
|---|
| 1714 | DEFINE_CALLNONVIRTUALMETHODA(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1715 | , HOTSPOT_JNI_CALLNONVIRTUALBOOLEANMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1716 | HOTSPOT_JNI_CALLNONVIRTUALBOOLEANMETHODA_RETURN(_ret_ref)) | 
|---|
| 1717 | DEFINE_CALLNONVIRTUALMETHODA(jbyte,    Byte,    T_BYTE | 
|---|
| 1718 | , HOTSPOT_JNI_CALLNONVIRTUALBYTEMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1719 | HOTSPOT_JNI_CALLNONVIRTUALBYTEMETHODA_RETURN(_ret_ref)) | 
|---|
| 1720 | DEFINE_CALLNONVIRTUALMETHODA(jchar,    Char,    T_CHAR | 
|---|
| 1721 | , HOTSPOT_JNI_CALLNONVIRTUALCHARMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1722 | HOTSPOT_JNI_CALLNONVIRTUALCHARMETHODA_RETURN(_ret_ref)) | 
|---|
| 1723 | DEFINE_CALLNONVIRTUALMETHODA(jshort,   Short,   T_SHORT | 
|---|
| 1724 | , HOTSPOT_JNI_CALLNONVIRTUALSHORTMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1725 | HOTSPOT_JNI_CALLNONVIRTUALSHORTMETHODA_RETURN(_ret_ref)) | 
|---|
| 1726 |  | 
|---|
| 1727 | DEFINE_CALLNONVIRTUALMETHODA(jobject,  Object,  T_OBJECT | 
|---|
| 1728 | , HOTSPOT_JNI_CALLNONVIRTUALOBJECTMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1729 | HOTSPOT_JNI_CALLNONVIRTUALOBJECTMETHODA_RETURN(_ret_ref)) | 
|---|
| 1730 | DEFINE_CALLNONVIRTUALMETHODA(jint,     Int,     T_INT | 
|---|
| 1731 | , HOTSPOT_JNI_CALLNONVIRTUALINTMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1732 | HOTSPOT_JNI_CALLNONVIRTUALINTMETHODA_RETURN(_ret_ref)) | 
|---|
| 1733 | DEFINE_CALLNONVIRTUALMETHODA(jlong,    Long,    T_LONG | 
|---|
| 1734 | , HOTSPOT_JNI_CALLNONVIRTUALLONGMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1735 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1736 | HOTSPOT_JNI_CALLNONVIRTUALLONGMETHODA_RETURN(_ret_ref)) | 
|---|
| 1737 | DEFINE_CALLNONVIRTUALMETHODA(jfloat,   Float,   T_FLOAT | 
|---|
| 1738 | , HOTSPOT_JNI_CALLNONVIRTUALFLOATMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1739 | HOTSPOT_JNI_CALLNONVIRTUALFLOATMETHODA_RETURN()) | 
|---|
| 1740 | DEFINE_CALLNONVIRTUALMETHODA(jdouble,  Double,  T_DOUBLE | 
|---|
| 1741 | , HOTSPOT_JNI_CALLNONVIRTUALDOUBLEMETHODA_ENTRY(env, obj, cls, (uintptr_t)methodID), | 
|---|
| 1742 | HOTSPOT_JNI_CALLNONVIRTUALDOUBLEMETHODA_RETURN()) | 
|---|
| 1743 |  | 
|---|
| 1744 | DT_VOID_RETURN_MARK_DECL(CallNonvirtualVoidMethod | 
|---|
| 1745 | , HOTSPOT_JNI_CALLNONVIRTUALVOIDMETHOD_RETURN()); | 
|---|
| 1746 | DT_VOID_RETURN_MARK_DECL(CallNonvirtualVoidMethodV | 
|---|
| 1747 | , HOTSPOT_JNI_CALLNONVIRTUALVOIDMETHODV_RETURN()); | 
|---|
| 1748 | DT_VOID_RETURN_MARK_DECL(CallNonvirtualVoidMethodA | 
|---|
| 1749 | , HOTSPOT_JNI_CALLNONVIRTUALVOIDMETHODA_RETURN()); | 
|---|
| 1750 |  | 
|---|
| 1751 | JNI_ENTRY(void, jni_CallNonvirtualVoidMethod(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, ...)) | 
|---|
| 1752 | JNIWrapper( "CallNonvirtualVoidMethod"); | 
|---|
| 1753 |  | 
|---|
| 1754 | HOTSPOT_JNI_CALLNONVIRTUALVOIDMETHOD_ENTRY(env, obj, cls, (uintptr_t) methodID); | 
|---|
| 1755 | DT_VOID_RETURN_MARK(CallNonvirtualVoidMethod); | 
|---|
| 1756 |  | 
|---|
| 1757 | va_list args; | 
|---|
| 1758 | va_start(args, methodID); | 
|---|
| 1759 | JavaValue jvalue(T_VOID); | 
|---|
| 1760 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1761 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK); | 
|---|
| 1762 | va_end(args); | 
|---|
| 1763 | JNI_END | 
|---|
| 1764 |  | 
|---|
| 1765 |  | 
|---|
| 1766 | JNI_ENTRY(void, jni_CallNonvirtualVoidMethodV(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, va_list args)) | 
|---|
| 1767 | JNIWrapper( "CallNonvirtualVoidMethodV"); | 
|---|
| 1768 |  | 
|---|
| 1769 | HOTSPOT_JNI_CALLNONVIRTUALVOIDMETHODV_ENTRY( | 
|---|
| 1770 | env, obj, cls, (uintptr_t) methodID); | 
|---|
| 1771 | DT_VOID_RETURN_MARK(CallNonvirtualVoidMethodV); | 
|---|
| 1772 |  | 
|---|
| 1773 | JavaValue jvalue(T_VOID); | 
|---|
| 1774 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1775 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK); | 
|---|
| 1776 | JNI_END | 
|---|
| 1777 |  | 
|---|
| 1778 |  | 
|---|
| 1779 | JNI_ENTRY(void, jni_CallNonvirtualVoidMethodA(JNIEnv *env, jobject obj, jclass cls, jmethodID methodID, const jvalue *args)) | 
|---|
| 1780 | JNIWrapper( "CallNonvirtualVoidMethodA"); | 
|---|
| 1781 | HOTSPOT_JNI_CALLNONVIRTUALVOIDMETHODA_ENTRY( | 
|---|
| 1782 | env, obj, cls, (uintptr_t) methodID); | 
|---|
| 1783 | DT_VOID_RETURN_MARK(CallNonvirtualVoidMethodA); | 
|---|
| 1784 | JavaValue jvalue(T_VOID); | 
|---|
| 1785 | JNI_ArgumentPusherArray ap(methodID, args); | 
|---|
| 1786 | jni_invoke_nonstatic(env, &jvalue, obj, JNI_NONVIRTUAL, methodID, &ap, CHECK); | 
|---|
| 1787 | JNI_END | 
|---|
| 1788 |  | 
|---|
| 1789 |  | 
|---|
| 1790 |  | 
|---|
| 1791 | #define DEFINE_CALLSTATICMETHOD(ResultType, Result, Tag \ | 
|---|
| 1792 | , EntryProbe, ResultProbe) \ | 
|---|
| 1793 | \ | 
|---|
| 1794 | DT_RETURN_MARK_DECL_FOR(Result, CallStatic##Result##Method, ResultType \ | 
|---|
| 1795 | , ResultProbe);                               \ | 
|---|
| 1796 | \ | 
|---|
| 1797 | JNI_ENTRY(ResultType, \ | 
|---|
| 1798 | jni_CallStatic##Result##Method(JNIEnv *env, jclass cls, jmethodID methodID, ...)) \ | 
|---|
| 1799 | JNIWrapper("CallStatic" XSTR(Result) "Method"); \ | 
|---|
| 1800 | \ | 
|---|
| 1801 | EntryProbe; \ | 
|---|
| 1802 | ResultType ret = 0;\ | 
|---|
| 1803 | DT_RETURN_MARK_FOR(Result, CallStatic##Result##Method, ResultType, \ | 
|---|
| 1804 | (const ResultType&)ret);\ | 
|---|
| 1805 | \ | 
|---|
| 1806 | va_list args; \ | 
|---|
| 1807 | va_start(args, methodID); \ | 
|---|
| 1808 | JavaValue jvalue(Tag); \ | 
|---|
| 1809 | JNI_ArgumentPusherVaArg ap(methodID, args); \ | 
|---|
| 1810 | jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK_0); \ | 
|---|
| 1811 | va_end(args); \ | 
|---|
| 1812 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1813 | return ret;\ | 
|---|
| 1814 | JNI_END | 
|---|
| 1815 |  | 
|---|
| 1816 | // the runtime type of subword integral basic types is integer | 
|---|
| 1817 | DEFINE_CALLSTATICMETHOD(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1818 | , HOTSPOT_JNI_CALLSTATICBOOLEANMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1819 | HOTSPOT_JNI_CALLSTATICBOOLEANMETHOD_RETURN(_ret_ref)); | 
|---|
| 1820 | DEFINE_CALLSTATICMETHOD(jbyte,    Byte,    T_BYTE | 
|---|
| 1821 | , HOTSPOT_JNI_CALLSTATICBYTEMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1822 | HOTSPOT_JNI_CALLSTATICBYTEMETHOD_RETURN(_ret_ref)); | 
|---|
| 1823 | DEFINE_CALLSTATICMETHOD(jchar,    Char,    T_CHAR | 
|---|
| 1824 | , HOTSPOT_JNI_CALLSTATICCHARMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1825 | HOTSPOT_JNI_CALLSTATICCHARMETHOD_RETURN(_ret_ref)); | 
|---|
| 1826 | DEFINE_CALLSTATICMETHOD(jshort,   Short,   T_SHORT | 
|---|
| 1827 | , HOTSPOT_JNI_CALLSTATICSHORTMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1828 | HOTSPOT_JNI_CALLSTATICSHORTMETHOD_RETURN(_ret_ref)); | 
|---|
| 1829 |  | 
|---|
| 1830 | DEFINE_CALLSTATICMETHOD(jobject,  Object,  T_OBJECT | 
|---|
| 1831 | , HOTSPOT_JNI_CALLSTATICOBJECTMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1832 | HOTSPOT_JNI_CALLSTATICOBJECTMETHOD_RETURN(_ret_ref)); | 
|---|
| 1833 | DEFINE_CALLSTATICMETHOD(jint,     Int,     T_INT | 
|---|
| 1834 | , HOTSPOT_JNI_CALLSTATICINTMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1835 | HOTSPOT_JNI_CALLSTATICINTMETHOD_RETURN(_ret_ref)); | 
|---|
| 1836 | DEFINE_CALLSTATICMETHOD(jlong,    Long,    T_LONG | 
|---|
| 1837 | , HOTSPOT_JNI_CALLSTATICLONGMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1838 | HOTSPOT_JNI_CALLSTATICLONGMETHOD_RETURN(_ret_ref)); | 
|---|
| 1839 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1840 | DEFINE_CALLSTATICMETHOD(jfloat,   Float,   T_FLOAT | 
|---|
| 1841 | , HOTSPOT_JNI_CALLSTATICFLOATMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1842 | HOTSPOT_JNI_CALLSTATICFLOATMETHOD_RETURN()); | 
|---|
| 1843 | DEFINE_CALLSTATICMETHOD(jdouble,  Double,  T_DOUBLE | 
|---|
| 1844 | , HOTSPOT_JNI_CALLSTATICDOUBLEMETHOD_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1845 | HOTSPOT_JNI_CALLSTATICDOUBLEMETHOD_RETURN()); | 
|---|
| 1846 |  | 
|---|
| 1847 | #define DEFINE_CALLSTATICMETHODV(ResultType, Result, Tag \ | 
|---|
| 1848 | , EntryProbe, ResultProbe) \ | 
|---|
| 1849 | \ | 
|---|
| 1850 | DT_RETURN_MARK_DECL_FOR(Result, CallStatic##Result##MethodV, ResultType \ | 
|---|
| 1851 | , ResultProbe);                               \ | 
|---|
| 1852 | \ | 
|---|
| 1853 | JNI_ENTRY(ResultType, \ | 
|---|
| 1854 | jni_CallStatic##Result##MethodV(JNIEnv *env, jclass cls, jmethodID methodID, va_list args)) \ | 
|---|
| 1855 | JNIWrapper("CallStatic" XSTR(Result) "MethodV"); \ | 
|---|
| 1856 | \ | 
|---|
| 1857 | EntryProbe; \ | 
|---|
| 1858 | ResultType ret = 0;\ | 
|---|
| 1859 | DT_RETURN_MARK_FOR(Result, CallStatic##Result##MethodV, ResultType, \ | 
|---|
| 1860 | (const ResultType&)ret);\ | 
|---|
| 1861 | \ | 
|---|
| 1862 | JavaValue jvalue(Tag); \ | 
|---|
| 1863 | JNI_ArgumentPusherVaArg ap(methodID, args); \ | 
|---|
| 1864 | /* Make sure class is initialized before trying to invoke its method */ \ | 
|---|
| 1865 | Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); \ | 
|---|
| 1866 | k->initialize(CHECK_0); \ | 
|---|
| 1867 | jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK_0); \ | 
|---|
| 1868 | va_end(args); \ | 
|---|
| 1869 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1870 | return ret;\ | 
|---|
| 1871 | JNI_END | 
|---|
| 1872 |  | 
|---|
| 1873 | // the runtime type of subword integral basic types is integer | 
|---|
| 1874 | DEFINE_CALLSTATICMETHODV(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1875 | , HOTSPOT_JNI_CALLSTATICBOOLEANMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1876 | HOTSPOT_JNI_CALLSTATICBOOLEANMETHODV_RETURN(_ret_ref)); | 
|---|
| 1877 | DEFINE_CALLSTATICMETHODV(jbyte,    Byte,    T_BYTE | 
|---|
| 1878 | , HOTSPOT_JNI_CALLSTATICBYTEMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1879 | HOTSPOT_JNI_CALLSTATICBYTEMETHODV_RETURN(_ret_ref)); | 
|---|
| 1880 | DEFINE_CALLSTATICMETHODV(jchar,    Char,    T_CHAR | 
|---|
| 1881 | , HOTSPOT_JNI_CALLSTATICCHARMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1882 | HOTSPOT_JNI_CALLSTATICCHARMETHODV_RETURN(_ret_ref)); | 
|---|
| 1883 | DEFINE_CALLSTATICMETHODV(jshort,   Short,   T_SHORT | 
|---|
| 1884 | , HOTSPOT_JNI_CALLSTATICSHORTMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1885 | HOTSPOT_JNI_CALLSTATICSHORTMETHODV_RETURN(_ret_ref)); | 
|---|
| 1886 |  | 
|---|
| 1887 | DEFINE_CALLSTATICMETHODV(jobject,  Object,  T_OBJECT | 
|---|
| 1888 | , HOTSPOT_JNI_CALLSTATICOBJECTMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1889 | HOTSPOT_JNI_CALLSTATICOBJECTMETHODV_RETURN(_ret_ref)); | 
|---|
| 1890 | DEFINE_CALLSTATICMETHODV(jint,     Int,     T_INT | 
|---|
| 1891 | , HOTSPOT_JNI_CALLSTATICINTMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1892 | HOTSPOT_JNI_CALLSTATICINTMETHODV_RETURN(_ret_ref)); | 
|---|
| 1893 | DEFINE_CALLSTATICMETHODV(jlong,    Long,    T_LONG | 
|---|
| 1894 | , HOTSPOT_JNI_CALLSTATICLONGMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1895 | HOTSPOT_JNI_CALLSTATICLONGMETHODV_RETURN(_ret_ref)); | 
|---|
| 1896 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1897 | DEFINE_CALLSTATICMETHODV(jfloat,   Float,   T_FLOAT | 
|---|
| 1898 | , HOTSPOT_JNI_CALLSTATICFLOATMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1899 | HOTSPOT_JNI_CALLSTATICFLOATMETHODV_RETURN()); | 
|---|
| 1900 | DEFINE_CALLSTATICMETHODV(jdouble,  Double,  T_DOUBLE | 
|---|
| 1901 | , HOTSPOT_JNI_CALLSTATICDOUBLEMETHODV_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1902 | HOTSPOT_JNI_CALLSTATICDOUBLEMETHODV_RETURN()); | 
|---|
| 1903 |  | 
|---|
| 1904 | #define DEFINE_CALLSTATICMETHODA(ResultType, Result, Tag \ | 
|---|
| 1905 | , EntryProbe, ResultProbe) \ | 
|---|
| 1906 | \ | 
|---|
| 1907 | DT_RETURN_MARK_DECL_FOR(Result, CallStatic##Result##MethodA, ResultType \ | 
|---|
| 1908 | , ResultProbe);                               \ | 
|---|
| 1909 | \ | 
|---|
| 1910 | JNI_ENTRY(ResultType, \ | 
|---|
| 1911 | jni_CallStatic##Result##MethodA(JNIEnv *env, jclass cls, jmethodID methodID, const jvalue *args)) \ | 
|---|
| 1912 | JNIWrapper("CallStatic" XSTR(Result) "MethodA"); \ | 
|---|
| 1913 | \ | 
|---|
| 1914 | EntryProbe; \ | 
|---|
| 1915 | ResultType ret = 0;\ | 
|---|
| 1916 | DT_RETURN_MARK_FOR(Result, CallStatic##Result##MethodA, ResultType, \ | 
|---|
| 1917 | (const ResultType&)ret);\ | 
|---|
| 1918 | \ | 
|---|
| 1919 | JavaValue jvalue(Tag); \ | 
|---|
| 1920 | JNI_ArgumentPusherArray ap(methodID, args); \ | 
|---|
| 1921 | jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK_0); \ | 
|---|
| 1922 | ret = jvalue.get_##ResultType(); \ | 
|---|
| 1923 | return ret;\ | 
|---|
| 1924 | JNI_END | 
|---|
| 1925 |  | 
|---|
| 1926 | // the runtime type of subword integral basic types is integer | 
|---|
| 1927 | DEFINE_CALLSTATICMETHODA(jboolean, Boolean, T_BOOLEAN | 
|---|
| 1928 | , HOTSPOT_JNI_CALLSTATICBOOLEANMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1929 | HOTSPOT_JNI_CALLSTATICBOOLEANMETHODA_RETURN(_ret_ref)); | 
|---|
| 1930 | DEFINE_CALLSTATICMETHODA(jbyte,    Byte,    T_BYTE | 
|---|
| 1931 | , HOTSPOT_JNI_CALLSTATICBYTEMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1932 | HOTSPOT_JNI_CALLSTATICBYTEMETHODA_RETURN(_ret_ref)); | 
|---|
| 1933 | DEFINE_CALLSTATICMETHODA(jchar,    Char,    T_CHAR | 
|---|
| 1934 | , HOTSPOT_JNI_CALLSTATICCHARMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1935 | HOTSPOT_JNI_CALLSTATICCHARMETHODA_RETURN(_ret_ref)); | 
|---|
| 1936 | DEFINE_CALLSTATICMETHODA(jshort,   Short,   T_SHORT | 
|---|
| 1937 | , HOTSPOT_JNI_CALLSTATICSHORTMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1938 | HOTSPOT_JNI_CALLSTATICSHORTMETHODA_RETURN(_ret_ref)); | 
|---|
| 1939 |  | 
|---|
| 1940 | DEFINE_CALLSTATICMETHODA(jobject,  Object,  T_OBJECT | 
|---|
| 1941 | , HOTSPOT_JNI_CALLSTATICOBJECTMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1942 | HOTSPOT_JNI_CALLSTATICOBJECTMETHODA_RETURN(_ret_ref)); | 
|---|
| 1943 | DEFINE_CALLSTATICMETHODA(jint,     Int,     T_INT | 
|---|
| 1944 | , HOTSPOT_JNI_CALLSTATICINTMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1945 | HOTSPOT_JNI_CALLSTATICINTMETHODA_RETURN(_ret_ref)); | 
|---|
| 1946 | DEFINE_CALLSTATICMETHODA(jlong,    Long,    T_LONG | 
|---|
| 1947 | , HOTSPOT_JNI_CALLSTATICLONGMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1948 | HOTSPOT_JNI_CALLSTATICLONGMETHODA_RETURN(_ret_ref)); | 
|---|
| 1949 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 1950 | DEFINE_CALLSTATICMETHODA(jfloat,   Float,   T_FLOAT | 
|---|
| 1951 | , HOTSPOT_JNI_CALLSTATICFLOATMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1952 | HOTSPOT_JNI_CALLSTATICFLOATMETHODA_RETURN()); | 
|---|
| 1953 | DEFINE_CALLSTATICMETHODA(jdouble,  Double,  T_DOUBLE | 
|---|
| 1954 | , HOTSPOT_JNI_CALLSTATICDOUBLEMETHODA_ENTRY(env, cls, (uintptr_t)methodID), | 
|---|
| 1955 | HOTSPOT_JNI_CALLSTATICDOUBLEMETHODA_RETURN()); | 
|---|
| 1956 |  | 
|---|
| 1957 | DT_VOID_RETURN_MARK_DECL(CallStaticVoidMethod | 
|---|
| 1958 | , HOTSPOT_JNI_CALLSTATICVOIDMETHOD_RETURN()); | 
|---|
| 1959 | DT_VOID_RETURN_MARK_DECL(CallStaticVoidMethodV | 
|---|
| 1960 | , HOTSPOT_JNI_CALLSTATICVOIDMETHODV_RETURN()); | 
|---|
| 1961 | DT_VOID_RETURN_MARK_DECL(CallStaticVoidMethodA | 
|---|
| 1962 | , HOTSPOT_JNI_CALLSTATICVOIDMETHODA_RETURN()); | 
|---|
| 1963 |  | 
|---|
| 1964 | JNI_ENTRY(void, jni_CallStaticVoidMethod(JNIEnv *env, jclass cls, jmethodID methodID, ...)) | 
|---|
| 1965 | JNIWrapper( "CallStaticVoidMethod"); | 
|---|
| 1966 | HOTSPOT_JNI_CALLSTATICVOIDMETHOD_ENTRY(env, cls, (uintptr_t) methodID); | 
|---|
| 1967 | DT_VOID_RETURN_MARK(CallStaticVoidMethod); | 
|---|
| 1968 |  | 
|---|
| 1969 | va_list args; | 
|---|
| 1970 | va_start(args, methodID); | 
|---|
| 1971 | JavaValue jvalue(T_VOID); | 
|---|
| 1972 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1973 | jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK); | 
|---|
| 1974 | va_end(args); | 
|---|
| 1975 | JNI_END | 
|---|
| 1976 |  | 
|---|
| 1977 |  | 
|---|
| 1978 | JNI_ENTRY(void, jni_CallStaticVoidMethodV(JNIEnv *env, jclass cls, jmethodID methodID, va_list args)) | 
|---|
| 1979 | JNIWrapper( "CallStaticVoidMethodV"); | 
|---|
| 1980 | HOTSPOT_JNI_CALLSTATICVOIDMETHODV_ENTRY(env, cls, (uintptr_t) methodID); | 
|---|
| 1981 | DT_VOID_RETURN_MARK(CallStaticVoidMethodV); | 
|---|
| 1982 |  | 
|---|
| 1983 | JavaValue jvalue(T_VOID); | 
|---|
| 1984 | JNI_ArgumentPusherVaArg ap(methodID, args); | 
|---|
| 1985 | jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK); | 
|---|
| 1986 | JNI_END | 
|---|
| 1987 |  | 
|---|
| 1988 |  | 
|---|
| 1989 | JNI_ENTRY(void, jni_CallStaticVoidMethodA(JNIEnv *env, jclass cls, jmethodID methodID, const jvalue *args)) | 
|---|
| 1990 | JNIWrapper( "CallStaticVoidMethodA"); | 
|---|
| 1991 | HOTSPOT_JNI_CALLSTATICVOIDMETHODA_ENTRY(env, cls, (uintptr_t) methodID); | 
|---|
| 1992 | DT_VOID_RETURN_MARK(CallStaticVoidMethodA); | 
|---|
| 1993 |  | 
|---|
| 1994 | JavaValue jvalue(T_VOID); | 
|---|
| 1995 | JNI_ArgumentPusherArray ap(methodID, args); | 
|---|
| 1996 | jni_invoke_static(env, &jvalue, NULL, JNI_STATIC, methodID, &ap, CHECK); | 
|---|
| 1997 | JNI_END | 
|---|
| 1998 |  | 
|---|
| 1999 |  | 
|---|
| 2000 | // | 
|---|
| 2001 | // Accessing Fields | 
|---|
| 2002 | // | 
|---|
| 2003 |  | 
|---|
| 2004 |  | 
|---|
| 2005 | DT_RETURN_MARK_DECL(GetFieldID, jfieldID | 
|---|
| 2006 | , HOTSPOT_JNI_GETFIELDID_RETURN((uintptr_t)_ret_ref)); | 
|---|
| 2007 |  | 
|---|
| 2008 | JNI_ENTRY(jfieldID, jni_GetFieldID(JNIEnv *env, jclass clazz, | 
|---|
| 2009 | const char *name, const char *sig)) | 
|---|
| 2010 | JNIWrapper( "GetFieldID"); | 
|---|
| 2011 | HOTSPOT_JNI_GETFIELDID_ENTRY(env, clazz, (char *) name, (char *) sig); | 
|---|
| 2012 | jfieldID ret = 0; | 
|---|
| 2013 | DT_RETURN_MARK(GetFieldID, jfieldID, (const jfieldID&)ret); | 
|---|
| 2014 |  | 
|---|
| 2015 | Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); | 
|---|
| 2016 |  | 
|---|
| 2017 | // The class should have been loaded (we have an instance of the class | 
|---|
| 2018 | // passed in) so the field and signature should already be in the symbol | 
|---|
| 2019 | // table.  If they're not there, the field doesn't exist. | 
|---|
| 2020 | TempNewSymbol fieldname = SymbolTable::probe(name, (int)strlen(name)); | 
|---|
| 2021 | TempNewSymbol signame = SymbolTable::probe(sig, (int)strlen(sig)); | 
|---|
| 2022 | if (fieldname == NULL || signame == NULL) { | 
|---|
| 2023 | ResourceMark rm; | 
|---|
| 2024 | THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), err_msg( "%s.%s %s", k->external_name(), name, sig)); | 
|---|
| 2025 | } | 
|---|
| 2026 |  | 
|---|
| 2027 | // Make sure class is initialized before handing id's out to fields | 
|---|
| 2028 | k->initialize(CHECK_NULL); | 
|---|
| 2029 |  | 
|---|
| 2030 | fieldDescriptor fd; | 
|---|
| 2031 | if (!k->is_instance_klass() || | 
|---|
| 2032 | !InstanceKlass::cast(k)->find_field(fieldname, signame, false, &fd)) { | 
|---|
| 2033 | ResourceMark rm; | 
|---|
| 2034 | THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), err_msg( "%s.%s %s", k->external_name(), name, sig)); | 
|---|
| 2035 | } | 
|---|
| 2036 |  | 
|---|
| 2037 | // A jfieldID for a non-static field is simply the offset of the field within the instanceOop | 
|---|
| 2038 | // It may also have hash bits for k, if VerifyJNIFields is turned on. | 
|---|
| 2039 | ret = jfieldIDWorkaround::to_instance_jfieldID(k, fd.offset()); | 
|---|
| 2040 | return ret; | 
|---|
| 2041 | JNI_END | 
|---|
| 2042 |  | 
|---|
| 2043 |  | 
|---|
| 2044 | JNI_ENTRY(jobject, jni_GetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID)) | 
|---|
| 2045 | JNIWrapper( "GetObjectField"); | 
|---|
| 2046 | HOTSPOT_JNI_GETOBJECTFIELD_ENTRY(env, obj, (uintptr_t) fieldID); | 
|---|
| 2047 | oop o = JNIHandles::resolve_non_null(obj); | 
|---|
| 2048 | Klass* k = o->klass(); | 
|---|
| 2049 | int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); | 
|---|
| 2050 | // Keep JVMTI addition small and only check enabled flag here. | 
|---|
| 2051 | // jni_GetField_probe() assumes that is okay to create handles. | 
|---|
| 2052 | if (JvmtiExport::should_post_field_access()) { | 
|---|
| 2053 | o = JvmtiExport::jni_GetField_probe(thread, obj, o, k, fieldID, false); | 
|---|
| 2054 | } | 
|---|
| 2055 | oop loaded_obj = HeapAccess<ON_UNKNOWN_OOP_REF>::oop_load_at(o, offset); | 
|---|
| 2056 | jobject ret = JNIHandles::make_local(env, loaded_obj); | 
|---|
| 2057 | HOTSPOT_JNI_GETOBJECTFIELD_RETURN(ret); | 
|---|
| 2058 | return ret; | 
|---|
| 2059 | JNI_END | 
|---|
| 2060 |  | 
|---|
| 2061 |  | 
|---|
| 2062 |  | 
|---|
| 2063 | #define DEFINE_GETFIELD(Return,Fieldname,Result \ | 
|---|
| 2064 | , EntryProbe, ReturnProbe) \ | 
|---|
| 2065 | \ | 
|---|
| 2066 | DT_RETURN_MARK_DECL_FOR(Result, Get##Result##Field, Return \ | 
|---|
| 2067 | , ReturnProbe); \ | 
|---|
| 2068 | \ | 
|---|
| 2069 | JNI_QUICK_ENTRY(Return, jni_Get##Result##Field(JNIEnv *env, jobject obj, jfieldID fieldID)) \ | 
|---|
| 2070 | JNIWrapper("Get" XSTR(Result) "Field"); \ | 
|---|
| 2071 | \ | 
|---|
| 2072 | EntryProbe; \ | 
|---|
| 2073 | Return ret = 0;\ | 
|---|
| 2074 | DT_RETURN_MARK_FOR(Result, Get##Result##Field, Return, (const Return&)ret);\ | 
|---|
| 2075 | \ | 
|---|
| 2076 | oop o = JNIHandles::resolve_non_null(obj); \ | 
|---|
| 2077 | Klass* k = o->klass(); \ | 
|---|
| 2078 | int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID);  \ | 
|---|
| 2079 | /* Keep JVMTI addition small and only check enabled flag here.       */ \ | 
|---|
| 2080 | /* jni_GetField_probe_nh() assumes that is not okay to create handles */ \ | 
|---|
| 2081 | /* and creates a ResetNoHandleMark.                                   */ \ | 
|---|
| 2082 | if (JvmtiExport::should_post_field_access()) { \ | 
|---|
| 2083 | o = JvmtiExport::jni_GetField_probe_nh(thread, obj, o, k, fieldID, false); \ | 
|---|
| 2084 | } \ | 
|---|
| 2085 | ret = o->Fieldname##_field(offset); \ | 
|---|
| 2086 | return ret; \ | 
|---|
| 2087 | JNI_END | 
|---|
| 2088 |  | 
|---|
| 2089 | DEFINE_GETFIELD(jboolean, bool,   Boolean | 
|---|
| 2090 | , HOTSPOT_JNI_GETBOOLEANFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2091 | HOTSPOT_JNI_GETBOOLEANFIELD_RETURN(_ret_ref)) | 
|---|
| 2092 | DEFINE_GETFIELD(jbyte,    byte,   Byte | 
|---|
| 2093 | , HOTSPOT_JNI_GETBYTEFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2094 | HOTSPOT_JNI_GETBYTEFIELD_RETURN(_ret_ref)) | 
|---|
| 2095 | DEFINE_GETFIELD(jchar,    char,   Char | 
|---|
| 2096 | , HOTSPOT_JNI_GETCHARFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2097 | HOTSPOT_JNI_GETCHARFIELD_RETURN(_ret_ref)) | 
|---|
| 2098 | DEFINE_GETFIELD(jshort,   short,  Short | 
|---|
| 2099 | , HOTSPOT_JNI_GETSHORTFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2100 | HOTSPOT_JNI_GETSHORTFIELD_RETURN(_ret_ref)) | 
|---|
| 2101 | DEFINE_GETFIELD(jint,     int,    Int | 
|---|
| 2102 | , HOTSPOT_JNI_GETINTFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2103 | HOTSPOT_JNI_GETINTFIELD_RETURN(_ret_ref)) | 
|---|
| 2104 | DEFINE_GETFIELD(jlong,    long,   Long | 
|---|
| 2105 | , HOTSPOT_JNI_GETLONGFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2106 | HOTSPOT_JNI_GETLONGFIELD_RETURN(_ret_ref)) | 
|---|
| 2107 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 2108 | DEFINE_GETFIELD(jfloat,   float,  Float | 
|---|
| 2109 | , HOTSPOT_JNI_GETFLOATFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2110 | HOTSPOT_JNI_GETFLOATFIELD_RETURN()) | 
|---|
| 2111 | DEFINE_GETFIELD(jdouble,  double, Double | 
|---|
| 2112 | , HOTSPOT_JNI_GETDOUBLEFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2113 | HOTSPOT_JNI_GETDOUBLEFIELD_RETURN()) | 
|---|
| 2114 |  | 
|---|
| 2115 | address jni_GetBooleanField_addr() { | 
|---|
| 2116 | return (address)jni_GetBooleanField; | 
|---|
| 2117 | } | 
|---|
| 2118 | address jni_GetByteField_addr() { | 
|---|
| 2119 | return (address)jni_GetByteField; | 
|---|
| 2120 | } | 
|---|
| 2121 | address jni_GetCharField_addr() { | 
|---|
| 2122 | return (address)jni_GetCharField; | 
|---|
| 2123 | } | 
|---|
| 2124 | address jni_GetShortField_addr() { | 
|---|
| 2125 | return (address)jni_GetShortField; | 
|---|
| 2126 | } | 
|---|
| 2127 | address jni_GetIntField_addr() { | 
|---|
| 2128 | return (address)jni_GetIntField; | 
|---|
| 2129 | } | 
|---|
| 2130 | address jni_GetLongField_addr() { | 
|---|
| 2131 | return (address)jni_GetLongField; | 
|---|
| 2132 | } | 
|---|
| 2133 | address jni_GetFloatField_addr() { | 
|---|
| 2134 | return (address)jni_GetFloatField; | 
|---|
| 2135 | } | 
|---|
| 2136 | address jni_GetDoubleField_addr() { | 
|---|
| 2137 | return (address)jni_GetDoubleField; | 
|---|
| 2138 | } | 
|---|
| 2139 |  | 
|---|
| 2140 | JNI_QUICK_ENTRY(void, jni_SetObjectField(JNIEnv *env, jobject obj, jfieldID fieldID, jobject value)) | 
|---|
| 2141 | JNIWrapper( "SetObjectField"); | 
|---|
| 2142 | HOTSPOT_JNI_SETOBJECTFIELD_ENTRY(env, obj, (uintptr_t) fieldID, value); | 
|---|
| 2143 | oop o = JNIHandles::resolve_non_null(obj); | 
|---|
| 2144 | Klass* k = o->klass(); | 
|---|
| 2145 | int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); | 
|---|
| 2146 | // Keep JVMTI addition small and only check enabled flag here. | 
|---|
| 2147 | // jni_SetField_probe_nh() assumes that is not okay to create handles | 
|---|
| 2148 | // and creates a ResetNoHandleMark. | 
|---|
| 2149 | if (JvmtiExport::should_post_field_modification()) { | 
|---|
| 2150 | jvalue field_value; | 
|---|
| 2151 | field_value.l = value; | 
|---|
| 2152 | o = JvmtiExport::jni_SetField_probe_nh(thread, obj, o, k, fieldID, false, 'L', (jvalue *)&field_value); | 
|---|
| 2153 | } | 
|---|
| 2154 | HeapAccess<ON_UNKNOWN_OOP_REF>::oop_store_at(o, offset, JNIHandles::resolve(value)); | 
|---|
| 2155 | HOTSPOT_JNI_SETOBJECTFIELD_RETURN(); | 
|---|
| 2156 | JNI_END | 
|---|
| 2157 |  | 
|---|
| 2158 |  | 
|---|
| 2159 | #define DEFINE_SETFIELD(Argument,Fieldname,Result,SigType,unionType \ | 
|---|
| 2160 | , EntryProbe, ReturnProbe) \ | 
|---|
| 2161 | \ | 
|---|
| 2162 | JNI_QUICK_ENTRY(void, jni_Set##Result##Field(JNIEnv *env, jobject obj, jfieldID fieldID, Argument value)) \ | 
|---|
| 2163 | JNIWrapper("Set" XSTR(Result) "Field"); \ | 
|---|
| 2164 | \ | 
|---|
| 2165 | EntryProbe; \ | 
|---|
| 2166 | \ | 
|---|
| 2167 | oop o = JNIHandles::resolve_non_null(obj); \ | 
|---|
| 2168 | Klass* k = o->klass(); \ | 
|---|
| 2169 | int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID);  \ | 
|---|
| 2170 | /* Keep JVMTI addition small and only check enabled flag here.       */ \ | 
|---|
| 2171 | /* jni_SetField_probe_nh() assumes that is not okay to create handles */ \ | 
|---|
| 2172 | /* and creates a ResetNoHandleMark.                                   */ \ | 
|---|
| 2173 | if (JvmtiExport::should_post_field_modification()) { \ | 
|---|
| 2174 | jvalue field_value; \ | 
|---|
| 2175 | field_value.unionType = value; \ | 
|---|
| 2176 | o = JvmtiExport::jni_SetField_probe_nh(thread, obj, o, k, fieldID, false, SigType, (jvalue *)&field_value); \ | 
|---|
| 2177 | } \ | 
|---|
| 2178 | if (SigType == 'Z') { value = ((jboolean)value) & 1; } \ | 
|---|
| 2179 | o->Fieldname##_field_put(offset, value); \ | 
|---|
| 2180 | ReturnProbe; \ | 
|---|
| 2181 | JNI_END | 
|---|
| 2182 |  | 
|---|
| 2183 | DEFINE_SETFIELD(jboolean, bool,   Boolean, 'Z', z | 
|---|
| 2184 | , HOTSPOT_JNI_SETBOOLEANFIELD_ENTRY(env, obj, (uintptr_t)fieldID, value), | 
|---|
| 2185 | HOTSPOT_JNI_SETBOOLEANFIELD_RETURN()) | 
|---|
| 2186 | DEFINE_SETFIELD(jbyte,    byte,   Byte,    'B', b | 
|---|
| 2187 | , HOTSPOT_JNI_SETBYTEFIELD_ENTRY(env, obj, (uintptr_t)fieldID, value), | 
|---|
| 2188 | HOTSPOT_JNI_SETBYTEFIELD_RETURN()) | 
|---|
| 2189 | DEFINE_SETFIELD(jchar,    char,   Char,    'C', c | 
|---|
| 2190 | , HOTSPOT_JNI_SETCHARFIELD_ENTRY(env, obj, (uintptr_t)fieldID, value), | 
|---|
| 2191 | HOTSPOT_JNI_SETCHARFIELD_RETURN()) | 
|---|
| 2192 | DEFINE_SETFIELD(jshort,   short,  Short,   'S', s | 
|---|
| 2193 | , HOTSPOT_JNI_SETSHORTFIELD_ENTRY(env, obj, (uintptr_t)fieldID, value), | 
|---|
| 2194 | HOTSPOT_JNI_SETSHORTFIELD_RETURN()) | 
|---|
| 2195 | DEFINE_SETFIELD(jint,     int,    Int,     'I', i | 
|---|
| 2196 | , HOTSPOT_JNI_SETINTFIELD_ENTRY(env, obj, (uintptr_t)fieldID, value), | 
|---|
| 2197 | HOTSPOT_JNI_SETINTFIELD_RETURN()) | 
|---|
| 2198 | DEFINE_SETFIELD(jlong,    long,   Long,    'J', j | 
|---|
| 2199 | , HOTSPOT_JNI_SETLONGFIELD_ENTRY(env, obj, (uintptr_t)fieldID, value), | 
|---|
| 2200 | HOTSPOT_JNI_SETLONGFIELD_RETURN()) | 
|---|
| 2201 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 2202 | DEFINE_SETFIELD(jfloat,   float,  Float,   'F', f | 
|---|
| 2203 | , HOTSPOT_JNI_SETFLOATFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2204 | HOTSPOT_JNI_SETFLOATFIELD_RETURN()) | 
|---|
| 2205 | DEFINE_SETFIELD(jdouble,  double, Double,  'D', d | 
|---|
| 2206 | , HOTSPOT_JNI_SETDOUBLEFIELD_ENTRY(env, obj, (uintptr_t)fieldID), | 
|---|
| 2207 | HOTSPOT_JNI_SETDOUBLEFIELD_RETURN()) | 
|---|
| 2208 |  | 
|---|
| 2209 | DT_RETURN_MARK_DECL(ToReflectedField, jobject | 
|---|
| 2210 | , HOTSPOT_JNI_TOREFLECTEDFIELD_RETURN(_ret_ref)); | 
|---|
| 2211 |  | 
|---|
| 2212 | JNI_ENTRY(jobject, jni_ToReflectedField(JNIEnv *env, jclass cls, jfieldID fieldID, jboolean isStatic)) | 
|---|
| 2213 | JNIWrapper( "ToReflectedField"); | 
|---|
| 2214 | HOTSPOT_JNI_TOREFLECTEDFIELD_ENTRY(env, cls, (uintptr_t) fieldID, isStatic); | 
|---|
| 2215 | jobject ret = NULL; | 
|---|
| 2216 | DT_RETURN_MARK(ToReflectedField, jobject, (const jobject&)ret); | 
|---|
| 2217 |  | 
|---|
| 2218 | fieldDescriptor fd; | 
|---|
| 2219 | bool found = false; | 
|---|
| 2220 | Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(cls)); | 
|---|
| 2221 |  | 
|---|
| 2222 | assert(jfieldIDWorkaround::is_static_jfieldID(fieldID) == (isStatic != 0), "invalid fieldID"); | 
|---|
| 2223 |  | 
|---|
| 2224 | if (isStatic) { | 
|---|
| 2225 | // Static field. The fieldID a JNIid specifying the field holder and the offset within the Klass*. | 
|---|
| 2226 | JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); | 
|---|
| 2227 | assert(id->is_static_field_id(), "invalid static field id"); | 
|---|
| 2228 | found = id->find_local_field(&fd); | 
|---|
| 2229 | } else { | 
|---|
| 2230 | // Non-static field. The fieldID is really the offset of the field within the instanceOop. | 
|---|
| 2231 | int offset = jfieldIDWorkaround::from_instance_jfieldID(k, fieldID); | 
|---|
| 2232 | found = InstanceKlass::cast(k)->find_field_from_offset(offset, false, &fd); | 
|---|
| 2233 | } | 
|---|
| 2234 | assert(found, "bad fieldID passed into jni_ToReflectedField"); | 
|---|
| 2235 | oop reflected = Reflection::new_field(&fd, CHECK_NULL); | 
|---|
| 2236 | ret = JNIHandles::make_local(env, reflected); | 
|---|
| 2237 | return ret; | 
|---|
| 2238 | JNI_END | 
|---|
| 2239 |  | 
|---|
| 2240 |  | 
|---|
| 2241 | // | 
|---|
| 2242 | // Accessing Static Fields | 
|---|
| 2243 | // | 
|---|
| 2244 | DT_RETURN_MARK_DECL(GetStaticFieldID, jfieldID | 
|---|
| 2245 | , HOTSPOT_JNI_GETSTATICFIELDID_RETURN((uintptr_t)_ret_ref)); | 
|---|
| 2246 |  | 
|---|
| 2247 | JNI_ENTRY(jfieldID, jni_GetStaticFieldID(JNIEnv *env, jclass clazz, | 
|---|
| 2248 | const char *name, const char *sig)) | 
|---|
| 2249 | JNIWrapper( "GetStaticFieldID"); | 
|---|
| 2250 | HOTSPOT_JNI_GETSTATICFIELDID_ENTRY(env, clazz, (char *) name, (char *) sig); | 
|---|
| 2251 | jfieldID ret = NULL; | 
|---|
| 2252 | DT_RETURN_MARK(GetStaticFieldID, jfieldID, (const jfieldID&)ret); | 
|---|
| 2253 |  | 
|---|
| 2254 | // The class should have been loaded (we have an instance of the class | 
|---|
| 2255 | // passed in) so the field and signature should already be in the symbol | 
|---|
| 2256 | // table.  If they're not there, the field doesn't exist. | 
|---|
| 2257 | TempNewSymbol fieldname = SymbolTable::probe(name, (int)strlen(name)); | 
|---|
| 2258 | TempNewSymbol signame = SymbolTable::probe(sig, (int)strlen(sig)); | 
|---|
| 2259 | if (fieldname == NULL || signame == NULL) { | 
|---|
| 2260 | THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); | 
|---|
| 2261 | } | 
|---|
| 2262 | Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); | 
|---|
| 2263 | // Make sure class is initialized before handing id's out to static fields | 
|---|
| 2264 | k->initialize(CHECK_NULL); | 
|---|
| 2265 |  | 
|---|
| 2266 | fieldDescriptor fd; | 
|---|
| 2267 | if (!k->is_instance_klass() || | 
|---|
| 2268 | !InstanceKlass::cast(k)->find_field(fieldname, signame, true, &fd)) { | 
|---|
| 2269 | THROW_MSG_0(vmSymbols::java_lang_NoSuchFieldError(), (char*) name); | 
|---|
| 2270 | } | 
|---|
| 2271 |  | 
|---|
| 2272 | // A jfieldID for a static field is a JNIid specifying the field holder and the offset within the Klass* | 
|---|
| 2273 | JNIid* id = fd.field_holder()->jni_id_for(fd.offset()); | 
|---|
| 2274 | debug_only(id->set_is_static_field_id();) | 
|---|
| 2275 |  | 
|---|
| 2276 | debug_only(id->verify(fd.field_holder())); | 
|---|
| 2277 |  | 
|---|
| 2278 | ret = jfieldIDWorkaround::to_static_jfieldID(id); | 
|---|
| 2279 | return ret; | 
|---|
| 2280 | JNI_END | 
|---|
| 2281 |  | 
|---|
| 2282 |  | 
|---|
| 2283 | JNI_ENTRY(jobject, jni_GetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID)) | 
|---|
| 2284 | JNIWrapper( "GetStaticObjectField"); | 
|---|
| 2285 | HOTSPOT_JNI_GETSTATICOBJECTFIELD_ENTRY(env, clazz, (uintptr_t) fieldID); | 
|---|
| 2286 | #if INCLUDE_JNI_CHECK | 
|---|
| 2287 | DEBUG_ONLY(Klass* param_k = jniCheck::validate_class(thread, clazz);) | 
|---|
| 2288 | #endif // INCLUDE_JNI_CHECK | 
|---|
| 2289 | JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); | 
|---|
| 2290 | assert(id->is_static_field_id(), "invalid static field id"); | 
|---|
| 2291 | // Keep JVMTI addition small and only check enabled flag here. | 
|---|
| 2292 | // jni_GetField_probe() assumes that is okay to create handles. | 
|---|
| 2293 | if (JvmtiExport::should_post_field_access()) { | 
|---|
| 2294 | JvmtiExport::jni_GetField_probe(thread, NULL, NULL, id->holder(), fieldID, true); | 
|---|
| 2295 | } | 
|---|
| 2296 | jobject ret = JNIHandles::make_local(id->holder()->java_mirror()->obj_field(id->offset())); | 
|---|
| 2297 | HOTSPOT_JNI_GETSTATICOBJECTFIELD_RETURN(ret); | 
|---|
| 2298 | return ret; | 
|---|
| 2299 | JNI_END | 
|---|
| 2300 |  | 
|---|
| 2301 |  | 
|---|
| 2302 | #define DEFINE_GETSTATICFIELD(Return,Fieldname,Result \ | 
|---|
| 2303 | , EntryProbe, ReturnProbe) \ | 
|---|
| 2304 | \ | 
|---|
| 2305 | DT_RETURN_MARK_DECL_FOR(Result, GetStatic##Result##Field, Return \ | 
|---|
| 2306 | , ReturnProbe);                                          \ | 
|---|
| 2307 | \ | 
|---|
| 2308 | JNI_ENTRY(Return, jni_GetStatic##Result##Field(JNIEnv *env, jclass clazz, jfieldID fieldID)) \ | 
|---|
| 2309 | JNIWrapper("GetStatic" XSTR(Result) "Field"); \ | 
|---|
| 2310 | EntryProbe; \ | 
|---|
| 2311 | Return ret = 0;\ | 
|---|
| 2312 | DT_RETURN_MARK_FOR(Result, GetStatic##Result##Field, Return, \ | 
|---|
| 2313 | (const Return&)ret);\ | 
|---|
| 2314 | JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); \ | 
|---|
| 2315 | assert(id->is_static_field_id(), "invalid static field id"); \ | 
|---|
| 2316 | /* Keep JVMTI addition small and only check enabled flag here. */ \ | 
|---|
| 2317 | /* jni_GetField_probe() assumes that is okay to create handles. */ \ | 
|---|
| 2318 | if (JvmtiExport::should_post_field_access()) { \ | 
|---|
| 2319 | JvmtiExport::jni_GetField_probe(thread, NULL, NULL, id->holder(), fieldID, true); \ | 
|---|
| 2320 | } \ | 
|---|
| 2321 | ret = id->holder()->java_mirror()-> Fieldname##_field (id->offset()); \ | 
|---|
| 2322 | return ret;\ | 
|---|
| 2323 | JNI_END | 
|---|
| 2324 |  | 
|---|
| 2325 | DEFINE_GETSTATICFIELD(jboolean, bool,   Boolean | 
|---|
| 2326 | , HOTSPOT_JNI_GETSTATICBOOLEANFIELD_ENTRY(env, clazz, (uintptr_t) fieldID), HOTSPOT_JNI_GETSTATICBOOLEANFIELD_RETURN(_ret_ref)) | 
|---|
| 2327 | DEFINE_GETSTATICFIELD(jbyte,    byte,   Byte | 
|---|
| 2328 | , HOTSPOT_JNI_GETSTATICBYTEFIELD_ENTRY(env, clazz, (uintptr_t) fieldID),    HOTSPOT_JNI_GETSTATICBYTEFIELD_RETURN(_ret_ref)   ) | 
|---|
| 2329 | DEFINE_GETSTATICFIELD(jchar,    char,   Char | 
|---|
| 2330 | , HOTSPOT_JNI_GETSTATICCHARFIELD_ENTRY(env, clazz, (uintptr_t) fieldID),    HOTSPOT_JNI_GETSTATICCHARFIELD_RETURN(_ret_ref)   ) | 
|---|
| 2331 | DEFINE_GETSTATICFIELD(jshort,   short,  Short | 
|---|
| 2332 | , HOTSPOT_JNI_GETSTATICSHORTFIELD_ENTRY(env, clazz, (uintptr_t) fieldID),   HOTSPOT_JNI_GETSTATICSHORTFIELD_RETURN(_ret_ref)  ) | 
|---|
| 2333 | DEFINE_GETSTATICFIELD(jint,     int,    Int | 
|---|
| 2334 | , HOTSPOT_JNI_GETSTATICINTFIELD_ENTRY(env, clazz, (uintptr_t) fieldID),     HOTSPOT_JNI_GETSTATICINTFIELD_RETURN(_ret_ref)    ) | 
|---|
| 2335 | DEFINE_GETSTATICFIELD(jlong,    long,   Long | 
|---|
| 2336 | , HOTSPOT_JNI_GETSTATICLONGFIELD_ENTRY(env, clazz, (uintptr_t) fieldID),    HOTSPOT_JNI_GETSTATICLONGFIELD_RETURN(_ret_ref)   ) | 
|---|
| 2337 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 2338 | DEFINE_GETSTATICFIELD(jfloat,   float,  Float | 
|---|
| 2339 | , HOTSPOT_JNI_GETSTATICFLOATFIELD_ENTRY(env, clazz, (uintptr_t) fieldID),   HOTSPOT_JNI_GETSTATICFLOATFIELD_RETURN()          ) | 
|---|
| 2340 | DEFINE_GETSTATICFIELD(jdouble,  double, Double | 
|---|
| 2341 | , HOTSPOT_JNI_GETSTATICDOUBLEFIELD_ENTRY(env, clazz, (uintptr_t) fieldID),  HOTSPOT_JNI_GETSTATICDOUBLEFIELD_RETURN()         ) | 
|---|
| 2342 |  | 
|---|
| 2343 | JNI_ENTRY(void, jni_SetStaticObjectField(JNIEnv *env, jclass clazz, jfieldID fieldID, jobject value)) | 
|---|
| 2344 | JNIWrapper( "SetStaticObjectField"); | 
|---|
| 2345 | HOTSPOT_JNI_SETSTATICOBJECTFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value); | 
|---|
| 2346 | JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); | 
|---|
| 2347 | assert(id->is_static_field_id(), "invalid static field id"); | 
|---|
| 2348 | // Keep JVMTI addition small and only check enabled flag here. | 
|---|
| 2349 | // jni_SetField_probe() assumes that is okay to create handles. | 
|---|
| 2350 | if (JvmtiExport::should_post_field_modification()) { | 
|---|
| 2351 | jvalue field_value; | 
|---|
| 2352 | field_value.l = value; | 
|---|
| 2353 | JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, 'L', (jvalue *)&field_value); | 
|---|
| 2354 | } | 
|---|
| 2355 | id->holder()->java_mirror()->obj_field_put(id->offset(), JNIHandles::resolve(value)); | 
|---|
| 2356 | HOTSPOT_JNI_SETSTATICOBJECTFIELD_RETURN(); | 
|---|
| 2357 | JNI_END | 
|---|
| 2358 |  | 
|---|
| 2359 |  | 
|---|
| 2360 |  | 
|---|
| 2361 | #define DEFINE_SETSTATICFIELD(Argument,Fieldname,Result,SigType,unionType \ | 
|---|
| 2362 | , EntryProbe, ReturnProbe) \ | 
|---|
| 2363 | \ | 
|---|
| 2364 | JNI_ENTRY(void, jni_SetStatic##Result##Field(JNIEnv *env, jclass clazz, jfieldID fieldID, Argument value)) \ | 
|---|
| 2365 | JNIWrapper("SetStatic" XSTR(Result) "Field"); \ | 
|---|
| 2366 | EntryProbe; \ | 
|---|
| 2367 | \ | 
|---|
| 2368 | JNIid* id = jfieldIDWorkaround::from_static_jfieldID(fieldID); \ | 
|---|
| 2369 | assert(id->is_static_field_id(), "invalid static field id"); \ | 
|---|
| 2370 | /* Keep JVMTI addition small and only check enabled flag here. */ \ | 
|---|
| 2371 | /* jni_SetField_probe() assumes that is okay to create handles. */ \ | 
|---|
| 2372 | if (JvmtiExport::should_post_field_modification()) { \ | 
|---|
| 2373 | jvalue field_value; \ | 
|---|
| 2374 | field_value.unionType = value; \ | 
|---|
| 2375 | JvmtiExport::jni_SetField_probe(thread, NULL, NULL, id->holder(), fieldID, true, SigType, (jvalue *)&field_value); \ | 
|---|
| 2376 | } \ | 
|---|
| 2377 | if (SigType == 'Z') { value = ((jboolean)value) & 1; } \ | 
|---|
| 2378 | id->holder()->java_mirror()-> Fieldname##_field_put (id->offset(), value); \ | 
|---|
| 2379 | ReturnProbe;\ | 
|---|
| 2380 | JNI_END | 
|---|
| 2381 |  | 
|---|
| 2382 | DEFINE_SETSTATICFIELD(jboolean, bool,   Boolean, 'Z', z | 
|---|
| 2383 | , HOTSPOT_JNI_SETSTATICBOOLEANFIELD_ENTRY(env, clazz, (uintptr_t)fieldID, value), | 
|---|
| 2384 | HOTSPOT_JNI_SETSTATICBOOLEANFIELD_RETURN()) | 
|---|
| 2385 | DEFINE_SETSTATICFIELD(jbyte,    byte,   Byte,    'B', b | 
|---|
| 2386 | , HOTSPOT_JNI_SETSTATICBYTEFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value), | 
|---|
| 2387 | HOTSPOT_JNI_SETSTATICBYTEFIELD_RETURN()) | 
|---|
| 2388 | DEFINE_SETSTATICFIELD(jchar,    char,   Char,    'C', c | 
|---|
| 2389 | , HOTSPOT_JNI_SETSTATICCHARFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value), | 
|---|
| 2390 | HOTSPOT_JNI_SETSTATICCHARFIELD_RETURN()) | 
|---|
| 2391 | DEFINE_SETSTATICFIELD(jshort,   short,  Short,   'S', s | 
|---|
| 2392 | , HOTSPOT_JNI_SETSTATICSHORTFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value), | 
|---|
| 2393 | HOTSPOT_JNI_SETSTATICSHORTFIELD_RETURN()) | 
|---|
| 2394 | DEFINE_SETSTATICFIELD(jint,     int,    Int,     'I', i | 
|---|
| 2395 | , HOTSPOT_JNI_SETSTATICINTFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value), | 
|---|
| 2396 | HOTSPOT_JNI_SETSTATICINTFIELD_RETURN()) | 
|---|
| 2397 | DEFINE_SETSTATICFIELD(jlong,    long,   Long,    'J', j | 
|---|
| 2398 | , HOTSPOT_JNI_SETSTATICLONGFIELD_ENTRY(env, clazz, (uintptr_t) fieldID, value), | 
|---|
| 2399 | HOTSPOT_JNI_SETSTATICLONGFIELD_RETURN()) | 
|---|
| 2400 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 2401 | DEFINE_SETSTATICFIELD(jfloat,   float,  Float,   'F', f | 
|---|
| 2402 | , HOTSPOT_JNI_SETSTATICFLOATFIELD_ENTRY(env, clazz, (uintptr_t) fieldID), | 
|---|
| 2403 | HOTSPOT_JNI_SETSTATICFLOATFIELD_RETURN()) | 
|---|
| 2404 | DEFINE_SETSTATICFIELD(jdouble,  double, Double,  'D', d | 
|---|
| 2405 | , HOTSPOT_JNI_SETSTATICDOUBLEFIELD_ENTRY(env, clazz, (uintptr_t) fieldID), | 
|---|
| 2406 | HOTSPOT_JNI_SETSTATICDOUBLEFIELD_RETURN()) | 
|---|
| 2407 |  | 
|---|
| 2408 | // | 
|---|
| 2409 | // String Operations | 
|---|
| 2410 | // | 
|---|
| 2411 |  | 
|---|
| 2412 | // Unicode Interface | 
|---|
| 2413 |  | 
|---|
| 2414 | DT_RETURN_MARK_DECL(NewString, jstring | 
|---|
| 2415 | , HOTSPOT_JNI_NEWSTRING_RETURN(_ret_ref)); | 
|---|
| 2416 |  | 
|---|
| 2417 | JNI_ENTRY(jstring, jni_NewString(JNIEnv *env, const jchar *unicodeChars, jsize len)) | 
|---|
| 2418 | JNIWrapper( "NewString"); | 
|---|
| 2419 | HOTSPOT_JNI_NEWSTRING_ENTRY(env, (uint16_t *) unicodeChars, len); | 
|---|
| 2420 | jstring ret = NULL; | 
|---|
| 2421 | DT_RETURN_MARK(NewString, jstring, (const jstring&)ret); | 
|---|
| 2422 | oop string=java_lang_String::create_oop_from_unicode((jchar*) unicodeChars, len, CHECK_NULL); | 
|---|
| 2423 | ret = (jstring) JNIHandles::make_local(env, string); | 
|---|
| 2424 | return ret; | 
|---|
| 2425 | JNI_END | 
|---|
| 2426 |  | 
|---|
| 2427 |  | 
|---|
| 2428 | JNI_QUICK_ENTRY(jsize, jni_GetStringLength(JNIEnv *env, jstring string)) | 
|---|
| 2429 | JNIWrapper( "GetStringLength"); | 
|---|
| 2430 | HOTSPOT_JNI_GETSTRINGLENGTH_ENTRY(env, string); | 
|---|
| 2431 | jsize ret = 0; | 
|---|
| 2432 | oop s = JNIHandles::resolve_non_null(string); | 
|---|
| 2433 | ret = java_lang_String::length(s); | 
|---|
| 2434 | HOTSPOT_JNI_GETSTRINGLENGTH_RETURN(ret); | 
|---|
| 2435 | return ret; | 
|---|
| 2436 | JNI_END | 
|---|
| 2437 |  | 
|---|
| 2438 |  | 
|---|
| 2439 | JNI_QUICK_ENTRY(const jchar*, jni_GetStringChars( | 
|---|
| 2440 | JNIEnv *env, jstring string, jboolean *isCopy)) | 
|---|
| 2441 | JNIWrapper( "GetStringChars"); | 
|---|
| 2442 | HOTSPOT_JNI_GETSTRINGCHARS_ENTRY(env, string, (uintptr_t *) isCopy); | 
|---|
| 2443 | jchar* buf = NULL; | 
|---|
| 2444 | oop s = JNIHandles::resolve_non_null(string); | 
|---|
| 2445 | typeArrayOop s_value = java_lang_String::value(s); | 
|---|
| 2446 | if (s_value != NULL) { | 
|---|
| 2447 | int s_len = java_lang_String::length(s, s_value); | 
|---|
| 2448 | bool is_latin1 = java_lang_String::is_latin1(s); | 
|---|
| 2449 | buf = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal);  // add one for zero termination | 
|---|
| 2450 | /* JNI Specification states return NULL on OOM */ | 
|---|
| 2451 | if (buf != NULL) { | 
|---|
| 2452 | if (s_len > 0) { | 
|---|
| 2453 | if (!is_latin1) { | 
|---|
| 2454 | ArrayAccess<>::arraycopy_to_native(s_value, (size_t) typeArrayOopDesc::element_offset<jchar>(0), | 
|---|
| 2455 | buf, s_len); | 
|---|
| 2456 | } else { | 
|---|
| 2457 | for (int i = 0; i < s_len; i++) { | 
|---|
| 2458 | buf[i] = ((jchar) s_value->byte_at(i)) & 0xff; | 
|---|
| 2459 | } | 
|---|
| 2460 | } | 
|---|
| 2461 | } | 
|---|
| 2462 | buf[s_len] = 0; | 
|---|
| 2463 | //%note jni_5 | 
|---|
| 2464 | if (isCopy != NULL) { | 
|---|
| 2465 | *isCopy = JNI_TRUE; | 
|---|
| 2466 | } | 
|---|
| 2467 | } | 
|---|
| 2468 | } | 
|---|
| 2469 | HOTSPOT_JNI_GETSTRINGCHARS_RETURN(buf); | 
|---|
| 2470 | return buf; | 
|---|
| 2471 | JNI_END | 
|---|
| 2472 |  | 
|---|
| 2473 |  | 
|---|
| 2474 | JNI_QUICK_ENTRY(void, jni_ReleaseStringChars(JNIEnv *env, jstring str, const jchar *chars)) | 
|---|
| 2475 | JNIWrapper( "ReleaseStringChars"); | 
|---|
| 2476 | HOTSPOT_JNI_RELEASESTRINGCHARS_ENTRY(env, str, (uint16_t *) chars); | 
|---|
| 2477 | //%note jni_6 | 
|---|
| 2478 | if (chars != NULL) { | 
|---|
| 2479 | // Since String objects are supposed to be immutable, don't copy any | 
|---|
| 2480 | // new data back.  A bad user will have to go after the char array. | 
|---|
| 2481 | FreeHeap((void*) chars); | 
|---|
| 2482 | } | 
|---|
| 2483 | HOTSPOT_JNI_RELEASESTRINGCHARS_RETURN(); | 
|---|
| 2484 | JNI_END | 
|---|
| 2485 |  | 
|---|
| 2486 |  | 
|---|
| 2487 | // UTF Interface | 
|---|
| 2488 |  | 
|---|
| 2489 | DT_RETURN_MARK_DECL(NewStringUTF, jstring | 
|---|
| 2490 | , HOTSPOT_JNI_NEWSTRINGUTF_RETURN(_ret_ref)); | 
|---|
| 2491 |  | 
|---|
| 2492 | JNI_ENTRY(jstring, jni_NewStringUTF(JNIEnv *env, const char *bytes)) | 
|---|
| 2493 | JNIWrapper( "NewStringUTF"); | 
|---|
| 2494 | HOTSPOT_JNI_NEWSTRINGUTF_ENTRY(env, (char *) bytes); | 
|---|
| 2495 | jstring ret; | 
|---|
| 2496 | DT_RETURN_MARK(NewStringUTF, jstring, (const jstring&)ret); | 
|---|
| 2497 |  | 
|---|
| 2498 | oop result = java_lang_String::create_oop_from_str((char*) bytes, CHECK_NULL); | 
|---|
| 2499 | ret = (jstring) JNIHandles::make_local(env, result); | 
|---|
| 2500 | return ret; | 
|---|
| 2501 | JNI_END | 
|---|
| 2502 |  | 
|---|
| 2503 |  | 
|---|
| 2504 | JNI_ENTRY(jsize, jni_GetStringUTFLength(JNIEnv *env, jstring string)) | 
|---|
| 2505 | JNIWrapper( "GetStringUTFLength"); | 
|---|
| 2506 | HOTSPOT_JNI_GETSTRINGUTFLENGTH_ENTRY(env, string); | 
|---|
| 2507 | oop java_string = JNIHandles::resolve_non_null(string); | 
|---|
| 2508 | jsize ret = java_lang_String::utf8_length(java_string); | 
|---|
| 2509 | HOTSPOT_JNI_GETSTRINGUTFLENGTH_RETURN(ret); | 
|---|
| 2510 | return ret; | 
|---|
| 2511 | JNI_END | 
|---|
| 2512 |  | 
|---|
| 2513 |  | 
|---|
| 2514 | JNI_ENTRY(const char*, jni_GetStringUTFChars(JNIEnv *env, jstring string, jboolean *isCopy)) | 
|---|
| 2515 | JNIWrapper( "GetStringUTFChars"); | 
|---|
| 2516 | HOTSPOT_JNI_GETSTRINGUTFCHARS_ENTRY(env, string, (uintptr_t *) isCopy); | 
|---|
| 2517 | char* result = NULL; | 
|---|
| 2518 | oop java_string = JNIHandles::resolve_non_null(string); | 
|---|
| 2519 | typeArrayOop s_value = java_lang_String::value(java_string); | 
|---|
| 2520 | if (s_value != NULL) { | 
|---|
| 2521 | size_t length = java_lang_String::utf8_length(java_string, s_value); | 
|---|
| 2522 | /* JNI Specification states return NULL on OOM */ | 
|---|
| 2523 | result = AllocateHeap(length + 1, mtInternal, 0, AllocFailStrategy::RETURN_NULL); | 
|---|
| 2524 | if (result != NULL) { | 
|---|
| 2525 | java_lang_String::as_utf8_string(java_string, s_value, result, (int) length + 1); | 
|---|
| 2526 | if (isCopy != NULL) { | 
|---|
| 2527 | *isCopy = JNI_TRUE; | 
|---|
| 2528 | } | 
|---|
| 2529 | } | 
|---|
| 2530 | } | 
|---|
| 2531 | HOTSPOT_JNI_GETSTRINGUTFCHARS_RETURN(result); | 
|---|
| 2532 | return result; | 
|---|
| 2533 | JNI_END | 
|---|
| 2534 |  | 
|---|
| 2535 |  | 
|---|
| 2536 | JNI_LEAF(void, jni_ReleaseStringUTFChars(JNIEnv *env, jstring str, const char *chars)) | 
|---|
| 2537 | JNIWrapper( "ReleaseStringUTFChars"); | 
|---|
| 2538 | HOTSPOT_JNI_RELEASESTRINGUTFCHARS_ENTRY(env, str, (char *) chars); | 
|---|
| 2539 | if (chars != NULL) { | 
|---|
| 2540 | FreeHeap((char*) chars); | 
|---|
| 2541 | } | 
|---|
| 2542 | HOTSPOT_JNI_RELEASESTRINGUTFCHARS_RETURN(); | 
|---|
| 2543 | JNI_END | 
|---|
| 2544 |  | 
|---|
| 2545 |  | 
|---|
| 2546 | JNI_QUICK_ENTRY(jsize, jni_GetArrayLength(JNIEnv *env, jarray array)) | 
|---|
| 2547 | JNIWrapper( "GetArrayLength"); | 
|---|
| 2548 | HOTSPOT_JNI_GETARRAYLENGTH_ENTRY(env, array); | 
|---|
| 2549 | arrayOop a = arrayOop(JNIHandles::resolve_non_null(array)); | 
|---|
| 2550 | assert(a->is_array(), "must be array"); | 
|---|
| 2551 | jsize ret = a->length(); | 
|---|
| 2552 | HOTSPOT_JNI_GETARRAYLENGTH_RETURN(ret); | 
|---|
| 2553 | return ret; | 
|---|
| 2554 | JNI_END | 
|---|
| 2555 |  | 
|---|
| 2556 |  | 
|---|
| 2557 | // | 
|---|
| 2558 | // Object Array Operations | 
|---|
| 2559 | // | 
|---|
| 2560 |  | 
|---|
| 2561 | DT_RETURN_MARK_DECL(NewObjectArray, jobjectArray | 
|---|
| 2562 | , HOTSPOT_JNI_NEWOBJECTARRAY_RETURN(_ret_ref)); | 
|---|
| 2563 |  | 
|---|
| 2564 | JNI_ENTRY(jobjectArray, jni_NewObjectArray(JNIEnv *env, jsize length, jclass elementClass, jobject initialElement)) | 
|---|
| 2565 | JNIWrapper( "NewObjectArray"); | 
|---|
| 2566 | HOTSPOT_JNI_NEWOBJECTARRAY_ENTRY(env, length, elementClass, initialElement); | 
|---|
| 2567 | jobjectArray ret = NULL; | 
|---|
| 2568 | DT_RETURN_MARK(NewObjectArray, jobjectArray, (const jobjectArray&)ret); | 
|---|
| 2569 | Klass* ek = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(elementClass)); | 
|---|
| 2570 | Klass* ak = ek->array_klass(CHECK_NULL); | 
|---|
| 2571 | ObjArrayKlass::cast(ak)->initialize(CHECK_NULL); | 
|---|
| 2572 | objArrayOop result = ObjArrayKlass::cast(ak)->allocate(length, CHECK_NULL); | 
|---|
| 2573 | oop initial_value = JNIHandles::resolve(initialElement); | 
|---|
| 2574 | if (initial_value != NULL) {  // array already initialized with NULL | 
|---|
| 2575 | for (int index = 0; index < length; index++) { | 
|---|
| 2576 | result->obj_at_put(index, initial_value); | 
|---|
| 2577 | } | 
|---|
| 2578 | } | 
|---|
| 2579 | ret = (jobjectArray) JNIHandles::make_local(env, result); | 
|---|
| 2580 | return ret; | 
|---|
| 2581 | JNI_END | 
|---|
| 2582 |  | 
|---|
| 2583 | DT_RETURN_MARK_DECL(GetObjectArrayElement, jobject | 
|---|
| 2584 | , HOTSPOT_JNI_GETOBJECTARRAYELEMENT_RETURN(_ret_ref)); | 
|---|
| 2585 |  | 
|---|
| 2586 | JNI_ENTRY(jobject, jni_GetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index)) | 
|---|
| 2587 | JNIWrapper( "GetObjectArrayElement"); | 
|---|
| 2588 | HOTSPOT_JNI_GETOBJECTARRAYELEMENT_ENTRY(env, array, index); | 
|---|
| 2589 | jobject ret = NULL; | 
|---|
| 2590 | DT_RETURN_MARK(GetObjectArrayElement, jobject, (const jobject&)ret); | 
|---|
| 2591 | objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); | 
|---|
| 2592 | if (a->is_within_bounds(index)) { | 
|---|
| 2593 | ret = JNIHandles::make_local(env, a->obj_at(index)); | 
|---|
| 2594 | return ret; | 
|---|
| 2595 | } else { | 
|---|
| 2596 | ResourceMark rm(THREAD); | 
|---|
| 2597 | stringStream ss; | 
|---|
| 2598 | ss.print( "Index %d out of bounds for length %d", index, a->length()); | 
|---|
| 2599 | THROW_MSG_0(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); | 
|---|
| 2600 | } | 
|---|
| 2601 | JNI_END | 
|---|
| 2602 |  | 
|---|
| 2603 | DT_VOID_RETURN_MARK_DECL(SetObjectArrayElement | 
|---|
| 2604 | , HOTSPOT_JNI_SETOBJECTARRAYELEMENT_RETURN()); | 
|---|
| 2605 |  | 
|---|
| 2606 | JNI_ENTRY(void, jni_SetObjectArrayElement(JNIEnv *env, jobjectArray array, jsize index, jobject value)) | 
|---|
| 2607 | JNIWrapper( "SetObjectArrayElement"); | 
|---|
| 2608 | HOTSPOT_JNI_SETOBJECTARRAYELEMENT_ENTRY(env, array, index, value); | 
|---|
| 2609 | DT_VOID_RETURN_MARK(SetObjectArrayElement); | 
|---|
| 2610 |  | 
|---|
| 2611 | objArrayOop a = objArrayOop(JNIHandles::resolve_non_null(array)); | 
|---|
| 2612 | oop v = JNIHandles::resolve(value); | 
|---|
| 2613 | if (a->is_within_bounds(index)) { | 
|---|
| 2614 | if (v == NULL || v->is_a(ObjArrayKlass::cast(a->klass())->element_klass())) { | 
|---|
| 2615 | a->obj_at_put(index, v); | 
|---|
| 2616 | } else { | 
|---|
| 2617 | ResourceMark rm(THREAD); | 
|---|
| 2618 | stringStream ss; | 
|---|
| 2619 | Klass *bottom_kl = ObjArrayKlass::cast(a->klass())->bottom_klass(); | 
|---|
| 2620 | ss.print( "type mismatch: can not store %s to %s[%d]", | 
|---|
| 2621 | v->klass()->external_name(), | 
|---|
| 2622 | bottom_kl->is_typeArray_klass() ? type2name_tab[ArrayKlass::cast(bottom_kl)->element_type()] : bottom_kl->external_name(), | 
|---|
| 2623 | index); | 
|---|
| 2624 | for (int dims = ArrayKlass::cast(a->klass())->dimension(); dims > 1; --dims) { | 
|---|
| 2625 | ss.print( "[]"); | 
|---|
| 2626 | } | 
|---|
| 2627 | THROW_MSG(vmSymbols::java_lang_ArrayStoreException(), ss.as_string()); | 
|---|
| 2628 | } | 
|---|
| 2629 | } else { | 
|---|
| 2630 | ResourceMark rm(THREAD); | 
|---|
| 2631 | stringStream ss; | 
|---|
| 2632 | ss.print( "Index %d out of bounds for length %d", index, a->length()); | 
|---|
| 2633 | THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); | 
|---|
| 2634 | } | 
|---|
| 2635 | JNI_END | 
|---|
| 2636 |  | 
|---|
| 2637 |  | 
|---|
| 2638 |  | 
|---|
| 2639 | #define DEFINE_NEWSCALARARRAY(Return,Allocator,Result \ | 
|---|
| 2640 | ,EntryProbe,ReturnProbe)  \ | 
|---|
| 2641 | \ | 
|---|
| 2642 | DT_RETURN_MARK_DECL(New##Result##Array, Return \ | 
|---|
| 2643 | , ReturnProbe); \ | 
|---|
| 2644 | \ | 
|---|
| 2645 | JNI_ENTRY(Return, \ | 
|---|
| 2646 | jni_New##Result##Array(JNIEnv *env, jsize len)) \ | 
|---|
| 2647 | JNIWrapper("New" XSTR(Result) "Array"); \ | 
|---|
| 2648 | EntryProbe; \ | 
|---|
| 2649 | Return ret = NULL;\ | 
|---|
| 2650 | DT_RETURN_MARK(New##Result##Array, Return, (const Return&)ret);\ | 
|---|
| 2651 | \ | 
|---|
| 2652 | oop obj= oopFactory::Allocator(len, CHECK_0); \ | 
|---|
| 2653 | ret = (Return) JNIHandles::make_local(env, obj); \ | 
|---|
| 2654 | return ret;\ | 
|---|
| 2655 | JNI_END | 
|---|
| 2656 |  | 
|---|
| 2657 | DEFINE_NEWSCALARARRAY(jbooleanArray, new_boolArray,   Boolean, | 
|---|
| 2658 | HOTSPOT_JNI_NEWBOOLEANARRAY_ENTRY(env, len), | 
|---|
| 2659 | HOTSPOT_JNI_NEWBOOLEANARRAY_RETURN(_ret_ref)) | 
|---|
| 2660 | DEFINE_NEWSCALARARRAY(jbyteArray,    new_byteArray,   Byte, | 
|---|
| 2661 | HOTSPOT_JNI_NEWBYTEARRAY_ENTRY(env, len), | 
|---|
| 2662 | HOTSPOT_JNI_NEWBYTEARRAY_RETURN(_ret_ref)) | 
|---|
| 2663 | DEFINE_NEWSCALARARRAY(jshortArray,   new_shortArray,  Short, | 
|---|
| 2664 | HOTSPOT_JNI_NEWSHORTARRAY_ENTRY(env, len), | 
|---|
| 2665 | HOTSPOT_JNI_NEWSHORTARRAY_RETURN(_ret_ref)) | 
|---|
| 2666 | DEFINE_NEWSCALARARRAY(jcharArray,    new_charArray,   Char, | 
|---|
| 2667 | HOTSPOT_JNI_NEWCHARARRAY_ENTRY(env, len), | 
|---|
| 2668 | HOTSPOT_JNI_NEWCHARARRAY_RETURN(_ret_ref)) | 
|---|
| 2669 | DEFINE_NEWSCALARARRAY(jintArray,     new_intArray,    Int, | 
|---|
| 2670 | HOTSPOT_JNI_NEWINTARRAY_ENTRY(env, len), | 
|---|
| 2671 | HOTSPOT_JNI_NEWINTARRAY_RETURN(_ret_ref)) | 
|---|
| 2672 | DEFINE_NEWSCALARARRAY(jlongArray,    new_longArray,   Long, | 
|---|
| 2673 | HOTSPOT_JNI_NEWLONGARRAY_ENTRY(env, len), | 
|---|
| 2674 | HOTSPOT_JNI_NEWLONGARRAY_RETURN(_ret_ref)) | 
|---|
| 2675 | DEFINE_NEWSCALARARRAY(jfloatArray,   new_floatArray,  Float, | 
|---|
| 2676 | HOTSPOT_JNI_NEWFLOATARRAY_ENTRY(env, len), | 
|---|
| 2677 | HOTSPOT_JNI_NEWFLOATARRAY_RETURN(_ret_ref)) | 
|---|
| 2678 | DEFINE_NEWSCALARARRAY(jdoubleArray,  new_doubleArray, Double, | 
|---|
| 2679 | HOTSPOT_JNI_NEWDOUBLEARRAY_ENTRY(env, len), | 
|---|
| 2680 | HOTSPOT_JNI_NEWDOUBLEARRAY_RETURN(_ret_ref)) | 
|---|
| 2681 |  | 
|---|
| 2682 | // Return an address which will fault if the caller writes to it. | 
|---|
| 2683 |  | 
|---|
| 2684 | static char* get_bad_address() { | 
|---|
| 2685 | static char* bad_address = NULL; | 
|---|
| 2686 | if (bad_address == NULL) { | 
|---|
| 2687 | size_t size = os::vm_allocation_granularity(); | 
|---|
| 2688 | bad_address = os::reserve_memory(size); | 
|---|
| 2689 | if (bad_address != NULL) { | 
|---|
| 2690 | os::protect_memory(bad_address, size, os::MEM_PROT_READ, | 
|---|
| 2691 | /*is_committed*/false); | 
|---|
| 2692 | MemTracker::record_virtual_memory_type((void*)bad_address, mtInternal); | 
|---|
| 2693 | } | 
|---|
| 2694 | } | 
|---|
| 2695 | return bad_address; | 
|---|
| 2696 | } | 
|---|
| 2697 |  | 
|---|
| 2698 |  | 
|---|
| 2699 |  | 
|---|
| 2700 | #define DEFINE_GETSCALARARRAYELEMENTS(ElementTag,ElementType,Result, Tag \ | 
|---|
| 2701 | , EntryProbe, ReturnProbe) \ | 
|---|
| 2702 | \ | 
|---|
| 2703 | JNI_QUICK_ENTRY(ElementType*, \ | 
|---|
| 2704 | jni_Get##Result##ArrayElements(JNIEnv *env, ElementType##Array array, jboolean *isCopy)) \ | 
|---|
| 2705 | JNIWrapper("Get" XSTR(Result) "ArrayElements"); \ | 
|---|
| 2706 | EntryProbe; \ | 
|---|
| 2707 | /* allocate an chunk of memory in c land */ \ | 
|---|
| 2708 | typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(array)); \ | 
|---|
| 2709 | ElementType* result; \ | 
|---|
| 2710 | int len = a->length(); \ | 
|---|
| 2711 | if (len == 0) { \ | 
|---|
| 2712 | if (isCopy != NULL) { \ | 
|---|
| 2713 | *isCopy = JNI_FALSE; \ | 
|---|
| 2714 | } \ | 
|---|
| 2715 | /* Empty array: legal but useless, can't return NULL. \ | 
|---|
| 2716 | * Return a pointer to something useless. \ | 
|---|
| 2717 | * Avoid asserts in typeArrayOop. */ \ | 
|---|
| 2718 | result = (ElementType*)get_bad_address(); \ | 
|---|
| 2719 | } else { \ | 
|---|
| 2720 | /* JNI Specification states return NULL on OOM */                    \ | 
|---|
| 2721 | result = NEW_C_HEAP_ARRAY_RETURN_NULL(ElementType, len, mtInternal); \ | 
|---|
| 2722 | if (result != NULL) {                                                \ | 
|---|
| 2723 | /* copy the array to the c chunk */                                \ | 
|---|
| 2724 | ArrayAccess<>::arraycopy_to_native(a, typeArrayOopDesc::element_offset<ElementType>(0), \ | 
|---|
| 2725 | result, len);                   \ | 
|---|
| 2726 | if (isCopy) {                                                      \ | 
|---|
| 2727 | *isCopy = JNI_TRUE;                                              \ | 
|---|
| 2728 | }                                                                  \ | 
|---|
| 2729 | }                                                                    \ | 
|---|
| 2730 | } \ | 
|---|
| 2731 | ReturnProbe; \ | 
|---|
| 2732 | return result; \ | 
|---|
| 2733 | JNI_END | 
|---|
| 2734 |  | 
|---|
| 2735 | DEFINE_GETSCALARARRAYELEMENTS(T_BOOLEAN, jboolean, Boolean, bool | 
|---|
| 2736 | , HOTSPOT_JNI_GETBOOLEANARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), | 
|---|
| 2737 | HOTSPOT_JNI_GETBOOLEANARRAYELEMENTS_RETURN((uintptr_t*)result)) | 
|---|
| 2738 | DEFINE_GETSCALARARRAYELEMENTS(T_BYTE,    jbyte,    Byte,    byte | 
|---|
| 2739 | , HOTSPOT_JNI_GETBYTEARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), | 
|---|
| 2740 | HOTSPOT_JNI_GETBYTEARRAYELEMENTS_RETURN((char*)result)) | 
|---|
| 2741 | DEFINE_GETSCALARARRAYELEMENTS(T_SHORT,   jshort,   Short,   short | 
|---|
| 2742 | , HOTSPOT_JNI_GETSHORTARRAYELEMENTS_ENTRY(env, (uint16_t*) array, (uintptr_t *) isCopy), | 
|---|
| 2743 | HOTSPOT_JNI_GETSHORTARRAYELEMENTS_RETURN((uint16_t*)result)) | 
|---|
| 2744 | DEFINE_GETSCALARARRAYELEMENTS(T_CHAR,    jchar,    Char,    char | 
|---|
| 2745 | , HOTSPOT_JNI_GETCHARARRAYELEMENTS_ENTRY(env, (uint16_t*) array, (uintptr_t *) isCopy), | 
|---|
| 2746 | HOTSPOT_JNI_GETCHARARRAYELEMENTS_RETURN(result)) | 
|---|
| 2747 | DEFINE_GETSCALARARRAYELEMENTS(T_INT,     jint,     Int,     int | 
|---|
| 2748 | , HOTSPOT_JNI_GETINTARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), | 
|---|
| 2749 | HOTSPOT_JNI_GETINTARRAYELEMENTS_RETURN((uint32_t*)result)) | 
|---|
| 2750 | DEFINE_GETSCALARARRAYELEMENTS(T_LONG,    jlong,    Long,    long | 
|---|
| 2751 | , HOTSPOT_JNI_GETLONGARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), | 
|---|
| 2752 | HOTSPOT_JNI_GETLONGARRAYELEMENTS_RETURN(((uintptr_t*)result))) | 
|---|
| 2753 | // Float and double probes don't return value because dtrace doesn't currently support it | 
|---|
| 2754 | DEFINE_GETSCALARARRAYELEMENTS(T_FLOAT,   jfloat,   Float,   float | 
|---|
| 2755 | , HOTSPOT_JNI_GETFLOATARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), | 
|---|
| 2756 | HOTSPOT_JNI_GETFLOATARRAYELEMENTS_RETURN(result)) | 
|---|
| 2757 | DEFINE_GETSCALARARRAYELEMENTS(T_DOUBLE,  jdouble,  Double,  double | 
|---|
| 2758 | , HOTSPOT_JNI_GETDOUBLEARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) isCopy), | 
|---|
| 2759 | HOTSPOT_JNI_GETDOUBLEARRAYELEMENTS_RETURN(result)) | 
|---|
| 2760 |  | 
|---|
| 2761 |  | 
|---|
| 2762 | #define DEFINE_RELEASESCALARARRAYELEMENTS(ElementTag,ElementType,Result,Tag \ | 
|---|
| 2763 | , EntryProbe, ReturnProbe);\ | 
|---|
| 2764 | \ | 
|---|
| 2765 | JNI_QUICK_ENTRY(void, \ | 
|---|
| 2766 | jni_Release##Result##ArrayElements(JNIEnv *env, ElementType##Array array, \ | 
|---|
| 2767 | ElementType *buf, jint mode)) \ | 
|---|
| 2768 | JNIWrapper("Release" XSTR(Result) "ArrayElements"); \ | 
|---|
| 2769 | EntryProbe; \ | 
|---|
| 2770 | typeArrayOop a = typeArrayOop(JNIHandles::resolve_non_null(array)); \ | 
|---|
| 2771 | int len = a->length(); \ | 
|---|
| 2772 | if (len != 0) {   /* Empty array:  nothing to free or copy. */  \ | 
|---|
| 2773 | if ((mode == 0) || (mode == JNI_COMMIT)) { \ | 
|---|
| 2774 | ArrayAccess<>::arraycopy_from_native(buf, a, typeArrayOopDesc::element_offset<ElementType>(0), len); \ | 
|---|
| 2775 | } \ | 
|---|
| 2776 | if ((mode == 0) || (mode == JNI_ABORT)) { \ | 
|---|
| 2777 | FreeHeap(buf); \ | 
|---|
| 2778 | } \ | 
|---|
| 2779 | } \ | 
|---|
| 2780 | ReturnProbe; \ | 
|---|
| 2781 | JNI_END | 
|---|
| 2782 |  | 
|---|
| 2783 | DEFINE_RELEASESCALARARRAYELEMENTS(T_BOOLEAN, jboolean, Boolean, bool | 
|---|
| 2784 | , HOTSPOT_JNI_RELEASEBOOLEANARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) buf, mode), | 
|---|
| 2785 | HOTSPOT_JNI_RELEASEBOOLEANARRAYELEMENTS_RETURN()) | 
|---|
| 2786 | DEFINE_RELEASESCALARARRAYELEMENTS(T_BYTE,    jbyte,    Byte,    byte | 
|---|
| 2787 | , HOTSPOT_JNI_RELEASEBYTEARRAYELEMENTS_ENTRY(env, array, (char *) buf, mode), | 
|---|
| 2788 | HOTSPOT_JNI_RELEASEBYTEARRAYELEMENTS_RETURN()) | 
|---|
| 2789 | DEFINE_RELEASESCALARARRAYELEMENTS(T_SHORT,   jshort,   Short,   short | 
|---|
| 2790 | ,  HOTSPOT_JNI_RELEASESHORTARRAYELEMENTS_ENTRY(env, array, (uint16_t *) buf, mode), | 
|---|
| 2791 | HOTSPOT_JNI_RELEASESHORTARRAYELEMENTS_RETURN()) | 
|---|
| 2792 | DEFINE_RELEASESCALARARRAYELEMENTS(T_CHAR,    jchar,    Char,    char | 
|---|
| 2793 | ,  HOTSPOT_JNI_RELEASECHARARRAYELEMENTS_ENTRY(env, array, (uint16_t *) buf, mode), | 
|---|
| 2794 | HOTSPOT_JNI_RELEASECHARARRAYELEMENTS_RETURN()) | 
|---|
| 2795 | DEFINE_RELEASESCALARARRAYELEMENTS(T_INT,     jint,     Int,     int | 
|---|
| 2796 | , HOTSPOT_JNI_RELEASEINTARRAYELEMENTS_ENTRY(env, array, (uint32_t *) buf, mode), | 
|---|
| 2797 | HOTSPOT_JNI_RELEASEINTARRAYELEMENTS_RETURN()) | 
|---|
| 2798 | DEFINE_RELEASESCALARARRAYELEMENTS(T_LONG,    jlong,    Long,    long | 
|---|
| 2799 | , HOTSPOT_JNI_RELEASELONGARRAYELEMENTS_ENTRY(env, array, (uintptr_t *) buf, mode), | 
|---|
| 2800 | HOTSPOT_JNI_RELEASELONGARRAYELEMENTS_RETURN()) | 
|---|
| 2801 | DEFINE_RELEASESCALARARRAYELEMENTS(T_FLOAT,   jfloat,   Float,   float | 
|---|
| 2802 | , HOTSPOT_JNI_RELEASEFLOATARRAYELEMENTS_ENTRY(env, array, (float *) buf, mode), | 
|---|
| 2803 | HOTSPOT_JNI_RELEASEFLOATARRAYELEMENTS_RETURN()) | 
|---|
| 2804 | DEFINE_RELEASESCALARARRAYELEMENTS(T_DOUBLE,  jdouble,  Double,  double | 
|---|
| 2805 | , HOTSPOT_JNI_RELEASEDOUBLEARRAYELEMENTS_ENTRY(env, array, (double *) buf, mode), | 
|---|
| 2806 | HOTSPOT_JNI_RELEASEDOUBLEARRAYELEMENTS_RETURN()) | 
|---|
| 2807 |  | 
|---|
| 2808 | static void check_bounds(jsize start, jsize copy_len, jsize array_len, TRAPS) { | 
|---|
| 2809 | ResourceMark rm(THREAD); | 
|---|
| 2810 | if (copy_len < 0) { | 
|---|
| 2811 | stringStream ss; | 
|---|
| 2812 | ss.print( "Length %d is negative", copy_len); | 
|---|
| 2813 | THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); | 
|---|
| 2814 | } else if (start < 0 || (start > array_len - copy_len)) { | 
|---|
| 2815 | stringStream ss; | 
|---|
| 2816 | ss.print( "Array region %d.."INT64_FORMAT " out of bounds for length %d", | 
|---|
| 2817 | start, (int64_t)start+(int64_t)copy_len, array_len); | 
|---|
| 2818 | THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string()); | 
|---|
| 2819 | } | 
|---|
| 2820 | } | 
|---|
| 2821 |  | 
|---|
| 2822 | #define DEFINE_GETSCALARARRAYREGION(ElementTag,ElementType,Result, Tag \ | 
|---|
| 2823 | , EntryProbe, ReturnProbe); \ | 
|---|
| 2824 | DT_VOID_RETURN_MARK_DECL(Get##Result##ArrayRegion \ | 
|---|
| 2825 | , ReturnProbe); \ | 
|---|
| 2826 | \ | 
|---|
| 2827 | JNI_ENTRY(void, \ | 
|---|
| 2828 | jni_Get##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, \ | 
|---|
| 2829 | jsize len, ElementType *buf)) \ | 
|---|
| 2830 | JNIWrapper("Get" XSTR(Result) "ArrayRegion"); \ | 
|---|
| 2831 | EntryProbe; \ | 
|---|
| 2832 | DT_VOID_RETURN_MARK(Get##Result##ArrayRegion); \ | 
|---|
| 2833 | typeArrayOop src = typeArrayOop(JNIHandles::resolve_non_null(array)); \ | 
|---|
| 2834 | check_bounds(start, len, src->length(), CHECK); \ | 
|---|
| 2835 | if (len > 0) {    \ | 
|---|
| 2836 | ArrayAccess<>::arraycopy_to_native(src, typeArrayOopDesc::element_offset<ElementType>(start), buf, len); \ | 
|---|
| 2837 | } \ | 
|---|
| 2838 | JNI_END | 
|---|
| 2839 |  | 
|---|
| 2840 | DEFINE_GETSCALARARRAYREGION(T_BOOLEAN, jboolean,Boolean, bool | 
|---|
| 2841 | , HOTSPOT_JNI_GETBOOLEANARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *) buf), | 
|---|
| 2842 | HOTSPOT_JNI_GETBOOLEANARRAYREGION_RETURN()); | 
|---|
| 2843 | DEFINE_GETSCALARARRAYREGION(T_BYTE,    jbyte,   Byte,    byte | 
|---|
| 2844 | ,  HOTSPOT_JNI_GETBYTEARRAYREGION_ENTRY(env, array, start, len, (char *) buf), | 
|---|
| 2845 | HOTSPOT_JNI_GETBYTEARRAYREGION_RETURN()); | 
|---|
| 2846 | DEFINE_GETSCALARARRAYREGION(T_SHORT,   jshort,  Short,   short | 
|---|
| 2847 | , HOTSPOT_JNI_GETSHORTARRAYREGION_ENTRY(env, array, start, len, (uint16_t *) buf), | 
|---|
| 2848 | HOTSPOT_JNI_GETSHORTARRAYREGION_RETURN()); | 
|---|
| 2849 | DEFINE_GETSCALARARRAYREGION(T_CHAR,    jchar,   Char,    char | 
|---|
| 2850 | ,  HOTSPOT_JNI_GETCHARARRAYREGION_ENTRY(env, array, start, len, (uint16_t*) buf), | 
|---|
| 2851 | HOTSPOT_JNI_GETCHARARRAYREGION_RETURN()); | 
|---|
| 2852 | DEFINE_GETSCALARARRAYREGION(T_INT,     jint,    Int,     int | 
|---|
| 2853 | , HOTSPOT_JNI_GETINTARRAYREGION_ENTRY(env, array, start, len, (uint32_t*) buf), | 
|---|
| 2854 | HOTSPOT_JNI_GETINTARRAYREGION_RETURN()); | 
|---|
| 2855 | DEFINE_GETSCALARARRAYREGION(T_LONG,    jlong,   Long,    long | 
|---|
| 2856 | ,  HOTSPOT_JNI_GETLONGARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *) buf), | 
|---|
| 2857 | HOTSPOT_JNI_GETLONGARRAYREGION_RETURN()); | 
|---|
| 2858 | DEFINE_GETSCALARARRAYREGION(T_FLOAT,   jfloat,  Float,   float | 
|---|
| 2859 | , HOTSPOT_JNI_GETFLOATARRAYREGION_ENTRY(env, array, start, len, (float *) buf), | 
|---|
| 2860 | HOTSPOT_JNI_GETFLOATARRAYREGION_RETURN()); | 
|---|
| 2861 | DEFINE_GETSCALARARRAYREGION(T_DOUBLE,  jdouble, Double,  double | 
|---|
| 2862 | , HOTSPOT_JNI_GETDOUBLEARRAYREGION_ENTRY(env, array, start, len, (double *) buf), | 
|---|
| 2863 | HOTSPOT_JNI_GETDOUBLEARRAYREGION_RETURN()); | 
|---|
| 2864 |  | 
|---|
| 2865 |  | 
|---|
| 2866 | #define DEFINE_SETSCALARARRAYREGION(ElementTag,ElementType,Result, Tag \ | 
|---|
| 2867 | , EntryProbe, ReturnProbe); \ | 
|---|
| 2868 | DT_VOID_RETURN_MARK_DECL(Set##Result##ArrayRegion \ | 
|---|
| 2869 | ,ReturnProbe);           \ | 
|---|
| 2870 | \ | 
|---|
| 2871 | JNI_ENTRY(void, \ | 
|---|
| 2872 | jni_Set##Result##ArrayRegion(JNIEnv *env, ElementType##Array array, jsize start, \ | 
|---|
| 2873 | jsize len, const ElementType *buf)) \ | 
|---|
| 2874 | JNIWrapper("Set" XSTR(Result) "ArrayRegion"); \ | 
|---|
| 2875 | EntryProbe; \ | 
|---|
| 2876 | DT_VOID_RETURN_MARK(Set##Result##ArrayRegion); \ | 
|---|
| 2877 | typeArrayOop dst = typeArrayOop(JNIHandles::resolve_non_null(array)); \ | 
|---|
| 2878 | check_bounds(start, len, dst->length(), CHECK); \ | 
|---|
| 2879 | if (len > 0) { \ | 
|---|
| 2880 | ArrayAccess<>::arraycopy_from_native(buf, dst, typeArrayOopDesc::element_offset<ElementType>(start), len); \ | 
|---|
| 2881 | } \ | 
|---|
| 2882 | JNI_END | 
|---|
| 2883 |  | 
|---|
| 2884 | DEFINE_SETSCALARARRAYREGION(T_BOOLEAN, jboolean, Boolean, bool | 
|---|
| 2885 | , HOTSPOT_JNI_SETBOOLEANARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *)buf), | 
|---|
| 2886 | HOTSPOT_JNI_SETBOOLEANARRAYREGION_RETURN()) | 
|---|
| 2887 | DEFINE_SETSCALARARRAYREGION(T_BYTE,    jbyte,    Byte,    byte | 
|---|
| 2888 | , HOTSPOT_JNI_SETBYTEARRAYREGION_ENTRY(env, array, start, len, (char *) buf), | 
|---|
| 2889 | HOTSPOT_JNI_SETBYTEARRAYREGION_RETURN()) | 
|---|
| 2890 | DEFINE_SETSCALARARRAYREGION(T_SHORT,   jshort,   Short,   short | 
|---|
| 2891 | , HOTSPOT_JNI_SETSHORTARRAYREGION_ENTRY(env, array, start, len, (uint16_t *) buf), | 
|---|
| 2892 | HOTSPOT_JNI_SETSHORTARRAYREGION_RETURN()) | 
|---|
| 2893 | DEFINE_SETSCALARARRAYREGION(T_CHAR,    jchar,    Char,    char | 
|---|
| 2894 | , HOTSPOT_JNI_SETCHARARRAYREGION_ENTRY(env, array, start, len, (uint16_t *) buf), | 
|---|
| 2895 | HOTSPOT_JNI_SETCHARARRAYREGION_RETURN()) | 
|---|
| 2896 | DEFINE_SETSCALARARRAYREGION(T_INT,     jint,     Int,     int | 
|---|
| 2897 | , HOTSPOT_JNI_SETINTARRAYREGION_ENTRY(env, array, start, len, (uint32_t *) buf), | 
|---|
| 2898 | HOTSPOT_JNI_SETINTARRAYREGION_RETURN()) | 
|---|
| 2899 | DEFINE_SETSCALARARRAYREGION(T_LONG,    jlong,    Long,    long | 
|---|
| 2900 | , HOTSPOT_JNI_SETLONGARRAYREGION_ENTRY(env, array, start, len, (uintptr_t *) buf), | 
|---|
| 2901 | HOTSPOT_JNI_SETLONGARRAYREGION_RETURN()) | 
|---|
| 2902 | DEFINE_SETSCALARARRAYREGION(T_FLOAT,   jfloat,   Float,   float | 
|---|
| 2903 | , HOTSPOT_JNI_SETFLOATARRAYREGION_ENTRY(env, array, start, len, (float *) buf), | 
|---|
| 2904 | HOTSPOT_JNI_SETFLOATARRAYREGION_RETURN()) | 
|---|
| 2905 | DEFINE_SETSCALARARRAYREGION(T_DOUBLE,  jdouble,  Double,  double | 
|---|
| 2906 | , HOTSPOT_JNI_SETDOUBLEARRAYREGION_ENTRY(env, array, start, len, (double *) buf), | 
|---|
| 2907 | HOTSPOT_JNI_SETDOUBLEARRAYREGION_RETURN()) | 
|---|
| 2908 |  | 
|---|
| 2909 |  | 
|---|
| 2910 | // | 
|---|
| 2911 | // Interception of natives | 
|---|
| 2912 | // | 
|---|
| 2913 |  | 
|---|
| 2914 | // The RegisterNatives call being attempted tried to register with a method that | 
|---|
| 2915 | // is not native.  Ask JVM TI what prefixes have been specified.  Then check | 
|---|
| 2916 | // to see if the native method is now wrapped with the prefixes.  See the | 
|---|
| 2917 | // SetNativeMethodPrefix(es) functions in the JVM TI Spec for details. | 
|---|
| 2918 | static Method* find_prefixed_native(Klass* k, Symbol* name, Symbol* signature, TRAPS) { | 
|---|
| 2919 | #if INCLUDE_JVMTI | 
|---|
| 2920 | ResourceMark rm(THREAD); | 
|---|
| 2921 | Method* method; | 
|---|
| 2922 | int name_len = name->utf8_length(); | 
|---|
| 2923 | char* name_str = name->as_utf8(); | 
|---|
| 2924 | int prefix_count; | 
|---|
| 2925 | char** prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count); | 
|---|
| 2926 | for (int i = 0; i < prefix_count; i++) { | 
|---|
| 2927 | char* prefix = prefixes[i]; | 
|---|
| 2928 | int prefix_len = (int)strlen(prefix); | 
|---|
| 2929 |  | 
|---|
| 2930 | // try adding this prefix to the method name and see if it matches another method name | 
|---|
| 2931 | int trial_len = name_len + prefix_len; | 
|---|
| 2932 | char* trial_name_str = NEW_RESOURCE_ARRAY(char, trial_len + 1); | 
|---|
| 2933 | strcpy(trial_name_str, prefix); | 
|---|
| 2934 | strcat(trial_name_str, name_str); | 
|---|
| 2935 | TempNewSymbol trial_name = SymbolTable::probe(trial_name_str, trial_len); | 
|---|
| 2936 | if (trial_name == NULL) { | 
|---|
| 2937 | continue; // no such symbol, so this prefix wasn't used, try the next prefix | 
|---|
| 2938 | } | 
|---|
| 2939 | method = k->lookup_method(trial_name, signature); | 
|---|
| 2940 | if (method == NULL) { | 
|---|
| 2941 | continue; // signature doesn't match, try the next prefix | 
|---|
| 2942 | } | 
|---|
| 2943 | if (method->is_native()) { | 
|---|
| 2944 | method->set_is_prefixed_native(); | 
|---|
| 2945 | return method; // wahoo, we found a prefixed version of the method, return it | 
|---|
| 2946 | } | 
|---|
| 2947 | // found as non-native, so prefix is good, add it, probably just need more prefixes | 
|---|
| 2948 | name_len = trial_len; | 
|---|
| 2949 | name_str = trial_name_str; | 
|---|
| 2950 | } | 
|---|
| 2951 | #endif // INCLUDE_JVMTI | 
|---|
| 2952 | return NULL; // not found | 
|---|
| 2953 | } | 
|---|
| 2954 |  | 
|---|
| 2955 | static bool register_native(Klass* k, Symbol* name, Symbol* signature, address entry, TRAPS) { | 
|---|
| 2956 | Method* method = k->lookup_method(name, signature); | 
|---|
| 2957 | if (method == NULL) { | 
|---|
| 2958 | ResourceMark rm; | 
|---|
| 2959 | stringStream st; | 
|---|
| 2960 | st.print( "Method '"); | 
|---|
| 2961 | Method::print_external_name(&st, k, name, signature); | 
|---|
| 2962 | st.print( "' name or signature does not match"); | 
|---|
| 2963 | THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false); | 
|---|
| 2964 | } | 
|---|
| 2965 | if (!method->is_native()) { | 
|---|
| 2966 | // trying to register to a non-native method, see if a JVM TI agent has added prefix(es) | 
|---|
| 2967 | method = find_prefixed_native(k, name, signature, THREAD); | 
|---|
| 2968 | if (method == NULL) { | 
|---|
| 2969 | ResourceMark rm; | 
|---|
| 2970 | stringStream st; | 
|---|
| 2971 | st.print( "Method '"); | 
|---|
| 2972 | Method::print_external_name(&st, k, name, signature); | 
|---|
| 2973 | st.print( "' is not declared as native"); | 
|---|
| 2974 | THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), false); | 
|---|
| 2975 | } | 
|---|
| 2976 | } | 
|---|
| 2977 |  | 
|---|
| 2978 | if (entry != NULL) { | 
|---|
| 2979 | method->set_native_function(entry, | 
|---|
| 2980 | Method::native_bind_event_is_interesting); | 
|---|
| 2981 | } else { | 
|---|
| 2982 | method->clear_native_function(); | 
|---|
| 2983 | } | 
|---|
| 2984 | if (PrintJNIResolving) { | 
|---|
| 2985 | ResourceMark rm(THREAD); | 
|---|
| 2986 | tty->print_cr( "[Registering JNI native method %s.%s]", | 
|---|
| 2987 | method->method_holder()->external_name(), | 
|---|
| 2988 | method->name()->as_C_string()); | 
|---|
| 2989 | } | 
|---|
| 2990 | return true; | 
|---|
| 2991 | } | 
|---|
| 2992 |  | 
|---|
| 2993 | DT_RETURN_MARK_DECL(RegisterNatives, jint | 
|---|
| 2994 | , HOTSPOT_JNI_REGISTERNATIVES_RETURN(_ret_ref)); | 
|---|
| 2995 |  | 
|---|
| 2996 | JNI_ENTRY(jint, jni_RegisterNatives(JNIEnv *env, jclass clazz, | 
|---|
| 2997 | const JNINativeMethod *methods, | 
|---|
| 2998 | jint nMethods)) | 
|---|
| 2999 | JNIWrapper( "RegisterNatives"); | 
|---|
| 3000 | HOTSPOT_JNI_REGISTERNATIVES_ENTRY(env, clazz, (void *) methods, nMethods); | 
|---|
| 3001 | jint ret = 0; | 
|---|
| 3002 | DT_RETURN_MARK(RegisterNatives, jint, (const jint&)ret); | 
|---|
| 3003 |  | 
|---|
| 3004 | Klass* k = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); | 
|---|
| 3005 |  | 
|---|
| 3006 | for (int index = 0; index < nMethods; index++) { | 
|---|
| 3007 | const char* meth_name = methods[index].name; | 
|---|
| 3008 | const char* meth_sig = methods[index].signature; | 
|---|
| 3009 | int meth_name_len = (int)strlen(meth_name); | 
|---|
| 3010 |  | 
|---|
| 3011 | // The class should have been loaded (we have an instance of the class | 
|---|
| 3012 | // passed in) so the method and signature should already be in the symbol | 
|---|
| 3013 | // table.  If they're not there, the method doesn't exist. | 
|---|
| 3014 | TempNewSymbol  name = SymbolTable::probe(meth_name, meth_name_len); | 
|---|
| 3015 | TempNewSymbol  signature = SymbolTable::probe(meth_sig, (int)strlen(meth_sig)); | 
|---|
| 3016 |  | 
|---|
| 3017 | if (name == NULL || signature == NULL) { | 
|---|
| 3018 | ResourceMark rm; | 
|---|
| 3019 | stringStream st; | 
|---|
| 3020 | st.print( "Method %s.%s%s not found", k->external_name(), meth_name, meth_sig); | 
|---|
| 3021 | // Must return negative value on failure | 
|---|
| 3022 | THROW_MSG_(vmSymbols::java_lang_NoSuchMethodError(), st.as_string(), -1); | 
|---|
| 3023 | } | 
|---|
| 3024 |  | 
|---|
| 3025 | bool res = register_native(k, name, signature, | 
|---|
| 3026 | (address) methods[index].fnPtr, THREAD); | 
|---|
| 3027 | if (!res) { | 
|---|
| 3028 | ret = -1; | 
|---|
| 3029 | break; | 
|---|
| 3030 | } | 
|---|
| 3031 | } | 
|---|
| 3032 | return ret; | 
|---|
| 3033 | JNI_END | 
|---|
| 3034 |  | 
|---|
| 3035 |  | 
|---|
| 3036 | JNI_ENTRY(jint, jni_UnregisterNatives(JNIEnv *env, jclass clazz)) | 
|---|
| 3037 | JNIWrapper( "UnregisterNatives"); | 
|---|
| 3038 | HOTSPOT_JNI_UNREGISTERNATIVES_ENTRY(env, clazz); | 
|---|
| 3039 | Klass* k   = java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)); | 
|---|
| 3040 | //%note jni_2 | 
|---|
| 3041 | if (k->is_instance_klass()) { | 
|---|
| 3042 | for (int index = 0; index < InstanceKlass::cast(k)->methods()->length(); index++) { | 
|---|
| 3043 | Method* m = InstanceKlass::cast(k)->methods()->at(index); | 
|---|
| 3044 | if (m->is_native()) { | 
|---|
| 3045 | m->clear_native_function(); | 
|---|
| 3046 | m->set_signature_handler(NULL); | 
|---|
| 3047 | } | 
|---|
| 3048 | } | 
|---|
| 3049 | } | 
|---|
| 3050 | HOTSPOT_JNI_UNREGISTERNATIVES_RETURN(0); | 
|---|
| 3051 | return 0; | 
|---|
| 3052 | JNI_END | 
|---|
| 3053 |  | 
|---|
| 3054 | // | 
|---|
| 3055 | // Monitor functions | 
|---|
| 3056 | // | 
|---|
| 3057 |  | 
|---|
| 3058 | DT_RETURN_MARK_DECL(MonitorEnter, jint | 
|---|
| 3059 | , HOTSPOT_JNI_MONITORENTER_RETURN(_ret_ref)); | 
|---|
| 3060 |  | 
|---|
| 3061 | JNI_ENTRY(jint, jni_MonitorEnter(JNIEnv *env, jobject jobj)) | 
|---|
| 3062 | HOTSPOT_JNI_MONITORENTER_ENTRY(env, jobj); | 
|---|
| 3063 | jint ret = JNI_ERR; | 
|---|
| 3064 | DT_RETURN_MARK(MonitorEnter, jint, (const jint&)ret); | 
|---|
| 3065 |  | 
|---|
| 3066 | // If the object is null, we can't do anything with it | 
|---|
| 3067 | if (jobj == NULL) { | 
|---|
| 3068 | THROW_(vmSymbols::java_lang_NullPointerException(), JNI_ERR); | 
|---|
| 3069 | } | 
|---|
| 3070 |  | 
|---|
| 3071 | Handle obj(thread, JNIHandles::resolve_non_null(jobj)); | 
|---|
| 3072 | ObjectSynchronizer::jni_enter(obj, CHECK_(JNI_ERR)); | 
|---|
| 3073 | ret = JNI_OK; | 
|---|
| 3074 | return ret; | 
|---|
| 3075 | JNI_END | 
|---|
| 3076 |  | 
|---|
| 3077 | DT_RETURN_MARK_DECL(MonitorExit, jint | 
|---|
| 3078 | , HOTSPOT_JNI_MONITOREXIT_RETURN(_ret_ref)); | 
|---|
| 3079 |  | 
|---|
| 3080 | JNI_ENTRY(jint, jni_MonitorExit(JNIEnv *env, jobject jobj)) | 
|---|
| 3081 | HOTSPOT_JNI_MONITOREXIT_ENTRY(env, jobj); | 
|---|
| 3082 | jint ret = JNI_ERR; | 
|---|
| 3083 | DT_RETURN_MARK(MonitorExit, jint, (const jint&)ret); | 
|---|
| 3084 |  | 
|---|
| 3085 | // Don't do anything with a null object | 
|---|
| 3086 | if (jobj == NULL) { | 
|---|
| 3087 | THROW_(vmSymbols::java_lang_NullPointerException(), JNI_ERR); | 
|---|
| 3088 | } | 
|---|
| 3089 |  | 
|---|
| 3090 | Handle obj(THREAD, JNIHandles::resolve_non_null(jobj)); | 
|---|
| 3091 | ObjectSynchronizer::jni_exit(obj(), CHECK_(JNI_ERR)); | 
|---|
| 3092 |  | 
|---|
| 3093 | ret = JNI_OK; | 
|---|
| 3094 | return ret; | 
|---|
| 3095 | JNI_END | 
|---|
| 3096 |  | 
|---|
| 3097 | // | 
|---|
| 3098 | // Extensions | 
|---|
| 3099 | // | 
|---|
| 3100 |  | 
|---|
| 3101 | DT_VOID_RETURN_MARK_DECL(GetStringRegion | 
|---|
| 3102 | , HOTSPOT_JNI_GETSTRINGREGION_RETURN()); | 
|---|
| 3103 |  | 
|---|
| 3104 | JNI_ENTRY(void, jni_GetStringRegion(JNIEnv *env, jstring string, jsize start, jsize len, jchar *buf)) | 
|---|
| 3105 | JNIWrapper( "GetStringRegion"); | 
|---|
| 3106 | HOTSPOT_JNI_GETSTRINGREGION_ENTRY(env, string, start, len, buf); | 
|---|
| 3107 | DT_VOID_RETURN_MARK(GetStringRegion); | 
|---|
| 3108 | oop s = JNIHandles::resolve_non_null(string); | 
|---|
| 3109 | typeArrayOop s_value = java_lang_String::value(s); | 
|---|
| 3110 | int s_len = java_lang_String::length(s, s_value); | 
|---|
| 3111 | if (start < 0 || len < 0 || start > s_len - len) { | 
|---|
| 3112 | THROW(vmSymbols::java_lang_StringIndexOutOfBoundsException()); | 
|---|
| 3113 | } else { | 
|---|
| 3114 | if (len > 0) { | 
|---|
| 3115 | bool is_latin1 = java_lang_String::is_latin1(s); | 
|---|
| 3116 | if (!is_latin1) { | 
|---|
| 3117 | ArrayAccess<>::arraycopy_to_native(s_value, typeArrayOopDesc::element_offset<jchar>(start), | 
|---|
| 3118 | buf, len); | 
|---|
| 3119 | } else { | 
|---|
| 3120 | for (int i = 0; i < len; i++) { | 
|---|
| 3121 | buf[i] = ((jchar) s_value->byte_at(i + start)) & 0xff; | 
|---|
| 3122 | } | 
|---|
| 3123 | } | 
|---|
| 3124 | } | 
|---|
| 3125 | } | 
|---|
| 3126 | JNI_END | 
|---|
| 3127 |  | 
|---|
| 3128 | DT_VOID_RETURN_MARK_DECL(GetStringUTFRegion | 
|---|
| 3129 | , HOTSPOT_JNI_GETSTRINGUTFREGION_RETURN()); | 
|---|
| 3130 |  | 
|---|
| 3131 | JNI_ENTRY(void, jni_GetStringUTFRegion(JNIEnv *env, jstring string, jsize start, jsize len, char *buf)) | 
|---|
| 3132 | JNIWrapper( "GetStringUTFRegion"); | 
|---|
| 3133 | HOTSPOT_JNI_GETSTRINGUTFREGION_ENTRY(env, string, start, len, buf); | 
|---|
| 3134 | DT_VOID_RETURN_MARK(GetStringUTFRegion); | 
|---|
| 3135 | oop s = JNIHandles::resolve_non_null(string); | 
|---|
| 3136 | typeArrayOop s_value = java_lang_String::value(s); | 
|---|
| 3137 | int s_len = java_lang_String::length(s, s_value); | 
|---|
| 3138 | if (start < 0 || len < 0 || start > s_len - len) { | 
|---|
| 3139 | THROW(vmSymbols::java_lang_StringIndexOutOfBoundsException()); | 
|---|
| 3140 | } else { | 
|---|
| 3141 | //%note jni_7 | 
|---|
| 3142 | if (len > 0) { | 
|---|
| 3143 | // Assume the buffer is large enough as the JNI spec. does not require user error checking | 
|---|
| 3144 | java_lang_String::as_utf8_string(s, s_value, start, len, buf, INT_MAX); | 
|---|
| 3145 | // as_utf8_string null-terminates the result string | 
|---|
| 3146 | } else { | 
|---|
| 3147 | // JDK null-terminates the buffer even in len is zero | 
|---|
| 3148 | if (buf != NULL) { | 
|---|
| 3149 | buf[0] = 0; | 
|---|
| 3150 | } | 
|---|
| 3151 | } | 
|---|
| 3152 | } | 
|---|
| 3153 | JNI_END | 
|---|
| 3154 |  | 
|---|
| 3155 | static oop lock_gc_or_pin_object(JavaThread* thread, jobject obj) { | 
|---|
| 3156 | if (Universe::heap()->supports_object_pinning()) { | 
|---|
| 3157 | const oop o = JNIHandles::resolve_non_null(obj); | 
|---|
| 3158 | return Universe::heap()->pin_object(thread, o); | 
|---|
| 3159 | } else { | 
|---|
| 3160 | GCLocker::lock_critical(thread); | 
|---|
| 3161 | return JNIHandles::resolve_non_null(obj); | 
|---|
| 3162 | } | 
|---|
| 3163 | } | 
|---|
| 3164 |  | 
|---|
| 3165 | static void unlock_gc_or_unpin_object(JavaThread* thread, jobject obj) { | 
|---|
| 3166 | if (Universe::heap()->supports_object_pinning()) { | 
|---|
| 3167 | const oop o = JNIHandles::resolve_non_null(obj); | 
|---|
| 3168 | return Universe::heap()->unpin_object(thread, o); | 
|---|
| 3169 | } else { | 
|---|
| 3170 | GCLocker::unlock_critical(thread); | 
|---|
| 3171 | } | 
|---|
| 3172 | } | 
|---|
| 3173 |  | 
|---|
| 3174 | JNI_ENTRY(void*, jni_GetPrimitiveArrayCritical(JNIEnv *env, jarray array, jboolean *isCopy)) | 
|---|
| 3175 | JNIWrapper( "GetPrimitiveArrayCritical"); | 
|---|
| 3176 | HOTSPOT_JNI_GETPRIMITIVEARRAYCRITICAL_ENTRY(env, array, (uintptr_t *) isCopy); | 
|---|
| 3177 | if (isCopy != NULL) { | 
|---|
| 3178 | *isCopy = JNI_FALSE; | 
|---|
| 3179 | } | 
|---|
| 3180 | oop a = lock_gc_or_pin_object(thread, array); | 
|---|
| 3181 | assert(a->is_array(), "just checking"); | 
|---|
| 3182 | BasicType type; | 
|---|
| 3183 | if (a->is_objArray()) { | 
|---|
| 3184 | type = T_OBJECT; | 
|---|
| 3185 | } else { | 
|---|
| 3186 | type = TypeArrayKlass::cast(a->klass())->element_type(); | 
|---|
| 3187 | } | 
|---|
| 3188 | void* ret = arrayOop(a)->base(type); | 
|---|
| 3189 | HOTSPOT_JNI_GETPRIMITIVEARRAYCRITICAL_RETURN(ret); | 
|---|
| 3190 | return ret; | 
|---|
| 3191 | JNI_END | 
|---|
| 3192 |  | 
|---|
| 3193 |  | 
|---|
| 3194 | JNI_ENTRY(void, jni_ReleasePrimitiveArrayCritical(JNIEnv *env, jarray array, void *carray, jint mode)) | 
|---|
| 3195 | JNIWrapper( "ReleasePrimitiveArrayCritical"); | 
|---|
| 3196 | HOTSPOT_JNI_RELEASEPRIMITIVEARRAYCRITICAL_ENTRY(env, array, carray, mode); | 
|---|
| 3197 | unlock_gc_or_unpin_object(thread, array); | 
|---|
| 3198 | HOTSPOT_JNI_RELEASEPRIMITIVEARRAYCRITICAL_RETURN(); | 
|---|
| 3199 | JNI_END | 
|---|
| 3200 |  | 
|---|
| 3201 |  | 
|---|
| 3202 | JNI_ENTRY(const jchar*, jni_GetStringCritical(JNIEnv *env, jstring string, jboolean *isCopy)) | 
|---|
| 3203 | JNIWrapper( "GetStringCritical"); | 
|---|
| 3204 | HOTSPOT_JNI_GETSTRINGCRITICAL_ENTRY(env, string, (uintptr_t *) isCopy); | 
|---|
| 3205 | oop s = lock_gc_or_pin_object(thread, string); | 
|---|
| 3206 | typeArrayOop s_value = java_lang_String::value(s); | 
|---|
| 3207 | bool is_latin1 = java_lang_String::is_latin1(s); | 
|---|
| 3208 | if (isCopy != NULL) { | 
|---|
| 3209 | *isCopy = is_latin1 ? JNI_TRUE : JNI_FALSE; | 
|---|
| 3210 | } | 
|---|
| 3211 | jchar* ret; | 
|---|
| 3212 | if (!is_latin1) { | 
|---|
| 3213 | ret = (jchar*) s_value->base(T_CHAR); | 
|---|
| 3214 | } else { | 
|---|
| 3215 | // Inflate latin1 encoded string to UTF16 | 
|---|
| 3216 | int s_len = java_lang_String::length(s, s_value); | 
|---|
| 3217 | ret = NEW_C_HEAP_ARRAY_RETURN_NULL(jchar, s_len + 1, mtInternal);  // add one for zero termination | 
|---|
| 3218 | /* JNI Specification states return NULL on OOM */ | 
|---|
| 3219 | if (ret != NULL) { | 
|---|
| 3220 | for (int i = 0; i < s_len; i++) { | 
|---|
| 3221 | ret[i] = ((jchar) s_value->byte_at(i)) & 0xff; | 
|---|
| 3222 | } | 
|---|
| 3223 | ret[s_len] = 0; | 
|---|
| 3224 | } | 
|---|
| 3225 | } | 
|---|
| 3226 | HOTSPOT_JNI_GETSTRINGCRITICAL_RETURN((uint16_t *) ret); | 
|---|
| 3227 | return ret; | 
|---|
| 3228 | JNI_END | 
|---|
| 3229 |  | 
|---|
| 3230 |  | 
|---|
| 3231 | JNI_ENTRY(void, jni_ReleaseStringCritical(JNIEnv *env, jstring str, const jchar *chars)) | 
|---|
| 3232 | JNIWrapper( "ReleaseStringCritical"); | 
|---|
| 3233 | HOTSPOT_JNI_RELEASESTRINGCRITICAL_ENTRY(env, str, (uint16_t *) chars); | 
|---|
| 3234 | // The str and chars arguments are ignored for UTF16 strings | 
|---|
| 3235 | oop s = JNIHandles::resolve_non_null(str); | 
|---|
| 3236 | bool is_latin1 = java_lang_String::is_latin1(s); | 
|---|
| 3237 | if (is_latin1) { | 
|---|
| 3238 | // For latin1 string, free jchar array allocated by earlier call to GetStringCritical. | 
|---|
| 3239 | // This assumes that ReleaseStringCritical bookends GetStringCritical. | 
|---|
| 3240 | FREE_C_HEAP_ARRAY(jchar, chars); | 
|---|
| 3241 | } | 
|---|
| 3242 | unlock_gc_or_unpin_object(thread, str); | 
|---|
| 3243 | HOTSPOT_JNI_RELEASESTRINGCRITICAL_RETURN(); | 
|---|
| 3244 | JNI_END | 
|---|
| 3245 |  | 
|---|
| 3246 |  | 
|---|
| 3247 | JNI_ENTRY(jweak, jni_NewWeakGlobalRef(JNIEnv *env, jobject ref)) | 
|---|
| 3248 | JNIWrapper( "jni_NewWeakGlobalRef"); | 
|---|
| 3249 | HOTSPOT_JNI_NEWWEAKGLOBALREF_ENTRY(env, ref); | 
|---|
| 3250 | Handle ref_handle(thread, JNIHandles::resolve(ref)); | 
|---|
| 3251 | jweak ret = JNIHandles::make_weak_global(ref_handle); | 
|---|
| 3252 | HOTSPOT_JNI_NEWWEAKGLOBALREF_RETURN(ret); | 
|---|
| 3253 | return ret; | 
|---|
| 3254 | JNI_END | 
|---|
| 3255 |  | 
|---|
| 3256 | // Must be JNI_ENTRY (with HandleMark) | 
|---|
| 3257 | JNI_ENTRY(void, jni_DeleteWeakGlobalRef(JNIEnv *env, jweak ref)) | 
|---|
| 3258 | JNIWrapper( "jni_DeleteWeakGlobalRef"); | 
|---|
| 3259 | HOTSPOT_JNI_DELETEWEAKGLOBALREF_ENTRY(env, ref); | 
|---|
| 3260 | JNIHandles::destroy_weak_global(ref); | 
|---|
| 3261 | HOTSPOT_JNI_DELETEWEAKGLOBALREF_RETURN(); | 
|---|
| 3262 | JNI_END | 
|---|
| 3263 |  | 
|---|
| 3264 |  | 
|---|
| 3265 | JNI_QUICK_ENTRY(jboolean, jni_ExceptionCheck(JNIEnv *env)) | 
|---|
| 3266 | JNIWrapper( "jni_ExceptionCheck"); | 
|---|
| 3267 | HOTSPOT_JNI_EXCEPTIONCHECK_ENTRY(env); | 
|---|
| 3268 | jni_check_async_exceptions(thread); | 
|---|
| 3269 | jboolean ret = (thread->has_pending_exception()) ? JNI_TRUE : JNI_FALSE; | 
|---|
| 3270 | HOTSPOT_JNI_EXCEPTIONCHECK_RETURN(ret); | 
|---|
| 3271 | return ret; | 
|---|
| 3272 | JNI_END | 
|---|
| 3273 |  | 
|---|
| 3274 |  | 
|---|
| 3275 | // Initialization state for three routines below relating to | 
|---|
| 3276 | // java.nio.DirectBuffers | 
|---|
| 3277 | static          int directBufferSupportInitializeStarted = 0; | 
|---|
| 3278 | static volatile int directBufferSupportInitializeEnded   = 0; | 
|---|
| 3279 | static volatile int directBufferSupportInitializeFailed  = 0; | 
|---|
| 3280 | static jclass    bufferClass                 = NULL; | 
|---|
| 3281 | static jclass    directBufferClass           = NULL; | 
|---|
| 3282 | static jclass    directByteBufferClass       = NULL; | 
|---|
| 3283 | static jmethodID directByteBufferConstructor = NULL; | 
|---|
| 3284 | static jfieldID  directBufferAddressField    = NULL; | 
|---|
| 3285 | static jfieldID  bufferCapacityField         = NULL; | 
|---|
| 3286 |  | 
|---|
| 3287 | static jclass lookupOne(JNIEnv* env, const char* name, TRAPS) { | 
|---|
| 3288 | Handle loader;            // null (bootstrap) loader | 
|---|
| 3289 | Handle protection_domain; // null protection domain | 
|---|
| 3290 |  | 
|---|
| 3291 | TempNewSymbol sym = SymbolTable::new_symbol(name); | 
|---|
| 3292 | jclass result =  find_class_from_class_loader(env, sym, true, loader, protection_domain, true, CHECK_NULL); | 
|---|
| 3293 |  | 
|---|
| 3294 | if (log_is_enabled(Debug, class, resolve) && result != NULL) { | 
|---|
| 3295 | trace_class_resolution(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(result))); | 
|---|
| 3296 | } | 
|---|
| 3297 | return result; | 
|---|
| 3298 | } | 
|---|
| 3299 |  | 
|---|
| 3300 | // These lookups are done with the NULL (bootstrap) ClassLoader to | 
|---|
| 3301 | // circumvent any security checks that would be done by jni_FindClass. | 
|---|
| 3302 | JNI_ENTRY(bool, lookupDirectBufferClasses(JNIEnv* env)) | 
|---|
| 3303 | { | 
|---|
| 3304 | if ((bufferClass           = lookupOne(env, "java/nio/Buffer", thread))           == NULL) { return false; } | 
|---|
| 3305 | if ((directBufferClass     = lookupOne(env, "sun/nio/ch/DirectBuffer", thread))   == NULL) { return false; } | 
|---|
| 3306 | if ((directByteBufferClass = lookupOne(env, "java/nio/DirectByteBuffer", thread)) == NULL) { return false; } | 
|---|
| 3307 | return true; | 
|---|
| 3308 | } | 
|---|
| 3309 | JNI_END | 
|---|
| 3310 |  | 
|---|
| 3311 |  | 
|---|
| 3312 | static bool initializeDirectBufferSupport(JNIEnv* env, JavaThread* thread) { | 
|---|
| 3313 | if (directBufferSupportInitializeFailed) { | 
|---|
| 3314 | return false; | 
|---|
| 3315 | } | 
|---|
| 3316 |  | 
|---|
| 3317 | if (Atomic::cmpxchg(1, &directBufferSupportInitializeStarted, 0) == 0) { | 
|---|
| 3318 | if (!lookupDirectBufferClasses(env)) { | 
|---|
| 3319 | directBufferSupportInitializeFailed = 1; | 
|---|
| 3320 | return false; | 
|---|
| 3321 | } | 
|---|
| 3322 |  | 
|---|
| 3323 | // Make global references for these | 
|---|
| 3324 | bufferClass           = (jclass) env->NewGlobalRef(bufferClass); | 
|---|
| 3325 | directBufferClass     = (jclass) env->NewGlobalRef(directBufferClass); | 
|---|
| 3326 | directByteBufferClass = (jclass) env->NewGlobalRef(directByteBufferClass); | 
|---|
| 3327 |  | 
|---|
| 3328 | // Get needed field and method IDs | 
|---|
| 3329 | directByteBufferConstructor = env->GetMethodID(directByteBufferClass, "<init>", "(JI)V"); | 
|---|
| 3330 | if (env->ExceptionCheck()) { | 
|---|
| 3331 | env->ExceptionClear(); | 
|---|
| 3332 | directBufferSupportInitializeFailed = 1; | 
|---|
| 3333 | return false; | 
|---|
| 3334 | } | 
|---|
| 3335 | directBufferAddressField    = env->GetFieldID(bufferClass, "address", "J"); | 
|---|
| 3336 | if (env->ExceptionCheck()) { | 
|---|
| 3337 | env->ExceptionClear(); | 
|---|
| 3338 | directBufferSupportInitializeFailed = 1; | 
|---|
| 3339 | return false; | 
|---|
| 3340 | } | 
|---|
| 3341 | bufferCapacityField         = env->GetFieldID(bufferClass, "capacity", "I"); | 
|---|
| 3342 | if (env->ExceptionCheck()) { | 
|---|
| 3343 | env->ExceptionClear(); | 
|---|
| 3344 | directBufferSupportInitializeFailed = 1; | 
|---|
| 3345 | return false; | 
|---|
| 3346 | } | 
|---|
| 3347 |  | 
|---|
| 3348 | if ((directByteBufferConstructor == NULL) || | 
|---|
| 3349 | (directBufferAddressField    == NULL) || | 
|---|
| 3350 | (bufferCapacityField         == NULL)) { | 
|---|
| 3351 | directBufferSupportInitializeFailed = 1; | 
|---|
| 3352 | return false; | 
|---|
| 3353 | } | 
|---|
| 3354 |  | 
|---|
| 3355 | directBufferSupportInitializeEnded = 1; | 
|---|
| 3356 | } else { | 
|---|
| 3357 | while (!directBufferSupportInitializeEnded && !directBufferSupportInitializeFailed) { | 
|---|
| 3358 | os::naked_yield(); | 
|---|
| 3359 | } | 
|---|
| 3360 | } | 
|---|
| 3361 |  | 
|---|
| 3362 | return !directBufferSupportInitializeFailed; | 
|---|
| 3363 | } | 
|---|
| 3364 |  | 
|---|
| 3365 | extern "C"jobject JNICALL jni_NewDirectByteBuffer(JNIEnv *env, void* address, jlong capacity) | 
|---|
| 3366 | { | 
|---|
| 3367 | // thread_from_jni_environment() will block if VM is gone. | 
|---|
| 3368 | JavaThread* thread = JavaThread::thread_from_jni_environment(env); | 
|---|
| 3369 |  | 
|---|
| 3370 | JNIWrapper( "jni_NewDirectByteBuffer"); | 
|---|
| 3371 | HOTSPOT_JNI_NEWDIRECTBYTEBUFFER_ENTRY(env, address, capacity); | 
|---|
| 3372 |  | 
|---|
| 3373 | if (!directBufferSupportInitializeEnded) { | 
|---|
| 3374 | if (!initializeDirectBufferSupport(env, thread)) { | 
|---|
| 3375 | HOTSPOT_JNI_NEWDIRECTBYTEBUFFER_RETURN(NULL); | 
|---|
| 3376 | return NULL; | 
|---|
| 3377 | } | 
|---|
| 3378 | } | 
|---|
| 3379 |  | 
|---|
| 3380 | // Being paranoid about accidental sign extension on address | 
|---|
| 3381 | jlong addr = (jlong) ((uintptr_t) address); | 
|---|
| 3382 | // NOTE that package-private DirectByteBuffer constructor currently | 
|---|
| 3383 | // takes int capacity | 
|---|
| 3384 | jint  cap  = (jint)  capacity; | 
|---|
| 3385 | jobject ret = env->NewObject(directByteBufferClass, directByteBufferConstructor, addr, cap); | 
|---|
| 3386 | HOTSPOT_JNI_NEWDIRECTBYTEBUFFER_RETURN(ret); | 
|---|
| 3387 | return ret; | 
|---|
| 3388 | } | 
|---|
| 3389 |  | 
|---|
| 3390 | DT_RETURN_MARK_DECL(GetDirectBufferAddress, void* | 
|---|
| 3391 | , HOTSPOT_JNI_GETDIRECTBUFFERADDRESS_RETURN((void*) _ret_ref)); | 
|---|
| 3392 |  | 
|---|
| 3393 | extern "C"void* JNICALL jni_GetDirectBufferAddress(JNIEnv *env, jobject buf) | 
|---|
| 3394 | { | 
|---|
| 3395 | // thread_from_jni_environment() will block if VM is gone. | 
|---|
| 3396 | JavaThread* thread = JavaThread::thread_from_jni_environment(env); | 
|---|
| 3397 |  | 
|---|
| 3398 | JNIWrapper( "jni_GetDirectBufferAddress"); | 
|---|
| 3399 | HOTSPOT_JNI_GETDIRECTBUFFERADDRESS_ENTRY(env, buf); | 
|---|
| 3400 | void* ret = NULL; | 
|---|
| 3401 | DT_RETURN_MARK(GetDirectBufferAddress, void*, (const void*&)ret); | 
|---|
| 3402 |  | 
|---|
| 3403 | if (!directBufferSupportInitializeEnded) { | 
|---|
| 3404 | if (!initializeDirectBufferSupport(env, thread)) { | 
|---|
| 3405 | return 0; | 
|---|
| 3406 | } | 
|---|
| 3407 | } | 
|---|
| 3408 |  | 
|---|
| 3409 | if ((buf != NULL) && (!env->IsInstanceOf(buf, directBufferClass))) { | 
|---|
| 3410 | return 0; | 
|---|
| 3411 | } | 
|---|
| 3412 |  | 
|---|
| 3413 | ret = (void*)(intptr_t)env->GetLongField(buf, directBufferAddressField); | 
|---|
| 3414 | return ret; | 
|---|
| 3415 | } | 
|---|
| 3416 |  | 
|---|
| 3417 | DT_RETURN_MARK_DECL(GetDirectBufferCapacity, jlong | 
|---|
| 3418 | , HOTSPOT_JNI_GETDIRECTBUFFERCAPACITY_RETURN(_ret_ref)); | 
|---|
| 3419 |  | 
|---|
| 3420 | extern "C"jlong JNICALL jni_GetDirectBufferCapacity(JNIEnv *env, jobject buf) | 
|---|
| 3421 | { | 
|---|
| 3422 | // thread_from_jni_environment() will block if VM is gone. | 
|---|
| 3423 | JavaThread* thread = JavaThread::thread_from_jni_environment(env); | 
|---|
| 3424 |  | 
|---|
| 3425 | JNIWrapper( "jni_GetDirectBufferCapacity"); | 
|---|
| 3426 | HOTSPOT_JNI_GETDIRECTBUFFERCAPACITY_ENTRY(env, buf); | 
|---|
| 3427 | jlong ret = -1; | 
|---|
| 3428 | DT_RETURN_MARK(GetDirectBufferCapacity, jlong, (const jlong&)ret); | 
|---|
| 3429 |  | 
|---|
| 3430 | if (!directBufferSupportInitializeEnded) { | 
|---|
| 3431 | if (!initializeDirectBufferSupport(env, thread)) { | 
|---|
| 3432 | ret = 0; | 
|---|
| 3433 | return ret; | 
|---|
| 3434 | } | 
|---|
| 3435 | } | 
|---|
| 3436 |  | 
|---|
| 3437 | if (buf == NULL) { | 
|---|
| 3438 | return -1; | 
|---|
| 3439 | } | 
|---|
| 3440 |  | 
|---|
| 3441 | if (!env->IsInstanceOf(buf, directBufferClass)) { | 
|---|
| 3442 | return -1; | 
|---|
| 3443 | } | 
|---|
| 3444 |  | 
|---|
| 3445 | // NOTE that capacity is currently an int in the implementation | 
|---|
| 3446 | ret = env->GetIntField(buf, bufferCapacityField); | 
|---|
| 3447 | return ret; | 
|---|
| 3448 | } | 
|---|
| 3449 |  | 
|---|
| 3450 |  | 
|---|
| 3451 | JNI_LEAF(jint, jni_GetVersion(JNIEnv *env)) | 
|---|
| 3452 | JNIWrapper( "GetVersion"); | 
|---|
| 3453 | HOTSPOT_JNI_GETVERSION_ENTRY(env); | 
|---|
| 3454 | HOTSPOT_JNI_GETVERSION_RETURN(CurrentVersion); | 
|---|
| 3455 | return CurrentVersion; | 
|---|
| 3456 | JNI_END | 
|---|
| 3457 |  | 
|---|
| 3458 | extern struct JavaVM_ main_vm; | 
|---|
| 3459 |  | 
|---|
| 3460 | JNI_LEAF(jint, jni_GetJavaVM(JNIEnv *env, JavaVM **vm)) | 
|---|
| 3461 | JNIWrapper( "jni_GetJavaVM"); | 
|---|
| 3462 | HOTSPOT_JNI_GETJAVAVM_ENTRY(env, (void **) vm); | 
|---|
| 3463 | *vm  = (JavaVM *)(&main_vm); | 
|---|
| 3464 | HOTSPOT_JNI_GETJAVAVM_RETURN(JNI_OK); | 
|---|
| 3465 | return JNI_OK; | 
|---|
| 3466 | JNI_END | 
|---|
| 3467 |  | 
|---|
| 3468 |  | 
|---|
| 3469 | JNI_ENTRY(jobject, jni_GetModule(JNIEnv* env, jclass clazz)) | 
|---|
| 3470 | JNIWrapper( "GetModule"); | 
|---|
| 3471 | return Modules::get_module(clazz, THREAD); | 
|---|
| 3472 | JNI_END | 
|---|
| 3473 |  | 
|---|
| 3474 |  | 
|---|
| 3475 | // Structure containing all jni functions | 
|---|
| 3476 | struct JNINativeInterface_ jni_NativeInterface = { | 
|---|
| 3477 | NULL, | 
|---|
| 3478 | NULL, | 
|---|
| 3479 | NULL, | 
|---|
| 3480 |  | 
|---|
| 3481 | NULL, | 
|---|
| 3482 |  | 
|---|
| 3483 | jni_GetVersion, | 
|---|
| 3484 |  | 
|---|
| 3485 | jni_DefineClass, | 
|---|
| 3486 | jni_FindClass, | 
|---|
| 3487 |  | 
|---|
| 3488 | jni_FromReflectedMethod, | 
|---|
| 3489 | jni_FromReflectedField, | 
|---|
| 3490 |  | 
|---|
| 3491 | jni_ToReflectedMethod, | 
|---|
| 3492 |  | 
|---|
| 3493 | jni_GetSuperclass, | 
|---|
| 3494 | jni_IsAssignableFrom, | 
|---|
| 3495 |  | 
|---|
| 3496 | jni_ToReflectedField, | 
|---|
| 3497 |  | 
|---|
| 3498 | jni_Throw, | 
|---|
| 3499 | jni_ThrowNew, | 
|---|
| 3500 | jni_ExceptionOccurred, | 
|---|
| 3501 | jni_ExceptionDescribe, | 
|---|
| 3502 | jni_ExceptionClear, | 
|---|
| 3503 | jni_FatalError, | 
|---|
| 3504 |  | 
|---|
| 3505 | jni_PushLocalFrame, | 
|---|
| 3506 | jni_PopLocalFrame, | 
|---|
| 3507 |  | 
|---|
| 3508 | jni_NewGlobalRef, | 
|---|
| 3509 | jni_DeleteGlobalRef, | 
|---|
| 3510 | jni_DeleteLocalRef, | 
|---|
| 3511 | jni_IsSameObject, | 
|---|
| 3512 |  | 
|---|
| 3513 | jni_NewLocalRef, | 
|---|
| 3514 | jni_EnsureLocalCapacity, | 
|---|
| 3515 |  | 
|---|
| 3516 | jni_AllocObject, | 
|---|
| 3517 | jni_NewObject, | 
|---|
| 3518 | jni_NewObjectV, | 
|---|
| 3519 | jni_NewObjectA, | 
|---|
| 3520 |  | 
|---|
| 3521 | jni_GetObjectClass, | 
|---|
| 3522 | jni_IsInstanceOf, | 
|---|
| 3523 |  | 
|---|
| 3524 | jni_GetMethodID, | 
|---|
| 3525 |  | 
|---|
| 3526 | jni_CallObjectMethod, | 
|---|
| 3527 | jni_CallObjectMethodV, | 
|---|
| 3528 | jni_CallObjectMethodA, | 
|---|
| 3529 | jni_CallBooleanMethod, | 
|---|
| 3530 | jni_CallBooleanMethodV, | 
|---|
| 3531 | jni_CallBooleanMethodA, | 
|---|
| 3532 | jni_CallByteMethod, | 
|---|
| 3533 | jni_CallByteMethodV, | 
|---|
| 3534 | jni_CallByteMethodA, | 
|---|
| 3535 | jni_CallCharMethod, | 
|---|
| 3536 | jni_CallCharMethodV, | 
|---|
| 3537 | jni_CallCharMethodA, | 
|---|
| 3538 | jni_CallShortMethod, | 
|---|
| 3539 | jni_CallShortMethodV, | 
|---|
| 3540 | jni_CallShortMethodA, | 
|---|
| 3541 | jni_CallIntMethod, | 
|---|
| 3542 | jni_CallIntMethodV, | 
|---|
| 3543 | jni_CallIntMethodA, | 
|---|
| 3544 | jni_CallLongMethod, | 
|---|
| 3545 | jni_CallLongMethodV, | 
|---|
| 3546 | jni_CallLongMethodA, | 
|---|
| 3547 | jni_CallFloatMethod, | 
|---|
| 3548 | jni_CallFloatMethodV, | 
|---|
| 3549 | jni_CallFloatMethodA, | 
|---|
| 3550 | jni_CallDoubleMethod, | 
|---|
| 3551 | jni_CallDoubleMethodV, | 
|---|
| 3552 | jni_CallDoubleMethodA, | 
|---|
| 3553 | jni_CallVoidMethod, | 
|---|
| 3554 | jni_CallVoidMethodV, | 
|---|
| 3555 | jni_CallVoidMethodA, | 
|---|
| 3556 |  | 
|---|
| 3557 | jni_CallNonvirtualObjectMethod, | 
|---|
| 3558 | jni_CallNonvirtualObjectMethodV, | 
|---|
| 3559 | jni_CallNonvirtualObjectMethodA, | 
|---|
| 3560 | jni_CallNonvirtualBooleanMethod, | 
|---|
| 3561 | jni_CallNonvirtualBooleanMethodV, | 
|---|
| 3562 | jni_CallNonvirtualBooleanMethodA, | 
|---|
| 3563 | jni_CallNonvirtualByteMethod, | 
|---|
| 3564 | jni_CallNonvirtualByteMethodV, | 
|---|
| 3565 | jni_CallNonvirtualByteMethodA, | 
|---|
| 3566 | jni_CallNonvirtualCharMethod, | 
|---|
| 3567 | jni_CallNonvirtualCharMethodV, | 
|---|
| 3568 | jni_CallNonvirtualCharMethodA, | 
|---|
| 3569 | jni_CallNonvirtualShortMethod, | 
|---|
| 3570 | jni_CallNonvirtualShortMethodV, | 
|---|
| 3571 | jni_CallNonvirtualShortMethodA, | 
|---|
| 3572 | jni_CallNonvirtualIntMethod, | 
|---|
| 3573 | jni_CallNonvirtualIntMethodV, | 
|---|
| 3574 | jni_CallNonvirtualIntMethodA, | 
|---|
| 3575 | jni_CallNonvirtualLongMethod, | 
|---|
| 3576 | jni_CallNonvirtualLongMethodV, | 
|---|
| 3577 | jni_CallNonvirtualLongMethodA, | 
|---|
| 3578 | jni_CallNonvirtualFloatMethod, | 
|---|
| 3579 | jni_CallNonvirtualFloatMethodV, | 
|---|
| 3580 | jni_CallNonvirtualFloatMethodA, | 
|---|
| 3581 | jni_CallNonvirtualDoubleMethod, | 
|---|
| 3582 | jni_CallNonvirtualDoubleMethodV, | 
|---|
| 3583 | jni_CallNonvirtualDoubleMethodA, | 
|---|
| 3584 | jni_CallNonvirtualVoidMethod, | 
|---|
| 3585 | jni_CallNonvirtualVoidMethodV, | 
|---|
| 3586 | jni_CallNonvirtualVoidMethodA, | 
|---|
| 3587 |  | 
|---|
| 3588 | jni_GetFieldID, | 
|---|
| 3589 |  | 
|---|
| 3590 | jni_GetObjectField, | 
|---|
| 3591 | jni_GetBooleanField, | 
|---|
| 3592 | jni_GetByteField, | 
|---|
| 3593 | jni_GetCharField, | 
|---|
| 3594 | jni_GetShortField, | 
|---|
| 3595 | jni_GetIntField, | 
|---|
| 3596 | jni_GetLongField, | 
|---|
| 3597 | jni_GetFloatField, | 
|---|
| 3598 | jni_GetDoubleField, | 
|---|
| 3599 |  | 
|---|
| 3600 | jni_SetObjectField, | 
|---|
| 3601 | jni_SetBooleanField, | 
|---|
| 3602 | jni_SetByteField, | 
|---|
| 3603 | jni_SetCharField, | 
|---|
| 3604 | jni_SetShortField, | 
|---|
| 3605 | jni_SetIntField, | 
|---|
| 3606 | jni_SetLongField, | 
|---|
| 3607 | jni_SetFloatField, | 
|---|
| 3608 | jni_SetDoubleField, | 
|---|
| 3609 |  | 
|---|
| 3610 | jni_GetStaticMethodID, | 
|---|
| 3611 |  | 
|---|
| 3612 | jni_CallStaticObjectMethod, | 
|---|
| 3613 | jni_CallStaticObjectMethodV, | 
|---|
| 3614 | jni_CallStaticObjectMethodA, | 
|---|
| 3615 | jni_CallStaticBooleanMethod, | 
|---|
| 3616 | jni_CallStaticBooleanMethodV, | 
|---|
| 3617 | jni_CallStaticBooleanMethodA, | 
|---|
| 3618 | jni_CallStaticByteMethod, | 
|---|
| 3619 | jni_CallStaticByteMethodV, | 
|---|
| 3620 | jni_CallStaticByteMethodA, | 
|---|
| 3621 | jni_CallStaticCharMethod, | 
|---|
| 3622 | jni_CallStaticCharMethodV, | 
|---|
| 3623 | jni_CallStaticCharMethodA, | 
|---|
| 3624 | jni_CallStaticShortMethod, | 
|---|
| 3625 | jni_CallStaticShortMethodV, | 
|---|
| 3626 | jni_CallStaticShortMethodA, | 
|---|
| 3627 | jni_CallStaticIntMethod, | 
|---|
| 3628 | jni_CallStaticIntMethodV, | 
|---|
| 3629 | jni_CallStaticIntMethodA, | 
|---|
| 3630 | jni_CallStaticLongMethod, | 
|---|
| 3631 | jni_CallStaticLongMethodV, | 
|---|
| 3632 | jni_CallStaticLongMethodA, | 
|---|
| 3633 | jni_CallStaticFloatMethod, | 
|---|
| 3634 | jni_CallStaticFloatMethodV, | 
|---|
| 3635 | jni_CallStaticFloatMethodA, | 
|---|
| 3636 | jni_CallStaticDoubleMethod, | 
|---|
| 3637 | jni_CallStaticDoubleMethodV, | 
|---|
| 3638 | jni_CallStaticDoubleMethodA, | 
|---|
| 3639 | jni_CallStaticVoidMethod, | 
|---|
| 3640 | jni_CallStaticVoidMethodV, | 
|---|
| 3641 | jni_CallStaticVoidMethodA, | 
|---|
| 3642 |  | 
|---|
| 3643 | jni_GetStaticFieldID, | 
|---|
| 3644 |  | 
|---|
| 3645 | jni_GetStaticObjectField, | 
|---|
| 3646 | jni_GetStaticBooleanField, | 
|---|
| 3647 | jni_GetStaticByteField, | 
|---|
| 3648 | jni_GetStaticCharField, | 
|---|
| 3649 | jni_GetStaticShortField, | 
|---|
| 3650 | jni_GetStaticIntField, | 
|---|
| 3651 | jni_GetStaticLongField, | 
|---|
| 3652 | jni_GetStaticFloatField, | 
|---|
| 3653 | jni_GetStaticDoubleField, | 
|---|
| 3654 |  | 
|---|
| 3655 | jni_SetStaticObjectField, | 
|---|
| 3656 | jni_SetStaticBooleanField, | 
|---|
| 3657 | jni_SetStaticByteField, | 
|---|
| 3658 | jni_SetStaticCharField, | 
|---|
| 3659 | jni_SetStaticShortField, | 
|---|
| 3660 | jni_SetStaticIntField, | 
|---|
| 3661 | jni_SetStaticLongField, | 
|---|
| 3662 | jni_SetStaticFloatField, | 
|---|
| 3663 | jni_SetStaticDoubleField, | 
|---|
| 3664 |  | 
|---|
| 3665 | jni_NewString, | 
|---|
| 3666 | jni_GetStringLength, | 
|---|
| 3667 | jni_GetStringChars, | 
|---|
| 3668 | jni_ReleaseStringChars, | 
|---|
| 3669 |  | 
|---|
| 3670 | jni_NewStringUTF, | 
|---|
| 3671 | jni_GetStringUTFLength, | 
|---|
| 3672 | jni_GetStringUTFChars, | 
|---|
| 3673 | jni_ReleaseStringUTFChars, | 
|---|
| 3674 |  | 
|---|
| 3675 | jni_GetArrayLength, | 
|---|
| 3676 |  | 
|---|
| 3677 | jni_NewObjectArray, | 
|---|
| 3678 | jni_GetObjectArrayElement, | 
|---|
| 3679 | jni_SetObjectArrayElement, | 
|---|
| 3680 |  | 
|---|
| 3681 | jni_NewBooleanArray, | 
|---|
| 3682 | jni_NewByteArray, | 
|---|
| 3683 | jni_NewCharArray, | 
|---|
| 3684 | jni_NewShortArray, | 
|---|
| 3685 | jni_NewIntArray, | 
|---|
| 3686 | jni_NewLongArray, | 
|---|
| 3687 | jni_NewFloatArray, | 
|---|
| 3688 | jni_NewDoubleArray, | 
|---|
| 3689 |  | 
|---|
| 3690 | jni_GetBooleanArrayElements, | 
|---|
| 3691 | jni_GetByteArrayElements, | 
|---|
| 3692 | jni_GetCharArrayElements, | 
|---|
| 3693 | jni_GetShortArrayElements, | 
|---|
| 3694 | jni_GetIntArrayElements, | 
|---|
| 3695 | jni_GetLongArrayElements, | 
|---|
| 3696 | jni_GetFloatArrayElements, | 
|---|
| 3697 | jni_GetDoubleArrayElements, | 
|---|
| 3698 |  | 
|---|
| 3699 | jni_ReleaseBooleanArrayElements, | 
|---|
| 3700 | jni_ReleaseByteArrayElements, | 
|---|
| 3701 | jni_ReleaseCharArrayElements, | 
|---|
| 3702 | jni_ReleaseShortArrayElements, | 
|---|
| 3703 | jni_ReleaseIntArrayElements, | 
|---|
| 3704 | jni_ReleaseLongArrayElements, | 
|---|
| 3705 | jni_ReleaseFloatArrayElements, | 
|---|
| 3706 | jni_ReleaseDoubleArrayElements, | 
|---|
| 3707 |  | 
|---|
| 3708 | jni_GetBooleanArrayRegion, | 
|---|
| 3709 | jni_GetByteArrayRegion, | 
|---|
| 3710 | jni_GetCharArrayRegion, | 
|---|
| 3711 | jni_GetShortArrayRegion, | 
|---|
| 3712 | jni_GetIntArrayRegion, | 
|---|
| 3713 | jni_GetLongArrayRegion, | 
|---|
| 3714 | jni_GetFloatArrayRegion, | 
|---|
| 3715 | jni_GetDoubleArrayRegion, | 
|---|
| 3716 |  | 
|---|
| 3717 | jni_SetBooleanArrayRegion, | 
|---|
| 3718 | jni_SetByteArrayRegion, | 
|---|
| 3719 | jni_SetCharArrayRegion, | 
|---|
| 3720 | jni_SetShortArrayRegion, | 
|---|
| 3721 | jni_SetIntArrayRegion, | 
|---|
| 3722 | jni_SetLongArrayRegion, | 
|---|
| 3723 | jni_SetFloatArrayRegion, | 
|---|
| 3724 | jni_SetDoubleArrayRegion, | 
|---|
| 3725 |  | 
|---|
| 3726 | jni_RegisterNatives, | 
|---|
| 3727 | jni_UnregisterNatives, | 
|---|
| 3728 |  | 
|---|
| 3729 | jni_MonitorEnter, | 
|---|
| 3730 | jni_MonitorExit, | 
|---|
| 3731 |  | 
|---|
| 3732 | jni_GetJavaVM, | 
|---|
| 3733 |  | 
|---|
| 3734 | jni_GetStringRegion, | 
|---|
| 3735 | jni_GetStringUTFRegion, | 
|---|
| 3736 |  | 
|---|
| 3737 | jni_GetPrimitiveArrayCritical, | 
|---|
| 3738 | jni_ReleasePrimitiveArrayCritical, | 
|---|
| 3739 |  | 
|---|
| 3740 | jni_GetStringCritical, | 
|---|
| 3741 | jni_ReleaseStringCritical, | 
|---|
| 3742 |  | 
|---|
| 3743 | jni_NewWeakGlobalRef, | 
|---|
| 3744 | jni_DeleteWeakGlobalRef, | 
|---|
| 3745 |  | 
|---|
| 3746 | jni_ExceptionCheck, | 
|---|
| 3747 |  | 
|---|
| 3748 | jni_NewDirectByteBuffer, | 
|---|
| 3749 | jni_GetDirectBufferAddress, | 
|---|
| 3750 | jni_GetDirectBufferCapacity, | 
|---|
| 3751 |  | 
|---|
| 3752 | // New 1_6 features | 
|---|
| 3753 |  | 
|---|
| 3754 | jni_GetObjectRefType, | 
|---|
| 3755 |  | 
|---|
| 3756 | // Module features | 
|---|
| 3757 |  | 
|---|
| 3758 | jni_GetModule | 
|---|
| 3759 | }; | 
|---|
| 3760 |  | 
|---|
| 3761 |  | 
|---|
| 3762 | // For jvmti use to modify jni function table. | 
|---|
| 3763 | // Java threads in native contiues to run until it is transitioned | 
|---|
| 3764 | // to VM at safepoint. Before the transition or before it is blocked | 
|---|
| 3765 | // for safepoint it may access jni function table. VM could crash if | 
|---|
| 3766 | // any java thread access the jni function table in the middle of memcpy. | 
|---|
| 3767 | // To avoid this each function pointers are copied automically. | 
|---|
| 3768 | void copy_jni_function_table(const struct JNINativeInterface_ *new_jni_NativeInterface) { | 
|---|
| 3769 | assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); | 
|---|
| 3770 | intptr_t *a = (intptr_t *) jni_functions(); | 
|---|
| 3771 | intptr_t *b = (intptr_t *) new_jni_NativeInterface; | 
|---|
| 3772 | for (uint i=0; i <  sizeof(struct JNINativeInterface_)/sizeof(void *); i++) { | 
|---|
| 3773 | Atomic::store(*b++, a++); | 
|---|
| 3774 | } | 
|---|
| 3775 | } | 
|---|
| 3776 |  | 
|---|
| 3777 | void quicken_jni_functions() { | 
|---|
| 3778 | // Replace Get<Primitive>Field with fast versions | 
|---|
| 3779 | if (UseFastJNIAccessors && !JvmtiExport::can_post_field_access() | 
|---|
| 3780 | && !VerifyJNIFields && !CountJNICalls && !CheckJNICalls) { | 
|---|
| 3781 | address func; | 
|---|
| 3782 | func = JNI_FastGetField::generate_fast_get_boolean_field(); | 
|---|
| 3783 | if (func != (address)-1) { | 
|---|
| 3784 | jni_NativeInterface.GetBooleanField = (GetBooleanField_t)func; | 
|---|
| 3785 | } | 
|---|
| 3786 | func = JNI_FastGetField::generate_fast_get_byte_field(); | 
|---|
| 3787 | if (func != (address)-1) { | 
|---|
| 3788 | jni_NativeInterface.GetByteField = (GetByteField_t)func; | 
|---|
| 3789 | } | 
|---|
| 3790 | func = JNI_FastGetField::generate_fast_get_char_field(); | 
|---|
| 3791 | if (func != (address)-1) { | 
|---|
| 3792 | jni_NativeInterface.GetCharField = (GetCharField_t)func; | 
|---|
| 3793 | } | 
|---|
| 3794 | func = JNI_FastGetField::generate_fast_get_short_field(); | 
|---|
| 3795 | if (func != (address)-1) { | 
|---|
| 3796 | jni_NativeInterface.GetShortField = (GetShortField_t)func; | 
|---|
| 3797 | } | 
|---|
| 3798 | func = JNI_FastGetField::generate_fast_get_int_field(); | 
|---|
| 3799 | if (func != (address)-1) { | 
|---|
| 3800 | jni_NativeInterface.GetIntField = (GetIntField_t)func; | 
|---|
| 3801 | } | 
|---|
| 3802 | func = JNI_FastGetField::generate_fast_get_long_field(); | 
|---|
| 3803 | if (func != (address)-1) { | 
|---|
| 3804 | jni_NativeInterface.GetLongField = (GetLongField_t)func; | 
|---|
| 3805 | } | 
|---|
| 3806 | func = JNI_FastGetField::generate_fast_get_float_field(); | 
|---|
| 3807 | if (func != (address)-1) { | 
|---|
| 3808 | jni_NativeInterface.GetFloatField = (GetFloatField_t)func; | 
|---|
| 3809 | } | 
|---|
| 3810 | func = JNI_FastGetField::generate_fast_get_double_field(); | 
|---|
| 3811 | if (func != (address)-1) { | 
|---|
| 3812 | jni_NativeInterface.GetDoubleField = (GetDoubleField_t)func; | 
|---|
| 3813 | } | 
|---|
| 3814 | } | 
|---|
| 3815 | } | 
|---|
| 3816 |  | 
|---|
| 3817 | // Returns the function structure | 
|---|
| 3818 | struct JNINativeInterface_* jni_functions() { | 
|---|
| 3819 | #if INCLUDE_JNI_CHECK | 
|---|
| 3820 | if (CheckJNICalls) return jni_functions_check(); | 
|---|
| 3821 | #endif // INCLUDE_JNI_CHECK | 
|---|
| 3822 | return &jni_NativeInterface; | 
|---|
| 3823 | } | 
|---|
| 3824 |  | 
|---|
| 3825 | // Returns the function structure | 
|---|
| 3826 | struct JNINativeInterface_* jni_functions_nocheck() { | 
|---|
| 3827 | return &jni_NativeInterface; | 
|---|
| 3828 | } | 
|---|
| 3829 |  | 
|---|
| 3830 | static void post_thread_start_event(const JavaThread* jt) { | 
|---|
| 3831 | assert(jt != NULL, "invariant"); | 
|---|
| 3832 | EventThreadStart event; | 
|---|
| 3833 | if (event.should_commit()) { | 
|---|
| 3834 | event.set_thread(JFR_THREAD_ID(jt)); | 
|---|
| 3835 | event.commit(); | 
|---|
| 3836 | } | 
|---|
| 3837 | } | 
|---|
| 3838 |  | 
|---|
| 3839 | // Invocation API | 
|---|
| 3840 |  | 
|---|
| 3841 |  | 
|---|
| 3842 | // Forward declaration | 
|---|
| 3843 | extern const struct JNIInvokeInterface_ jni_InvokeInterface; | 
|---|
| 3844 |  | 
|---|
| 3845 | // Global invocation API vars | 
|---|
| 3846 | volatile int vm_created = 0; | 
|---|
| 3847 | // Indicate whether it is safe to recreate VM | 
|---|
| 3848 | volatile int safe_to_recreate_vm = 1; | 
|---|
| 3849 | struct JavaVM_ main_vm = {&jni_InvokeInterface}; | 
|---|
| 3850 |  | 
|---|
| 3851 |  | 
|---|
| 3852 | #define JAVASTACKSIZE (400 * 1024)    /* Default size of a thread java stack */ | 
|---|
| 3853 | enum { VERIFY_NONE, VERIFY_REMOTE, VERIFY_ALL }; | 
|---|
| 3854 |  | 
|---|
| 3855 | DT_RETURN_MARK_DECL(GetDefaultJavaVMInitArgs, jint | 
|---|
| 3856 | , HOTSPOT_JNI_GETDEFAULTJAVAVMINITARGS_RETURN(_ret_ref)); | 
|---|
| 3857 |  | 
|---|
| 3858 | _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetDefaultJavaVMInitArgs(void *args_) { | 
|---|
| 3859 | HOTSPOT_JNI_GETDEFAULTJAVAVMINITARGS_ENTRY(args_); | 
|---|
| 3860 | JDK1_1InitArgs *args = (JDK1_1InitArgs *)args_; | 
|---|
| 3861 | jint ret = JNI_ERR; | 
|---|
| 3862 | DT_RETURN_MARK(GetDefaultJavaVMInitArgs, jint, (const jint&)ret); | 
|---|
| 3863 |  | 
|---|
| 3864 | if (Threads::is_supported_jni_version(args->version)) { | 
|---|
| 3865 | ret = JNI_OK; | 
|---|
| 3866 | } | 
|---|
| 3867 | // 1.1 style no longer supported in hotspot. | 
|---|
| 3868 | // According the JNI spec, we should update args->version on return. | 
|---|
| 3869 | // We also use the structure to communicate with launcher about default | 
|---|
| 3870 | // stack size. | 
|---|
| 3871 | if (args->version == JNI_VERSION_1_1) { | 
|---|
| 3872 | args->version = JNI_VERSION_1_2; | 
|---|
| 3873 | // javaStackSize is int in arguments structure | 
|---|
| 3874 | assert(jlong(ThreadStackSize) * K < INT_MAX, "integer overflow"); | 
|---|
| 3875 | args->javaStackSize = (jint)(ThreadStackSize * K); | 
|---|
| 3876 | } | 
|---|
| 3877 | return ret; | 
|---|
| 3878 | } | 
|---|
| 3879 |  | 
|---|
| 3880 | DT_RETURN_MARK_DECL(CreateJavaVM, jint | 
|---|
| 3881 | , HOTSPOT_JNI_CREATEJAVAVM_RETURN(_ret_ref)); | 
|---|
| 3882 |  | 
|---|
| 3883 | static jint JNI_CreateJavaVM_inner(JavaVM **vm, void **penv, void *args) { | 
|---|
| 3884 | HOTSPOT_JNI_CREATEJAVAVM_ENTRY((void **) vm, penv, args); | 
|---|
| 3885 |  | 
|---|
| 3886 | jint result = JNI_ERR; | 
|---|
| 3887 | DT_RETURN_MARK(CreateJavaVM, jint, (const jint&)result); | 
|---|
| 3888 |  | 
|---|
| 3889 | // We're about to use Atomic::xchg for synchronization.  Some Zero | 
|---|
| 3890 | // platforms use the GCC builtin __sync_lock_test_and_set for this, | 
|---|
| 3891 | // but __sync_lock_test_and_set is not guaranteed to do what we want | 
|---|
| 3892 | // on all architectures.  So we check it works before relying on it. | 
|---|
| 3893 | #if defined(ZERO) && defined(ASSERT) | 
|---|
| 3894 | { | 
|---|
| 3895 | jint a = 0xcafebabe; | 
|---|
| 3896 | jint b = Atomic::xchg((jint) 0xdeadbeef, &a); | 
|---|
| 3897 | void *c = &a; | 
|---|
| 3898 | void *d = Atomic::xchg(&b, &c); | 
|---|
| 3899 | assert(a == (jint) 0xdeadbeef && b == (jint) 0xcafebabe, "Atomic::xchg() works"); | 
|---|
| 3900 | assert(c == &b && d == &a, "Atomic::xchg() works"); | 
|---|
| 3901 | } | 
|---|
| 3902 | #endif // ZERO && ASSERT | 
|---|
| 3903 |  | 
|---|
| 3904 | // At the moment it's only possible to have one Java VM, | 
|---|
| 3905 | // since some of the runtime state is in global variables. | 
|---|
| 3906 |  | 
|---|
| 3907 | // We cannot use our mutex locks here, since they only work on | 
|---|
| 3908 | // Threads. We do an atomic compare and exchange to ensure only | 
|---|
| 3909 | // one thread can call this method at a time | 
|---|
| 3910 |  | 
|---|
| 3911 | // We use Atomic::xchg rather than Atomic::add/dec since on some platforms | 
|---|
| 3912 | // the add/dec implementations are dependent on whether we are running | 
|---|
| 3913 | // on a multiprocessor Atomic::xchg does not have this problem. | 
|---|
| 3914 | if (Atomic::xchg(1, &vm_created) == 1) { | 
|---|
| 3915 | return JNI_EEXIST;   // already created, or create attempt in progress | 
|---|
| 3916 | } | 
|---|
| 3917 | if (Atomic::xchg(0, &safe_to_recreate_vm) == 0) { | 
|---|
| 3918 | return JNI_ERR;  // someone tried and failed and retry not allowed. | 
|---|
| 3919 | } | 
|---|
| 3920 |  | 
|---|
| 3921 | assert(vm_created == 1, "vm_created is true during the creation"); | 
|---|
| 3922 |  | 
|---|
| 3923 | /** | 
|---|
| 3924 | * Certain errors during initialization are recoverable and do not | 
|---|
| 3925 | * prevent this method from being called again at a later time | 
|---|
| 3926 | * (perhaps with different arguments).  However, at a certain | 
|---|
| 3927 | * point during initialization if an error occurs we cannot allow | 
|---|
| 3928 | * this function to be called again (or it will crash).  In those | 
|---|
| 3929 | * situations, the 'canTryAgain' flag is set to false, which atomically | 
|---|
| 3930 | * sets safe_to_recreate_vm to 1, such that any new call to | 
|---|
| 3931 | * JNI_CreateJavaVM will immediately fail using the above logic. | 
|---|
| 3932 | */ | 
|---|
| 3933 | bool can_try_again = true; | 
|---|
| 3934 |  | 
|---|
| 3935 | result = Threads::create_vm((JavaVMInitArgs*) args, &can_try_again); | 
|---|
| 3936 | if (result == JNI_OK) { | 
|---|
| 3937 | JavaThread *thread = JavaThread::current(); | 
|---|
| 3938 | assert(!thread->has_pending_exception(), "should have returned not OK"); | 
|---|
| 3939 | /* thread is thread_in_vm here */ | 
|---|
| 3940 | *vm = (JavaVM *)(&main_vm); | 
|---|
| 3941 | *(JNIEnv**)penv = thread->jni_environment(); | 
|---|
| 3942 |  | 
|---|
| 3943 | #if INCLUDE_JVMCI | 
|---|
| 3944 | if (EnableJVMCI) { | 
|---|
| 3945 | if (UseJVMCICompiler) { | 
|---|
| 3946 | // JVMCI is initialized on a CompilerThread | 
|---|
| 3947 | if (BootstrapJVMCI) { | 
|---|
| 3948 | JavaThread* THREAD = thread; | 
|---|
| 3949 | JVMCICompiler* compiler = JVMCICompiler::instance(true, CATCH); | 
|---|
| 3950 | compiler->bootstrap(THREAD); | 
|---|
| 3951 | if (HAS_PENDING_EXCEPTION) { | 
|---|
| 3952 | HandleMark hm; | 
|---|
| 3953 | vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); | 
|---|
| 3954 | } | 
|---|
| 3955 | } | 
|---|
| 3956 | } | 
|---|
| 3957 | } | 
|---|
| 3958 | #endif | 
|---|
| 3959 |  | 
|---|
| 3960 | // Notify JVMTI | 
|---|
| 3961 | if (JvmtiExport::should_post_thread_life()) { | 
|---|
| 3962 | JvmtiExport::post_thread_start(thread); | 
|---|
| 3963 | } | 
|---|
| 3964 |  | 
|---|
| 3965 | post_thread_start_event(thread); | 
|---|
| 3966 |  | 
|---|
| 3967 | #ifndef PRODUCT | 
|---|
| 3968 | if (ReplayCompiles) ciReplay::replay(thread); | 
|---|
| 3969 |  | 
|---|
| 3970 | // Some platforms (like Win*) need a wrapper around these test | 
|---|
| 3971 | // functions in order to properly handle error conditions. | 
|---|
| 3972 | VMError::test_error_handler(); | 
|---|
| 3973 | #endif | 
|---|
| 3974 |  | 
|---|
| 3975 | // Since this is not a JVM_ENTRY we have to set the thread state manually before leaving. | 
|---|
| 3976 | ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); | 
|---|
| 3977 | } else { | 
|---|
| 3978 | // If create_vm exits because of a pending exception, exit with that | 
|---|
| 3979 | // exception.  In the future when we figure out how to reclaim memory, | 
|---|
| 3980 | // we may be able to exit with JNI_ERR and allow the calling application | 
|---|
| 3981 | // to continue. | 
|---|
| 3982 | if (Universe::is_fully_initialized()) { | 
|---|
| 3983 | // otherwise no pending exception possible - VM will already have aborted | 
|---|
| 3984 | JavaThread* THREAD = JavaThread::current(); | 
|---|
| 3985 | if (HAS_PENDING_EXCEPTION) { | 
|---|
| 3986 | HandleMark hm; | 
|---|
| 3987 | vm_exit_during_initialization(Handle(THREAD, PENDING_EXCEPTION)); | 
|---|
| 3988 | } | 
|---|
| 3989 | } | 
|---|
| 3990 |  | 
|---|
| 3991 | if (can_try_again) { | 
|---|
| 3992 | // reset safe_to_recreate_vm to 1 so that retrial would be possible | 
|---|
| 3993 | safe_to_recreate_vm = 1; | 
|---|
| 3994 | } | 
|---|
| 3995 |  | 
|---|
| 3996 | // Creation failed. We must reset vm_created | 
|---|
| 3997 | *vm = 0; | 
|---|
| 3998 | *(JNIEnv**)penv = 0; | 
|---|
| 3999 | // reset vm_created last to avoid race condition. Use OrderAccess to | 
|---|
| 4000 | // control both compiler and architectural-based reordering. | 
|---|
| 4001 | OrderAccess::release_store(&vm_created, 0); | 
|---|
| 4002 | } | 
|---|
| 4003 |  | 
|---|
| 4004 | // Flush stdout and stderr before exit. | 
|---|
| 4005 | fflush(stdout); | 
|---|
| 4006 | fflush(stderr); | 
|---|
| 4007 |  | 
|---|
| 4008 | return result; | 
|---|
| 4009 |  | 
|---|
| 4010 | } | 
|---|
| 4011 |  | 
|---|
| 4012 | _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_CreateJavaVM(JavaVM **vm, void **penv, void *args) { | 
|---|
| 4013 | jint result = JNI_ERR; | 
|---|
| 4014 | // On Windows, let CreateJavaVM run with SEH protection | 
|---|
| 4015 | #ifdef _WIN32 | 
|---|
| 4016 | __try { | 
|---|
| 4017 | #endif | 
|---|
| 4018 | result = JNI_CreateJavaVM_inner(vm, penv, args); | 
|---|
| 4019 | #ifdef _WIN32 | 
|---|
| 4020 | } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) { | 
|---|
| 4021 | // Nothing to do. | 
|---|
| 4022 | } | 
|---|
| 4023 | #endif | 
|---|
| 4024 | return result; | 
|---|
| 4025 | } | 
|---|
| 4026 |  | 
|---|
| 4027 | _JNI_IMPORT_OR_EXPORT_ jint JNICALL JNI_GetCreatedJavaVMs(JavaVM **vm_buf, jsize bufLen, jsize *numVMs) { | 
|---|
| 4028 | // See bug 4367188, the wrapper can sometimes cause VM crashes | 
|---|
| 4029 | // JNIWrapper("GetCreatedJavaVMs"); | 
|---|
| 4030 |  | 
|---|
| 4031 | HOTSPOT_JNI_GETCREATEDJAVAVMS_ENTRY((void **) vm_buf, bufLen, (uintptr_t *) numVMs); | 
|---|
| 4032 |  | 
|---|
| 4033 | if (vm_created == 1) { | 
|---|
| 4034 | if (numVMs != NULL) *numVMs = 1; | 
|---|
| 4035 | if (bufLen > 0)     *vm_buf = (JavaVM *)(&main_vm); | 
|---|
| 4036 | } else { | 
|---|
| 4037 | if (numVMs != NULL) *numVMs = 0; | 
|---|
| 4038 | } | 
|---|
| 4039 | HOTSPOT_JNI_GETCREATEDJAVAVMS_RETURN(JNI_OK); | 
|---|
| 4040 | return JNI_OK; | 
|---|
| 4041 | } | 
|---|
| 4042 |  | 
|---|
| 4043 | extern "C"{ | 
|---|
| 4044 |  | 
|---|
| 4045 | DT_RETURN_MARK_DECL(DestroyJavaVM, jint | 
|---|
| 4046 | , HOTSPOT_JNI_DESTROYJAVAVM_RETURN(_ret_ref)); | 
|---|
| 4047 |  | 
|---|
| 4048 | static jint JNICALL jni_DestroyJavaVM_inner(JavaVM *vm) { | 
|---|
| 4049 | HOTSPOT_JNI_DESTROYJAVAVM_ENTRY(vm); | 
|---|
| 4050 | jint res = JNI_ERR; | 
|---|
| 4051 | DT_RETURN_MARK(DestroyJavaVM, jint, (const jint&)res); | 
|---|
| 4052 |  | 
|---|
| 4053 | if (vm_created == 0) { | 
|---|
| 4054 | res = JNI_ERR; | 
|---|
| 4055 | return res; | 
|---|
| 4056 | } | 
|---|
| 4057 |  | 
|---|
| 4058 | JNIWrapper( "DestroyJavaVM"); | 
|---|
| 4059 | JNIEnv *env; | 
|---|
| 4060 | JavaVMAttachArgs destroyargs; | 
|---|
| 4061 | destroyargs.version = CurrentVersion; | 
|---|
| 4062 | destroyargs.name = (char *) "DestroyJavaVM"; | 
|---|
| 4063 | destroyargs.group = NULL; | 
|---|
| 4064 | res = vm->AttachCurrentThread((void **)&env, (void *)&destroyargs); | 
|---|
| 4065 | if (res != JNI_OK) { | 
|---|
| 4066 | return res; | 
|---|
| 4067 | } | 
|---|
| 4068 |  | 
|---|
| 4069 | // Since this is not a JVM_ENTRY we have to set the thread state manually before entering. | 
|---|
| 4070 | JavaThread* thread = JavaThread::current(); | 
|---|
| 4071 | ThreadStateTransition::transition_from_native(thread, _thread_in_vm); | 
|---|
| 4072 | if (Threads::destroy_vm()) { | 
|---|
| 4073 | // Should not change thread state, VM is gone | 
|---|
| 4074 | vm_created = 0; | 
|---|
| 4075 | res = JNI_OK; | 
|---|
| 4076 | return res; | 
|---|
| 4077 | } else { | 
|---|
| 4078 | ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); | 
|---|
| 4079 | res = JNI_ERR; | 
|---|
| 4080 | return res; | 
|---|
| 4081 | } | 
|---|
| 4082 | } | 
|---|
| 4083 |  | 
|---|
| 4084 | jint JNICALL jni_DestroyJavaVM(JavaVM *vm) { | 
|---|
| 4085 | jint result = JNI_ERR; | 
|---|
| 4086 | // On Windows, we need SEH protection | 
|---|
| 4087 | #ifdef _WIN32 | 
|---|
| 4088 | __try { | 
|---|
| 4089 | #endif | 
|---|
| 4090 | result = jni_DestroyJavaVM_inner(vm); | 
|---|
| 4091 | #ifdef _WIN32 | 
|---|
| 4092 | } __except(topLevelExceptionFilter((_EXCEPTION_POINTERS*)_exception_info())) { | 
|---|
| 4093 | // Nothing to do. | 
|---|
| 4094 | } | 
|---|
| 4095 | #endif | 
|---|
| 4096 | return result; | 
|---|
| 4097 | } | 
|---|
| 4098 |  | 
|---|
| 4099 | static jint attach_current_thread(JavaVM *vm, void **penv, void *_args, bool daemon) { | 
|---|
| 4100 | JavaVMAttachArgs *args = (JavaVMAttachArgs *) _args; | 
|---|
| 4101 |  | 
|---|
| 4102 | // Check below commented out from JDK1.2fcs as well | 
|---|
| 4103 | /* | 
|---|
| 4104 | if (args && (args->version != JNI_VERSION_1_1 || args->version != JNI_VERSION_1_2)) { | 
|---|
| 4105 | return JNI_EVERSION; | 
|---|
| 4106 | } | 
|---|
| 4107 | */ | 
|---|
| 4108 |  | 
|---|
| 4109 | Thread* t = Thread::current_or_null(); | 
|---|
| 4110 | if (t != NULL) { | 
|---|
| 4111 | // If the thread has been attached this operation is a no-op | 
|---|
| 4112 | *(JNIEnv**)penv = ((JavaThread*) t)->jni_environment(); | 
|---|
| 4113 | return JNI_OK; | 
|---|
| 4114 | } | 
|---|
| 4115 |  | 
|---|
| 4116 | // Create a thread and mark it as attaching so it will be skipped by the | 
|---|
| 4117 | // ThreadsListEnumerator - see CR 6404306 | 
|---|
| 4118 | JavaThread* thread = new JavaThread(true); | 
|---|
| 4119 |  | 
|---|
| 4120 | // Set correct safepoint info. The thread is going to call into Java when | 
|---|
| 4121 | // initializing the Java level thread object. Hence, the correct state must | 
|---|
| 4122 | // be set in order for the Safepoint code to deal with it correctly. | 
|---|
| 4123 | thread->set_thread_state(_thread_in_vm); | 
|---|
| 4124 | thread->record_stack_base_and_size(); | 
|---|
| 4125 | thread->register_thread_stack_with_NMT(); | 
|---|
| 4126 | thread->initialize_thread_current(); | 
|---|
| 4127 |  | 
|---|
| 4128 | if (!os::create_attached_thread(thread)) { | 
|---|
| 4129 | thread->smr_delete(); | 
|---|
| 4130 | return JNI_ERR; | 
|---|
| 4131 | } | 
|---|
| 4132 | // Enable stack overflow checks | 
|---|
| 4133 | thread->create_stack_guard_pages(); | 
|---|
| 4134 |  | 
|---|
| 4135 | thread->initialize_tlab(); | 
|---|
| 4136 |  | 
|---|
| 4137 | thread->cache_global_variables(); | 
|---|
| 4138 |  | 
|---|
| 4139 | // Crucial that we do not have a safepoint check for this thread, since it has | 
|---|
| 4140 | // not been added to the Thread list yet. | 
|---|
| 4141 | { Threads_lock->lock_without_safepoint_check(); | 
|---|
| 4142 | // This must be inside this lock in order to get FullGCALot to work properly, i.e., to | 
|---|
| 4143 | // avoid this thread trying to do a GC before it is added to the thread-list | 
|---|
| 4144 | thread->set_active_handles(JNIHandleBlock::allocate_block()); | 
|---|
| 4145 | Threads::add(thread, daemon); | 
|---|
| 4146 | Threads_lock->unlock(); | 
|---|
| 4147 | } | 
|---|
| 4148 | // Create thread group and name info from attach arguments | 
|---|
| 4149 | oop group = NULL; | 
|---|
| 4150 | char* thread_name = NULL; | 
|---|
| 4151 | if (args != NULL && Threads::is_supported_jni_version(args->version)) { | 
|---|
| 4152 | group = JNIHandles::resolve(args->group); | 
|---|
| 4153 | thread_name = args->name; // may be NULL | 
|---|
| 4154 | } | 
|---|
| 4155 | if (group == NULL) group = Universe::main_thread_group(); | 
|---|
| 4156 |  | 
|---|
| 4157 | // Create Java level thread object and attach it to this thread | 
|---|
| 4158 | bool attach_failed = false; | 
|---|
| 4159 | { | 
|---|
| 4160 | EXCEPTION_MARK; | 
|---|
| 4161 | HandleMark hm(THREAD); | 
|---|
| 4162 | Handle thread_group(THREAD, group); | 
|---|
| 4163 | thread->allocate_threadObj(thread_group, thread_name, daemon, THREAD); | 
|---|
| 4164 | if (HAS_PENDING_EXCEPTION) { | 
|---|
| 4165 | CLEAR_PENDING_EXCEPTION; | 
|---|
| 4166 | // cleanup outside the handle mark. | 
|---|
| 4167 | attach_failed = true; | 
|---|
| 4168 | } | 
|---|
| 4169 | } | 
|---|
| 4170 |  | 
|---|
| 4171 | if (attach_failed) { | 
|---|
| 4172 | // Added missing cleanup | 
|---|
| 4173 | thread->cleanup_failed_attach_current_thread(daemon); | 
|---|
| 4174 | return JNI_ERR; | 
|---|
| 4175 | } | 
|---|
| 4176 |  | 
|---|
| 4177 | // mark the thread as no longer attaching | 
|---|
| 4178 | // this uses a fence to push the change through so we don't have | 
|---|
| 4179 | // to regrab the threads_lock | 
|---|
| 4180 | thread->set_done_attaching_via_jni(); | 
|---|
| 4181 |  | 
|---|
| 4182 | // Set java thread status. | 
|---|
| 4183 | java_lang_Thread::set_thread_status(thread->threadObj(), | 
|---|
| 4184 | java_lang_Thread::RUNNABLE); | 
|---|
| 4185 |  | 
|---|
| 4186 | // Notify the debugger | 
|---|
| 4187 | if (JvmtiExport::should_post_thread_life()) { | 
|---|
| 4188 | JvmtiExport::post_thread_start(thread); | 
|---|
| 4189 | } | 
|---|
| 4190 |  | 
|---|
| 4191 | post_thread_start_event(thread); | 
|---|
| 4192 |  | 
|---|
| 4193 | *(JNIEnv**)penv = thread->jni_environment(); | 
|---|
| 4194 |  | 
|---|
| 4195 | // Now leaving the VM, so change thread_state. This is normally automatically taken care | 
|---|
| 4196 | // of in the JVM_ENTRY. But in this situation we have to do it manually. Notice, that by | 
|---|
| 4197 | // using ThreadStateTransition::transition, we do a callback to the safepoint code if | 
|---|
| 4198 | // needed. | 
|---|
| 4199 |  | 
|---|
| 4200 | ThreadStateTransition::transition(thread, _thread_in_vm, _thread_in_native); | 
|---|
| 4201 |  | 
|---|
| 4202 | // Perform any platform dependent FPU setup | 
|---|
| 4203 | os::setup_fpu(); | 
|---|
| 4204 |  | 
|---|
| 4205 | return JNI_OK; | 
|---|
| 4206 | } | 
|---|
| 4207 |  | 
|---|
| 4208 |  | 
|---|
| 4209 | jint JNICALL jni_AttachCurrentThread(JavaVM *vm, void **penv, void *_args) { | 
|---|
| 4210 | HOTSPOT_JNI_ATTACHCURRENTTHREAD_ENTRY(vm, penv, _args); | 
|---|
| 4211 | if (vm_created == 0) { | 
|---|
| 4212 | HOTSPOT_JNI_ATTACHCURRENTTHREAD_RETURN((uint32_t) JNI_ERR); | 
|---|
| 4213 | return JNI_ERR; | 
|---|
| 4214 | } | 
|---|
| 4215 |  | 
|---|
| 4216 | JNIWrapper( "AttachCurrentThread"); | 
|---|
| 4217 | jint ret = attach_current_thread(vm, penv, _args, false); | 
|---|
| 4218 | HOTSPOT_JNI_ATTACHCURRENTTHREAD_RETURN(ret); | 
|---|
| 4219 | return ret; | 
|---|
| 4220 | } | 
|---|
| 4221 |  | 
|---|
| 4222 |  | 
|---|
| 4223 | jint JNICALL jni_DetachCurrentThread(JavaVM *vm)  { | 
|---|
| 4224 | HOTSPOT_JNI_DETACHCURRENTTHREAD_ENTRY(vm); | 
|---|
| 4225 |  | 
|---|
| 4226 | JNIWrapper( "DetachCurrentThread"); | 
|---|
| 4227 |  | 
|---|
| 4228 | // If the thread has already been detached the operation is a no-op | 
|---|
| 4229 | if (Thread::current_or_null() == NULL) { | 
|---|
| 4230 | HOTSPOT_JNI_DETACHCURRENTTHREAD_RETURN(JNI_OK); | 
|---|
| 4231 | return JNI_OK; | 
|---|
| 4232 | } | 
|---|
| 4233 |  | 
|---|
| 4234 | VM_Exit::block_if_vm_exited(); | 
|---|
| 4235 |  | 
|---|
| 4236 | JavaThread* thread = JavaThread::current(); | 
|---|
| 4237 | if (thread->has_last_Java_frame()) { | 
|---|
| 4238 | HOTSPOT_JNI_DETACHCURRENTTHREAD_RETURN((uint32_t) JNI_ERR); | 
|---|
| 4239 | // Can't detach a thread that's running java, that can't work. | 
|---|
| 4240 | return JNI_ERR; | 
|---|
| 4241 | } | 
|---|
| 4242 |  | 
|---|
| 4243 | // Safepoint support. Have to do call-back to safepoint code, if in the | 
|---|
| 4244 | // middle of a safepoint operation | 
|---|
| 4245 | ThreadStateTransition::transition_from_native(thread, _thread_in_vm); | 
|---|
| 4246 |  | 
|---|
| 4247 | // XXX: Note that JavaThread::exit() call below removes the guards on the | 
|---|
| 4248 | // stack pages set up via enable_stack_{red,yellow}_zone() calls | 
|---|
| 4249 | // above in jni_AttachCurrentThread. Unfortunately, while the setting | 
|---|
| 4250 | // of the guards is visible in jni_AttachCurrentThread above, | 
|---|
| 4251 | // the removal of the guards is buried below in JavaThread::exit() | 
|---|
| 4252 | // here. The abstraction should be more symmetrically either exposed | 
|---|
| 4253 | // or hidden (e.g. it could probably be hidden in the same | 
|---|
| 4254 | // (platform-dependent) methods where we do alternate stack | 
|---|
| 4255 | // maintenance work?) | 
|---|
| 4256 | thread->exit(false, JavaThread::jni_detach); | 
|---|
| 4257 | thread->smr_delete(); | 
|---|
| 4258 |  | 
|---|
| 4259 | HOTSPOT_JNI_DETACHCURRENTTHREAD_RETURN(JNI_OK); | 
|---|
| 4260 | return JNI_OK; | 
|---|
| 4261 | } | 
|---|
| 4262 |  | 
|---|
| 4263 | DT_RETURN_MARK_DECL(GetEnv, jint | 
|---|
| 4264 | , HOTSPOT_JNI_GETENV_RETURN(_ret_ref)); | 
|---|
| 4265 |  | 
|---|
| 4266 | jint JNICALL jni_GetEnv(JavaVM *vm, void **penv, jint version) { | 
|---|
| 4267 | HOTSPOT_JNI_GETENV_ENTRY(vm, penv, version); | 
|---|
| 4268 | jint ret = JNI_ERR; | 
|---|
| 4269 | DT_RETURN_MARK(GetEnv, jint, (const jint&)ret); | 
|---|
| 4270 |  | 
|---|
| 4271 | if (vm_created == 0) { | 
|---|
| 4272 | *penv = NULL; | 
|---|
| 4273 | ret = JNI_EDETACHED; | 
|---|
| 4274 | return ret; | 
|---|
| 4275 | } | 
|---|
| 4276 |  | 
|---|
| 4277 | if (JniExportedInterface::GetExportedInterface(vm, penv, version, &ret)) { | 
|---|
| 4278 | return ret; | 
|---|
| 4279 | } | 
|---|
| 4280 |  | 
|---|
| 4281 | #ifndef JVMPI_VERSION_1 | 
|---|
| 4282 | // need these in order to be polite about older agents | 
|---|
| 4283 | #define JVMPI_VERSION_1   ((jint)0x10000001) | 
|---|
| 4284 | #define JVMPI_VERSION_1_1 ((jint)0x10000002) | 
|---|
| 4285 | #define JVMPI_VERSION_1_2 ((jint)0x10000003) | 
|---|
| 4286 | #endif // !JVMPI_VERSION_1 | 
|---|
| 4287 |  | 
|---|
| 4288 | Thread* thread = Thread::current_or_null(); | 
|---|
| 4289 | if (thread != NULL && thread->is_Java_thread()) { | 
|---|
| 4290 | if (Threads::is_supported_jni_version_including_1_1(version)) { | 
|---|
| 4291 | *(JNIEnv**)penv = ((JavaThread*) thread)->jni_environment(); | 
|---|
| 4292 | ret = JNI_OK; | 
|---|
| 4293 | return ret; | 
|---|
| 4294 |  | 
|---|
| 4295 | } else if (version == JVMPI_VERSION_1 || | 
|---|
| 4296 | version == JVMPI_VERSION_1_1 || | 
|---|
| 4297 | version == JVMPI_VERSION_1_2) { | 
|---|
| 4298 | tty->print_cr( "ERROR: JVMPI, an experimental interface, is no longer supported."); | 
|---|
| 4299 | tty->print_cr( "Please use the supported interface: the JVM Tool Interface (JVM TI)."); | 
|---|
| 4300 | ret = JNI_EVERSION; | 
|---|
| 4301 | return ret; | 
|---|
| 4302 | } else if (JvmtiExport::is_jvmdi_version(version)) { | 
|---|
| 4303 | tty->print_cr( "FATAL ERROR: JVMDI is no longer supported."); | 
|---|
| 4304 | tty->print_cr( "Please use the supported interface: the JVM Tool Interface (JVM TI)."); | 
|---|
| 4305 | ret = JNI_EVERSION; | 
|---|
| 4306 | return ret; | 
|---|
| 4307 | } else { | 
|---|
| 4308 | *penv = NULL; | 
|---|
| 4309 | ret = JNI_EVERSION; | 
|---|
| 4310 | return ret; | 
|---|
| 4311 | } | 
|---|
| 4312 | } else { | 
|---|
| 4313 | *penv = NULL; | 
|---|
| 4314 | ret = JNI_EDETACHED; | 
|---|
| 4315 | return ret; | 
|---|
| 4316 | } | 
|---|
| 4317 | } | 
|---|
| 4318 |  | 
|---|
| 4319 |  | 
|---|
| 4320 | jint JNICALL jni_AttachCurrentThreadAsDaemon(JavaVM *vm, void **penv, void *_args) { | 
|---|
| 4321 | HOTSPOT_JNI_ATTACHCURRENTTHREADASDAEMON_ENTRY(vm, penv, _args); | 
|---|
| 4322 | if (vm_created == 0) { | 
|---|
| 4323 | HOTSPOT_JNI_ATTACHCURRENTTHREADASDAEMON_RETURN((uint32_t) JNI_ERR); | 
|---|
| 4324 | return JNI_ERR; | 
|---|
| 4325 | } | 
|---|
| 4326 |  | 
|---|
| 4327 | JNIWrapper( "AttachCurrentThreadAsDaemon"); | 
|---|
| 4328 | jint ret = attach_current_thread(vm, penv, _args, true); | 
|---|
| 4329 | HOTSPOT_JNI_ATTACHCURRENTTHREADASDAEMON_RETURN(ret); | 
|---|
| 4330 | return ret; | 
|---|
| 4331 | } | 
|---|
| 4332 |  | 
|---|
| 4333 |  | 
|---|
| 4334 | } // End extern "C" | 
|---|
| 4335 |  | 
|---|
| 4336 | const struct JNIInvokeInterface_ jni_InvokeInterface = { | 
|---|
| 4337 | NULL, | 
|---|
| 4338 | NULL, | 
|---|
| 4339 | NULL, | 
|---|
| 4340 |  | 
|---|
| 4341 | jni_DestroyJavaVM, | 
|---|
| 4342 | jni_AttachCurrentThread, | 
|---|
| 4343 | jni_DetachCurrentThread, | 
|---|
| 4344 | jni_GetEnv, | 
|---|
| 4345 | jni_AttachCurrentThreadAsDaemon | 
|---|
| 4346 | }; | 
|---|
| 4347 |  | 
|---|