src/share/vm/prims/nativeLookup.cpp

Sat, 24 Oct 2020 16:43:47 +0800

author
aoqi
date
Sat, 24 Oct 2020 16:43:47 +0800
changeset 10015
eb7ce841ccec
parent 9931
fd44df5e3bc3
parent 10006
d0f692037e7b
permissions
-rw-r--r--

Merge

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

mercurial