| /* |
| * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| package nsk.jvmti.SetNativeMethodPrefix; |
| |
| import java.io.*; |
| import nsk.share.Consts; |
| |
| /* ============================================================================== */ |
| /* Quote from JVMTI specification v.1.1.102: |
| * |
| * Since native methods cannot be directly instrumented (they have no |
| * bytecodes), they must be wrapped with a non-native method which can be |
| * instrumented. For example, if we had: |
| * native boolean foo(int x); |
| * |
| * We could transform the class file (with the ClassFileLoadHook event) so |
| * that this becomes: |
| * boolean foo(int x) { |
| * ... record entry to foo ... |
| * return wrapped_foo(x); |
| * } |
| * |
| * native boolean wrapped_foo(int x); |
| * |
| * Where foo becomes a wrapper for the actual native method with the appended |
| * prefix "wrapped_". |
| * |
| * The wrapper will allow data to be collected on the native method call, but |
| * now the problem becomes linking up the wrapped method with the native |
| * implementation. That is, the method wrapped_foo needs to be resolved to the |
| * native implementation of foo, which might be: |
| * |
| * Java_somePackage_someClass_foo(JNIEnv* env, jint x) |
| * |
| * This function allows the prefix to be specified and the proper resolution |
| * to occur. Specifically, when the standard resolution fails, the resolution |
| * is retried taking the prefix into consideration. There are two ways that |
| * resolution occurs, explicit resolution with the JNI function |
| * RegisterNatives and the normal automatic resolution. For RegisterNatives, |
| * the VM will attempt this association: |
| * |
| * method(foo) -> nativeImplementation(foo) |
| * |
| * When this fails, the resolution will be retried with the specified prefix |
| * prepended to the method name, yielding the correct resolution: |
| * |
| * method(wrapped_foo) -> nativeImplementation(foo) |
| * |
| * For automatic resolution, the VM will attempt: |
| * |
| * method(wrapped_foo) -> nativeImplementation(wrapped_foo) |
| * |
| * When this fails, the resolution will be retried with the specified prefix |
| * deleted from the implementation name, yielding the correct resolution: |
| * |
| * method(wrapped_foo) -> nativeImplementation(foo) |
| * |
| * Note that since the prefix is only used when standard resolution fails, |
| * native methods can be wrapped selectively. |
| */ |
| /* ============================================================================== */ |
| |
| |
| /* ======================================================= */ |
| // Auxiliary classes for explicit method resolution |
| /* ======================================================= */ |
| class ExplicitResolution1 { |
| static public int foo() { return wrapped_foo(); } |
| native static public int wrapped_foo(); |
| } |
| |
| /* ======================================================= */ |
| class ExplicitResolution2 { |
| native static public int wrapped_foo(); |
| } |
| |
| /* ======================================================= */ |
| // Auxiliary classes for automatic resolution |
| /* ======================================================= */ |
| class AutomaticResolution1 { |
| static public int foo() { return wrapped_foo(); } |
| native static public int wrapped_foo(); |
| } |
| |
| /* ======================================================= */ |
| class AutomaticResolution2 { |
| static public int foo() { return wrapped_foo(); } |
| native static public int wrapped_foo(); |
| } |
| |
| /* ======================================================= */ |
| class AutomaticResolution3 { |
| static public int foo() { return wrapped_foo(); } |
| native static public int wrapped_foo(); |
| } |
| |
| /* ======================================================= */ |
| public class SetNativeMethodPrefix001 { |
| PrintStream out = System.out; |
| |
| static public final String prefix = "wrapped_"; |
| |
| /* ============================================================ */ |
| // |
| // For RegisterNatives, the VM will attempt this association: |
| // |
| // method(foo) -> nativeImplementation(foo) |
| // |
| // When this fails, the resolution will be retried with the specified |
| // prefix prepended to the method name, yielding the correct resolution: |
| // |
| // method(wrapped_foo) -> nativeImplementation(foo) |
| // |
| // The prefix is only used when standard resolution fails. |
| // |
| /* ============================================================ */ |
| public boolean checkExplicitResolution1(boolean isPrefixSet) { |
| |
| // Initiate class A loading and initialization |
| // See CR 6493522 for details |
| new ExplicitResolution1(); |
| |
| // Bind ExplicitResolution1.foo() to a native function. |
| // If the prefix isn't set, this code should fail since ExplicitResolution1.foo() isn't native. |
| if (Binder.registerMethod(ExplicitResolution1.class, "foo", "()I", Binder.FUNCTION_FOO) != isPrefixSet) |
| { |
| out.println("ERROR: unexpected RegisterNatives() behavior."); |
| return false; |
| } |
| |
| if (isPrefixSet) { |
| if (ExplicitResolution1.foo() != Binder.FOO_RETURN) { |
| out.println("ERROR: native method wrapped_foo() wasn't correctly bound."); |
| return false; |
| } |
| } |
| |
| // Bind ExplicitResolution1.wrapped_foo() to a native fucntion. |
| // This code should succeed since ExplicitResolution1.wrapped_foo() is native. |
| if (!Binder.registerMethod(ExplicitResolution1.class, "wrapped_foo", "()I", Binder.FUNCTION_WRAPPED_FOO)) |
| { |
| out.println("ERROR: RegisterNative() failed for native method ExplicitResolution1.wrapped_foo()."); |
| return false; |
| } |
| |
| if (ExplicitResolution1.foo() != Binder.WRAPPED_FOO_RETURN) { |
| out.println("ERROR: native method wrapped_foo() wasn't correctly bound."); |
| return false; |
| } |
| return true; |
| } |
| |
| /* ============================================================ */ |
| public boolean checkExplicitResolution2() { |
| // Initiate class ExplicitResolution2 loading and initialization |
| // See CR 6493522 for details |
| new ExplicitResolution2(); |
| |
| // This binding should fail whether the prefix is set or not since: |
| // - there's no Java_nsk_jvmti_SetNativeMethodPrefix_ExplicitResolution2_wrapped_1foo defined |
| // - class ExplicitResolution2 doesn't have java method foo() |
| if (Binder.registerMethod(ExplicitResolution2.class, "foo", "()I", Binder.FUNCTION_WRAPPED_FOO)) { |
| out.println("ERROR: unexpected RegisterNatives() behavior."); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* ============================================================ */ |
| public boolean checkExplicitResolution (boolean isMultiplePrefixes) { |
| // Setting method prefix |
| out.println("\tSetting prefix: "+prefix); |
| if (isMultiplePrefixes) { |
| if (!Binder.setMultiplePrefixes(prefix)) { return false; } |
| } else { |
| if (!Binder.setMethodPrefix(prefix)) { return false; } |
| } |
| |
| // Check the behavior |
| out.println("\t\tChecking resolution for ExplicitResolution1"); |
| if (!checkExplicitResolution1(true)) { return false; } |
| out.println("\t\tChecking resolution for ExplicitResolution2"); |
| if (!checkExplicitResolution2()) { return false; } |
| |
| // Resetting method prefix |
| out.println("\tResetting prefix"); |
| if (isMultiplePrefixes) { |
| if (!Binder.setMultiplePrefixes(null)) { return false; } |
| } else { |
| if (!Binder.setMethodPrefix(null)) { return false; } |
| } |
| |
| // Check the behavior |
| out.println("\t\tChecking resolution for ExplicitResolution1"); |
| if (!checkExplicitResolution1(false)) { return false; } |
| out.println("\t\tChecking resolution for ExplicitResolution2"); |
| if (!checkExplicitResolution2()) { return false; } |
| |
| return true; |
| } |
| |
| /* ============================================================ */ |
| // For automatic resolution, the VM will attempt: |
| // |
| // method(wrapped_foo) -> nativeImplementation(wrapped_foo) |
| // |
| // When this fails, the resolution will be retried with the specified |
| // prefix deleted from the implementation name, yielding the correct |
| // resolution: |
| // |
| // method(wrapped_foo) -> nativeImplementation(foo) |
| // |
| // The prefix is only used when standard resolution fails. |
| /* ============================================================ */ |
| public boolean checkAutomaticResolution1() { |
| if (AutomaticResolution1.foo() != Binder.WRAPPED_FOO_RETURN) { |
| out.println("ERROR: native method AutomaticResolution1.wrapped_foo() wasn't correctly bound."); |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* ============================================================ */ |
| public boolean checkAutomaticResolution2 (boolean isPrefixSet) { |
| if (isPrefixSet) { |
| if (AutomaticResolution2.foo() != Binder.FOO_RETURN) { |
| out.println("ERROR: native method AutomaticResolution2.wrapped_foo() wasn't correctly bound."); |
| return false; |
| } |
| } else { |
| try { |
| AutomaticResolution3.foo(); |
| out.println("ERROR: native method AutomaticResolution3.wrapped_foo() was bound."); |
| return false; |
| } catch (UnsatisfiedLinkError e) { |
| out.println(String.format("The method isn't bound: %s %s\n", e.getClass().getName(), e.getMessage())); |
| return true; |
| } |
| } |
| |
| return true; |
| } |
| |
| /* ============================================================ */ |
| public boolean checkAutomaticResolution (boolean isMultiplePrefixes) { |
| // Setting method prefix |
| out.println("\tSetting prefix: "+prefix); |
| if (isMultiplePrefixes) { |
| if (!Binder.setMultiplePrefixes(prefix)) { return false; } |
| } else { |
| if (!Binder.setMethodPrefix(prefix)) { return false; } |
| } |
| |
| // Check the behavior |
| out.println("\t\tChecking resolution for AutomaticResolution1"); |
| if (!checkAutomaticResolution1()) { return false; } |
| out.println("\t\tChecking resolution for AutomaticResolution2"); |
| if (!checkAutomaticResolution2(true)) { return false; } |
| |
| // Resetting method prefix |
| out.println("\tResetting prefix"); |
| if (isMultiplePrefixes) { |
| if (!Binder.setMultiplePrefixes(null)) { return false; } |
| } else { |
| if (!Binder.setMethodPrefix(null)) { return false; } |
| } |
| |
| // Check the behavior |
| out.println("\t\tChecking resolution for AutomaticResolution1"); |
| if (!checkAutomaticResolution1()) { return false; } |
| out.println("\t\tChecking resolution for AutomaticResolution2"); |
| if (!checkAutomaticResolution2(false)) { return false; } |
| |
| return true; |
| } |
| |
| /* ============================================================ */ |
| public boolean runIt(String [] args, PrintStream _out) { |
| if (_out != null) { |
| out = _out; |
| } |
| |
| out.println("\nAutomatic resolution; SetMethodPrefix is used"); |
| if (!checkAutomaticResolution(true)) { return false; } |
| |
| out.println("\nAutomatic resolution; SetMultiplePrefixes is used"); |
| if (!checkAutomaticResolution(false)) { return false; } |
| |
| out.println("\nExplicit resolution; SetMethodPrefix is used"); |
| if (!checkExplicitResolution(true)) { return false; } |
| |
| out.println("\nExplicit resolution; SetMultiplePrefixes is used"); |
| if (!checkExplicitResolution(false)) { return false; } |
| |
| |
| return true; |
| } |
| |
| /* ============================================================ */ |
| public static int run(String argv[], PrintStream out) { |
| if ((new SetNativeMethodPrefix001()).runIt(argv, out)) { |
| out.println("TEST PASSED"); |
| return Consts.TEST_PASSED; |
| } else { |
| out.println("TEST FAILED"); |
| return Consts.TEST_FAILED; |
| } |
| } |
| |
| /* ============================================================ */ |
| public static void main(String[] argv) { |
| argv = nsk.share.jvmti.JVMTITest.commonInit(argv); |
| |
| System.exit(run(argv, System.out) + Consts.JCK_STATUS_BASE); |
| } |
| } |