1 /*
2 * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25 #include "precompiled.hpp"
26 #include "classfile/javaClasses.hpp"
27 #include "classfile/symbolTable.hpp"
28 #include "classfile/systemDictionary.hpp"
29 #include "classfile/vmSymbols.hpp"
30 #include "logging/log.hpp"
31 #include "logging/logTag.hpp"
32 #include "memory/oopFactory.hpp"
33 #include "memory/resourceArea.hpp"
34 #include "oops/instanceKlass.hpp"
35 #include "oops/klass.inline.hpp"
36 #include "oops/method.hpp"
37 #include "oops/oop.inline.hpp"
38 #include "oops/symbol.hpp"
39 #include "prims/jvm_misc.hpp"
40 #include "prims/jvmtiExport.hpp"
41 #include "prims/nativeLookup.hpp"
42 #include "prims/unsafe.hpp"
43 #include "prims/scopedMemoryAccess.hpp"
44 #include "runtime/arguments.hpp"
45 #include "runtime/handles.inline.hpp"
46 #include "runtime/interfaceSupport.inline.hpp"
47 #include "runtime/javaCalls.hpp"
48 #include "runtime/os.inline.hpp"
49 #include "runtime/sharedRuntime.hpp"
50 #include "runtime/signature.hpp"
51 #include "utilities/macros.hpp"
52 #include "utilities/utf8.hpp"
53 #if INCLUDE_JFR
54 #include "jfr/jfr.hpp"
55 #endif
56
57 /*
58
59 The JNI specification defines the mapping from a Java native method name to
60 a C native library implementation function name as follows:
61
62 The mapping produces a native method name by concatenating the following components
63 derived from a `native` method declaration:
64
65 1. the prefix Java_
66 2. given the binary name, in internal form, of the class which declares the native method:
67 the result of escaping the name.
68 3. an underscore ("_")
69 4. the escaped method name
70 5. if the native method declaration is overloaded: two underscores ("__") followed by the
71 escaped parameter descriptor (JVMS 4.3.3) of the method declaration.
72
73 Escaping leaves every alphanumeric ASCII character (A-Za-z0-9) unchanged, and replaces each
74 UTF-16 code unit n the table below with the corresponding escape sequence. If the name to be
75 escaped contains a surrogate pair, then the high-surrogate code unit and the low-surrogate code
76 unit are escaped separately. The result of escaping is a string consisting only of the ASCII
77 characters A-Za-z0-9 and underscore.
78
79 ------------------------------ ------------------------------------
80 UTF-16 code unit Escape sequence
81 ------------------------------ ------------------------------------
82 Forward slash (/, U+002F) _
83 Underscore (_, U+005F) _1
84 Semicolon (;, U+003B) _2
85 Left square bracket ([, U+005B) _3
86 Any UTF-16 code unit \u_WXYZ_ that does not _0wxyz where w, x, y, and z are the lower-case
87 represent alphanumeric ASCII (A-Za-z0-9), forms of the hexadecimal digits W, X, Y, and Z.
88 forward slash, underscore, semicolon, (For example, U+ABCD becomes _0abcd.)
89 or left square bracket
90 ------------------------------ ------------------------------------
91
92 Note that escape sequences can safely begin _0, _1, etc, because class and method
93 names in Java source code never begin with a number. However, that is not the case in
94 class files that were not generated from Java source code.
95
96 To preserve the 1:1 mapping to a native method name, the VM checks the resulting name as
97 follows. If the process of escaping any precursor string from the native method declaration
98 (class or method name, or argument type) causes a "0", "1", "2", or "3" character
99 from the precursor string to appear unchanged in the result *either* immediately after an
100 underscore *or* at the beginning of the escaped string (where it will follow an underscore
101 in the fully assembled name), then the escaping process is said to have "failed".
102 In such cases, no native library search is performed, and the attempt to link the native
103 method invocation will throw UnsatisfiedLinkError.
104
105
106 For example:
107
108 package/my_class/method
109
110 and
111
112 package/my/1class/method
113
114 both map to
115
116 Java_package_my_1class_method
117
118 To address this potential conflict we need only check if the character after
119 / is a digit 0..3, or if the first character after an injected '_' seperator
120 is a digit 0..3. If we encounter an invalid identifier we reset the
121 stringStream and return false. Otherwise the stringStream contains the mapped
122 name and we return true.
123
124 */
map_escaped_name_on(stringStream * st,Symbol * name,int begin,int end)125 static bool map_escaped_name_on(stringStream* st, Symbol* name, int begin, int end) {
126 char* bytes = (char*)name->bytes() + begin;
127 char* end_bytes = (char*)name->bytes() + end;
128 bool check_escape_char = true; // initially true as first character here follows '_'
129 while (bytes < end_bytes) {
130 jchar c;
131 bytes = UTF8::next(bytes, &c);
132 if (c <= 0x7f && isalnum(c)) {
133 if (check_escape_char && (c >= '0' && c <= '3')) {
134 // This is a non-Java identifier and we won't escape it to
135 // ensure no name collisions with a Java identifier.
136 if (log_is_enabled(Debug, jni, resolve)) {
137 ResourceMark rm;
138 log_debug(jni, resolve)("[Lookup of native method with non-Java identifier rejected: %s]",
139 name->as_C_string());
140 }
141 st->reset(); // restore to "" on error
142 return false;
143 }
144 st->put((char) c);
145 check_escape_char = false;
146 } else {
147 check_escape_char = false;
148 if (c == '_') st->print("_1");
149 else if (c == '/') {
150 st->print("_");
151 // Following a / we must have non-escape character
152 check_escape_char = true;
153 }
154 else if (c == ';') st->print("_2");
155 else if (c == '[') st->print("_3");
156 else st->print("_%.5x", c);
157 }
158 }
159 return true;
160 }
161
162
map_escaped_name_on(stringStream * st,Symbol * name)163 static bool map_escaped_name_on(stringStream* st, Symbol* name) {
164 return map_escaped_name_on(st, name, 0, name->utf8_length());
165 }
166
167
pure_jni_name(const methodHandle & method)168 char* NativeLookup::pure_jni_name(const methodHandle& method) {
169 stringStream st;
170 // Prefix
171 st.print("Java_");
172 // Klass name
173 if (!map_escaped_name_on(&st, method->klass_name())) {
174 return NULL;
175 }
176 st.print("_");
177 // Method name
178 if (!map_escaped_name_on(&st, method->name())) {
179 return NULL;
180 }
181 return st.as_string();
182 }
183
184
critical_jni_name(const methodHandle & method)185 char* NativeLookup::critical_jni_name(const methodHandle& method) {
186 stringStream st;
187 // Prefix
188 st.print("JavaCritical_");
189 // Klass name
190 if (!map_escaped_name_on(&st, method->klass_name())) {
191 return NULL;
192 }
193 st.print("_");
194 // Method name
195 if (!map_escaped_name_on(&st, method->name())) {
196 return NULL;
197 }
198 return st.as_string();
199 }
200
201
long_jni_name(const methodHandle & method)202 char* NativeLookup::long_jni_name(const methodHandle& method) {
203 // Signatures ignore the wrapping parentheses and the trailing return type
204 stringStream st;
205 Symbol* signature = method->signature();
206 st.print("__");
207 // find ')'
208 int end;
209 for (end = 0; end < signature->utf8_length() && signature->char_at(end) != JVM_SIGNATURE_ENDFUNC; end++);
210 // skip first '('
211 if (!map_escaped_name_on(&st, signature, 1, end)) {
212 return NULL;
213 }
214
215 return st.as_string();
216 }
217
218 extern "C" {
219 void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls);
220 void JNICALL JVM_RegisterReferencesMethods(JNIEnv *env, jclass unsafecls);
221 void JNICALL JVM_RegisterUpcallHandlerMethods(JNIEnv *env, jclass unsafecls);
222 void JNICALL JVM_RegisterProgrammableUpcallHandlerMethods(JNIEnv *env, jclass unsafecls);
223 void JNICALL JVM_RegisterProgrammableInvokerMethods(JNIEnv *env, jclass unsafecls);
224 void JNICALL JVM_RegisterNativeEntryPointMethods(JNIEnv *env, jclass unsafecls);
225 void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass);
226 void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass);
227 void JNICALL JVM_RegisterVectorSupportMethods(JNIEnv *env, jclass vsclass);
228 #if INCLUDE_JVMCI
229 jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c);
230 void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass);
231 #endif
232 }
233
234 #define CC (char*) /* cast a literal from (const char*) */
235 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f)
236
237 static JNINativeMethod lookup_special_native_methods[] = {
238 { CC"Java_jdk_internal_misc_Unsafe_registerNatives", NULL, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) },
239 { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", NULL, FN_PTR(JVM_RegisterMethodHandleMethods) },
240 { CC"Java_jdk_internal_foreign_abi_UpcallStubs_registerNatives", NULL, FN_PTR(JVM_RegisterUpcallHandlerMethods) },
241 { CC"Java_jdk_internal_foreign_abi_ProgrammableUpcallHandler_registerNatives", NULL, FN_PTR(JVM_RegisterProgrammableUpcallHandlerMethods) },
242 { CC"Java_jdk_internal_foreign_abi_ProgrammableInvoker_registerNatives", NULL, FN_PTR(JVM_RegisterProgrammableInvokerMethods) },
243 { CC"Java_jdk_internal_invoke_NativeEntryPoint_registerNatives", NULL, FN_PTR(JVM_RegisterNativeEntryPointMethods) },
244 { CC"Java_jdk_internal_perf_Perf_registerNatives", NULL, FN_PTR(JVM_RegisterPerfMethods) },
245 { CC"Java_sun_hotspot_WhiteBox_registerNatives", NULL, FN_PTR(JVM_RegisterWhiteBoxMethods) },
246 { CC"Java_jdk_internal_vm_vector_VectorSupport_registerNatives", NULL, FN_PTR(JVM_RegisterVectorSupportMethods)},
247 #if INCLUDE_JVMCI
248 { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", NULL, FN_PTR(JVM_GetJVMCIRuntime) },
249 { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", NULL, FN_PTR(JVM_RegisterJVMCINatives) },
250 #endif
251 #if INCLUDE_JFR
252 { CC"Java_jdk_jfr_internal_JVM_registerNatives", NULL, FN_PTR(jfr_register_natives) },
253 #endif
254 { CC"Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives", NULL, FN_PTR(JVM_RegisterJDKInternalMiscScopedMemoryAccessMethods) },
255 };
256
lookup_special_native(const char * jni_name)257 static address lookup_special_native(const char* jni_name) {
258 int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod);
259 for (int i = 0; i < count; i++) {
260 // NB: To ignore the jni prefix and jni postfix strstr is used matching.
261 if (strstr(jni_name, lookup_special_native_methods[i].name) != NULL) {
262 return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr);
263 }
264 }
265 return NULL;
266 }
267
lookup_style(const methodHandle & method,char * pure_name,const char * long_name,int args_size,bool os_style,bool & in_base_library,TRAPS)268 address NativeLookup::lookup_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, bool os_style, bool& in_base_library, TRAPS) {
269 address entry;
270 const char* jni_name = compute_complete_jni_name(pure_name, long_name, args_size, os_style);
271
272
273 // If the loader is null we have a system class, so we attempt a lookup in
274 // the native Java library. This takes care of any bootstrapping problems.
275 // Note: It is critical for bootstrapping that Java_java_lang_ClassLoader_findNative
276 // gets found the first time around - otherwise an infinite loop can occure. This is
277 // another VM/library dependency
278 Handle loader(THREAD, method->method_holder()->class_loader());
279 if (loader.is_null()) {
280 entry = lookup_special_native(jni_name);
281 if (entry == NULL) {
282 entry = (address) os::dll_lookup(os::native_java_library(), jni_name);
283 }
284 if (entry != NULL) {
285 in_base_library = true;
286 return entry;
287 }
288 }
289
290 // Otherwise call static method findNative in ClassLoader
291 Klass* klass = SystemDictionary::ClassLoader_klass();
292 Handle name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL);
293
294 JavaValue result(T_LONG);
295 JavaCalls::call_static(&result,
296 klass,
297 vmSymbols::findNative_name(),
298 vmSymbols::classloader_string_long_signature(),
299 // Arguments
300 loader,
301 name_arg,
302 CHECK_NULL);
303 entry = (address) (intptr_t) result.get_jlong();
304
305 if (entry == NULL) {
306 // findNative didn't find it, if there are any agent libraries look in them
307 AgentLibrary* agent;
308 for (agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
309 entry = (address) os::dll_lookup(agent->os_lib(), jni_name);
310 if (entry != NULL) {
311 return entry;
312 }
313 }
314 }
315
316 return entry;
317 }
318
compute_complete_jni_name(const char * pure_name,const char * long_name,int args_size,bool os_style)319 const char* NativeLookup::compute_complete_jni_name(const char* pure_name, const char* long_name, int args_size, bool os_style) {
320 stringStream st;
321 if (os_style) {
322 os::print_jni_name_prefix_on(&st, args_size);
323 }
324
325 st.print_raw(pure_name);
326 st.print_raw(long_name);
327 if (os_style) {
328 os::print_jni_name_suffix_on(&st, args_size);
329 }
330
331 return st.as_string();
332 }
333
lookup_critical_style(void * dll,const char * pure_name,const char * long_name,int args_size,bool os_style)334 address NativeLookup::lookup_critical_style(void* dll, const char* pure_name, const char* long_name, int args_size, bool os_style) {
335 const char* jni_name = compute_complete_jni_name(pure_name, long_name, args_size, os_style);
336 assert(dll != NULL, "dll must be loaded");
337 return (address)os::dll_lookup(dll, jni_name);
338 }
339
340 // Check all the formats of native implementation name to see if there is one
341 // for the specified method.
lookup_entry(const methodHandle & method,bool & in_base_library,TRAPS)342 address NativeLookup::lookup_entry(const methodHandle& method, bool& in_base_library, TRAPS) {
343 address entry = NULL;
344 in_base_library = false;
345 // Compute pure name
346 char* pure_name = pure_jni_name(method);
347 if (pure_name == NULL) {
348 // JNI name mapping rejected this method so return
349 // NULL to indicate UnsatisfiedLinkError should be thrown.
350 return NULL;
351 }
352
353 // Compute argument size
354 int args_size = 1 // JNIEnv
355 + (method->is_static() ? 1 : 0) // class for static methods
356 + method->size_of_parameters(); // actual parameters
357
358 // 1) Try JNI short style
359 entry = lookup_style(method, pure_name, "", args_size, true, in_base_library, CHECK_NULL);
360 if (entry != NULL) return entry;
361
362 // Compute long name
363 char* long_name = long_jni_name(method);
364 if (long_name == NULL) {
365 // JNI name mapping rejected this method so return
366 // NULL to indicate UnsatisfiedLinkError should be thrown.
367 return NULL;
368 }
369
370 // 2) Try JNI long style
371 entry = lookup_style(method, pure_name, long_name, args_size, true, in_base_library, CHECK_NULL);
372 if (entry != NULL) return entry;
373
374 // 3) Try JNI short style without os prefix/suffix
375 entry = lookup_style(method, pure_name, "", args_size, false, in_base_library, CHECK_NULL);
376 if (entry != NULL) return entry;
377
378 // 4) Try JNI long style without os prefix/suffix
379 entry = lookup_style(method, pure_name, long_name, args_size, false, in_base_library, CHECK_NULL);
380
381 return entry; // NULL indicates not found
382 }
383
384 // Check all the formats of native implementation name to see if there is one
385 // for the specified method.
lookup_critical_entry(const methodHandle & method)386 address NativeLookup::lookup_critical_entry(const methodHandle& method) {
387 assert(CriticalJNINatives, "or should not be here");
388
389 if (method->is_synchronized() ||
390 !method->is_static()) {
391 // Only static non-synchronized methods are allowed
392 return NULL;
393 }
394
395 ResourceMark rm;
396
397 Symbol* signature = method->signature();
398 for (int end = 0; end < signature->utf8_length(); end++) {
399 if (signature->char_at(end) == 'L') {
400 // Don't allow object types
401 return NULL;
402 }
403 }
404
405 // Compute argument size
406 int args_size = method->size_of_parameters();
407 for (SignatureStream ss(signature); !ss.at_return_type(); ss.next()) {
408 if (ss.is_array()) {
409 args_size += T_INT_size; // array length parameter
410 }
411 }
412
413 // dll handling requires I/O. Don't do that while in _thread_in_vm (safepoint may get requested).
414 ThreadToNativeFromVM thread_in_native(JavaThread::current());
415
416 void* dll = dll_load(method);
417 address entry = NULL;
418
419 if (dll != NULL) {
420 entry = lookup_critical_style(dll, method, args_size);
421 // Close the handle to avoid keeping the library alive if the native method holder is unloaded.
422 // This is fine because the library is still kept alive by JNI (see JVM_LoadLibrary). As soon
423 // as the holder class and the library are unloaded (see JVM_UnloadLibrary), the native wrapper
424 // that calls 'critical_entry' becomes unreachable and is unloaded as well.
425 os::dll_unload(dll);
426 }
427
428 return entry; // NULL indicates not found
429 }
430
dll_load(const methodHandle & method)431 void* NativeLookup::dll_load(const methodHandle& method) {
432 if (method->has_native_function()) {
433
434 address current_entry = method->native_function();
435
436 char dll_name[JVM_MAXPATHLEN];
437 int offset;
438 if (os::dll_address_to_library_name(current_entry, dll_name, sizeof(dll_name), &offset)) {
439 char ebuf[32];
440 return os::dll_load(dll_name, ebuf, sizeof(ebuf));
441 }
442 }
443
444 return NULL;
445 }
446
lookup_critical_style(void * dll,const methodHandle & method,int args_size)447 address NativeLookup::lookup_critical_style(void* dll, const methodHandle& method, int args_size) {
448 address entry = NULL;
449 const char* critical_name = critical_jni_name(method);
450 if (critical_name == NULL) {
451 // JNI name mapping rejected this method so return
452 // NULL to indicate UnsatisfiedLinkError should be thrown.
453 return NULL;
454 }
455
456 // 1) Try JNI short style
457 entry = lookup_critical_style(dll, critical_name, "", args_size, true);
458 if (entry != NULL) {
459 return entry;
460 }
461
462 const char* long_name = long_jni_name(method);
463 if (long_name == NULL) {
464 // JNI name mapping rejected this method so return
465 // NULL to indicate UnsatisfiedLinkError should be thrown.
466 return NULL;
467 }
468
469 // 2) Try JNI long style
470 entry = lookup_critical_style(dll, critical_name, long_name, args_size, true);
471 if (entry != NULL) {
472 return entry;
473 }
474
475 // 3) Try JNI short style without os prefix/suffix
476 entry = lookup_critical_style(dll, critical_name, "", args_size, false);
477 if (entry != NULL) {
478 return entry;
479 }
480
481 // 4) Try JNI long style without os prefix/suffix
482 return lookup_critical_style(dll, critical_name, long_name, args_size, false);
483 }
484
485 // Check if there are any JVM TI prefixes which have been applied to the native method name.
486 // If any are found, remove them before attemping the look up of the
487 // native implementation again.
488 // See SetNativeMethodPrefix in the JVM TI Spec for more details.
lookup_entry_prefixed(const methodHandle & method,bool & in_base_library,TRAPS)489 address NativeLookup::lookup_entry_prefixed(const methodHandle& method, bool& in_base_library, TRAPS) {
490 #if INCLUDE_JVMTI
491 ResourceMark rm(THREAD);
492
493 int prefix_count;
494 char** prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count);
495 char* in_name = method->name()->as_C_string();
496 char* wrapper_name = in_name;
497 // last applied prefix will be first -- go backwards
498 for (int i = prefix_count-1; i >= 0; i--) {
499 char* prefix = prefixes[i];
500 size_t prefix_len = strlen(prefix);
501 if (strncmp(prefix, wrapper_name, prefix_len) == 0) {
502 // has this prefix remove it
503 wrapper_name += prefix_len;
504 }
505 }
506 if (wrapper_name != in_name) {
507 // we have a name for a wrapping method
508 int wrapper_name_len = (int)strlen(wrapper_name);
509 TempNewSymbol wrapper_symbol = SymbolTable::probe(wrapper_name, wrapper_name_len);
510 if (wrapper_symbol != NULL) {
511 Klass* k = method->method_holder();
512 Method* wrapper_method = k->lookup_method(wrapper_symbol, method->signature());
513 if (wrapper_method != NULL && !wrapper_method->is_native()) {
514 // we found a wrapper method, use its native entry
515 method->set_is_prefixed_native();
516 return lookup_entry(methodHandle(THREAD, wrapper_method), in_base_library, THREAD);
517 }
518 }
519 }
520 #endif // INCLUDE_JVMTI
521 return NULL;
522 }
523
lookup_base(const methodHandle & method,bool & in_base_library,TRAPS)524 address NativeLookup::lookup_base(const methodHandle& method, bool& in_base_library, TRAPS) {
525 address entry = NULL;
526 ResourceMark rm(THREAD);
527
528 entry = lookup_entry(method, in_base_library, THREAD);
529 if (entry != NULL) return entry;
530
531 // standard native method resolution has failed. Check if there are any
532 // JVM TI prefixes which have been applied to the native method name.
533 entry = lookup_entry_prefixed(method, in_base_library, THREAD);
534 if (entry != NULL) return entry;
535
536 // Native function not found, throw UnsatisfiedLinkError
537 stringStream ss;
538 ss.print("'");
539 method->print_external_name(&ss);
540 ss.print("'");
541 THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string());
542 }
543
544
lookup(const methodHandle & method,bool & in_base_library,TRAPS)545 address NativeLookup::lookup(const methodHandle& method, bool& in_base_library, TRAPS) {
546 if (!method->has_native_function()) {
547 address entry = lookup_base(method, in_base_library, CHECK_NULL);
548 method->set_native_function(entry,
549 Method::native_bind_event_is_interesting);
550 // -verbose:jni printing
551 if (log_is_enabled(Debug, jni, resolve)) {
552 ResourceMark rm(THREAD);
553 log_debug(jni, resolve)("[Dynamic-linking native method %s.%s ... JNI]",
554 method->method_holder()->external_name(),
555 method->name()->as_C_string());
556 }
557 }
558 return method->native_function();
559 }
560
base_library_lookup(const char * class_name,const char * method_name,const char * signature)561 address NativeLookup::base_library_lookup(const char* class_name, const char* method_name, const char* signature) {
562 EXCEPTION_MARK;
563 bool in_base_library = true; // SharedRuntime inits some math methods.
564 TempNewSymbol c_name = SymbolTable::new_symbol(class_name);
565 TempNewSymbol m_name = SymbolTable::new_symbol(method_name);
566 TempNewSymbol s_name = SymbolTable::new_symbol(signature);
567
568 // Find the class
569 Klass* k = SystemDictionary::resolve_or_fail(c_name, true, CATCH);
570 InstanceKlass* klass = InstanceKlass::cast(k);
571
572 // Find method and invoke standard lookup
573 methodHandle method (THREAD,
574 klass->uncached_lookup_method(m_name, s_name, Klass::OverpassLookupMode::find));
575 address result = lookup(method, in_base_library, CATCH);
576 assert(in_base_library, "must be in basic library");
577 guarantee(result != NULL, "must be non NULL");
578 return result;
579 }
580