6436034: Instance filter doesn't filter event if it occurs in native method
authorkamg
Wed, 12 Jan 2011 11:47:35 -0500
changeset 7978 120267233d5e
parent 7976 f273c0d04215
child 7979 0ae19fac0c55
6436034: Instance filter doesn't filter event if it occurs in native method Summary: Use 'GetLocalInstance' JVMTI extension if it exists Reviewed-by: coleenp, dcubed
jdk/src/share/back/debugInit.c
jdk/src/share/back/eventFilter.c
jdk/src/share/instrument/JPLISAgent.c
jdk/src/share/javavm/export/jvmti.h
jdk/test/com/sun/jdi/NativeInstanceFilter.java
jdk/test/com/sun/jdi/NativeInstanceFilterTarg.java
--- a/jdk/src/share/back/debugInit.c	Wed Jan 12 14:40:36 2011 +0000
+++ b/jdk/src/share/back/debugInit.c	Wed Jan 12 11:47:35 2011 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2005, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2010, 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
@@ -133,27 +133,60 @@
     return error;
 }
 
+typedef struct {
+    int major;
+    int minor;
+} version_type;
+
+typedef struct {
+    version_type runtime;
+    version_type compiletime;
+} compatible_versions_type;
+
+/*
+ * List of explicitly compatible JVMTI versions, specified as
+ * { runtime version, compile-time version } pairs. -1 is a wildcard.
+ */
+static int nof_compatible_versions = 3;
+static compatible_versions_type compatible_versions_list[] = {
+    /*
+     * FIXUP: Allow version 0 to be compatible with anything
+     * Special check for FCS of 1.0.
+     */
+    { {  0, -1 }, { -1, -1 } },
+    { { -1, -1 }, {  0, -1 } },
+    /*
+     * 1.2 is runtime compatible with 1.1 -- just make sure to check the
+     * version before using any new 1.2 features
+     */
+    { {  1,  1 }, {  1,  2 } }
+};
+
+
 /* Logic to determine JVMTI version compatibility */
 static jboolean
 compatible_versions(jint major_runtime,     jint minor_runtime,
                     jint major_compiletime, jint minor_compiletime)
 {
-#if 1 /* FIXUP: We allow version 0 to be compatible with anything */
-    /* Special check for FCS of 1.0. */
-    if ( major_runtime == 0 || major_compiletime == 0 ) {
-        return JNI_TRUE;
+    /*
+     * First check to see if versions are explicitly compatible via the
+     * list specified above.
+     */
+    int i;
+    for (i = 0; i < nof_compatible_versions; ++i) {
+        version_type runtime = compatible_versions_list[i].runtime;
+        version_type comptime = compatible_versions_list[i].compiletime;
+
+        if ((major_runtime     == runtime.major  || runtime.major  == -1) &&
+            (minor_runtime     == runtime.minor  || runtime.minor  == -1) &&
+            (major_compiletime == comptime.major || comptime.major == -1) &&
+            (minor_compiletime == comptime.minor || comptime.minor == -1)) {
+            return JNI_TRUE;
+        }
     }
-#endif
-    /* Runtime major version must match. */
-    if ( major_runtime != major_compiletime ) {
-        return JNI_FALSE;
-    }
-    /* Runtime minor version must be >= the version compiled with. */
-    if ( minor_runtime < minor_compiletime ) {
-        return JNI_FALSE;
-    }
-    /* Assumed compatible */
-    return JNI_TRUE;
+
+    return major_runtime == major_compiletime &&
+           minor_runtime >= minor_compiletime;
 }
 
 /* OnLoad startup:
--- a/jdk/src/share/back/eventFilter.c	Wed Jan 12 14:40:36 2011 +0000
+++ b/jdk/src/share/back/eventFilter.c	Wed Jan 12 11:47:35 2011 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2001, 2010, 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
@@ -39,6 +39,7 @@
 #include "stepControl.h"
 #include "threadControl.h"
 #include "SDE.h"
+#include "jvmti.h"
 
 typedef struct ClassFilter {
     jclass clazz;
@@ -275,6 +276,24 @@
     }
 }
 
+static jboolean isVersionGte12x() {
+    jint version;
+    jvmtiError err =
+        JVMTI_FUNC_PTR(gdata->jvmti,GetVersionNumber)(gdata->jvmti, &version);
+
+    if (err == JVMTI_ERROR_NONE) {
+        jint major, minor;
+
+        major = (version & JVMTI_VERSION_MASK_MAJOR)
+                    >> JVMTI_VERSION_SHIFT_MAJOR;
+        minor = (version & JVMTI_VERSION_MASK_MINOR)
+                    >> JVMTI_VERSION_SHIFT_MINOR;
+        return (major > 1 || major == 1 && minor >= 2);
+    } else {
+        return JNI_FALSE;
+    }
+}
+
 /* Return the object instance in which the event occurred */
 /* Return NULL if static or if an error occurs */
 static jobject
@@ -286,6 +305,14 @@
     jint        modifiers       = 0;
     jvmtiError  error;
 
+    static jboolean got_version = JNI_FALSE;
+    static jboolean is_version_gte_12x = JNI_FALSE;
+
+    if (!got_version) {
+        is_version_gte_12x = isVersionGte12x();
+        got_version = JNI_TRUE;
+    }
+
     switch (evinfo->ei) {
         case EI_SINGLE_STEP:
         case EI_BREAKPOINT:
@@ -314,11 +341,18 @@
     /* fail if error or static (0x8) */
     if (error == JVMTI_ERROR_NONE && thread!=NULL && (modifiers & 0x8) == 0) {
         FrameNumber fnum            = 0;
-        /* get slot zero object "this" */
-        error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
-                    (gdata->jvmti, thread, fnum, 0, &object);
-        if (error != JVMTI_ERROR_NONE)
+        if (is_version_gte_12x) {
+            /* Use new 1.2.x function, GetLocalInstance */
+            error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalInstance)
+                        (gdata->jvmti, thread, fnum, &object);
+        } else {
+            /* get slot zero object "this" */
+            error = JVMTI_FUNC_PTR(gdata->jvmti,GetLocalObject)
+                        (gdata->jvmti, thread, fnum, 0, &object);
+        }
+        if (error != JVMTI_ERROR_NONE) {
             object = NULL;
+        }
     }
 
     return object;
--- a/jdk/src/share/instrument/JPLISAgent.c	Wed Jan 12 14:40:36 2011 +0000
+++ b/jdk/src/share/instrument/JPLISAgent.c	Wed Jan 12 11:47:35 2011 -0500
@@ -209,7 +209,7 @@
     *agent_ptr = NULL;
     jnierror = (*vm)->GetEnv(  vm,
                                (void **) &jvmtienv,
-                               JVMTI_VERSION);
+                               JVMTI_VERSION_1_1);
     if ( jnierror != JNI_OK ) {
         initerror = JPLIS_INIT_ERROR_CANNOT_CREATE_NATIVE_AGENT;
     } else {
@@ -990,7 +990,7 @@
     }
     jnierror = (*agent->mJVM)->GetEnv(  agent->mJVM,
                                (void **) &retransformerEnv,
-                               JVMTI_VERSION);
+                               JVMTI_VERSION_1_1);
     if ( jnierror != JNI_OK ) {
         return NULL;
     }
--- a/jdk/src/share/javavm/export/jvmti.h	Wed Jan 12 14:40:36 2011 +0000
+++ b/jdk/src/share/javavm/export/jvmti.h	Wed Jan 12 11:47:35 2011 -0500
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2003, 2006, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2003, 2010, 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
@@ -41,8 +41,9 @@
     JVMTI_VERSION_1   = 0x30010000,
     JVMTI_VERSION_1_0 = 0x30010000,
     JVMTI_VERSION_1_1 = 0x30010100,
-
-    JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (1 * 0x100) + 102  /* version: 1.1.102 */
+    JVMTI_VERSION_1_2 = 0x30010200,
+
+    JVMTI_VERSION = 0x30000000 + (1 * 0x10000) + (2 * 0x100) + 1  /* version: 1.2.1 */
 };
 
 JNIEXPORT jint JNICALL
@@ -1774,6 +1775,12 @@
     jobject object,
     jlong* size_ptr);
 
+  /*   155 : Get Local Instance */
+  jvmtiError (JNICALL *GetLocalInstance) (jvmtiEnv* env,
+    jthread thread,
+    jint depth,
+    jobject* value_ptr);
+
 } jvmtiInterface_1;
 
 struct _jvmtiEnv {
@@ -2031,6 +2038,12 @@
     return functions->GetLocalObject(this, thread, depth, slot, value_ptr);
   }
 
+  jvmtiError GetLocalInstance(jthread thread,
+            jint depth,
+            jobject* value_ptr) {
+    return functions->GetLocalInstance(this, thread, depth, value_ptr);
+  }
+
   jvmtiError GetLocalInt(jthread thread,
             jint depth,
             jint slot,
@@ -2518,3 +2531,4 @@
 #endif /* __cplusplus */
 
 #endif /* !_JAVA_JVMTI_H_ */
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jdi/NativeInstanceFilter.java	Wed Jan 12 11:47:35 2011 -0500
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+
+/**
+ *  @test
+ *  @bug 6426034
+ *  @summary Instance filter doesn't filter event if it occurs in native method
+ *
+ *  @author Keith McGuigan
+ *
+ *  @library scaffold
+ *  @run build JDIScaffold VMConnection
+ *  @compile -XDignore.symbol.file NativeInstanceFilterTarg.java
+ *  @run main/othervm NativeInstanceFilter
+ */
+
+/*
+ *  This test tests instance filters for events generated from a native method
+ */
+
+import java.util.*;
+import com.sun.jdi.*;
+import com.sun.jdi.event.*;
+import com.sun.jdi.request.*;
+
+public class NativeInstanceFilter extends JDIScaffold {
+
+    static int unfilteredEvents = 0;
+
+    public static void main(String args[]) throws Exception {
+        new NativeInstanceFilter().startTests();
+    }
+
+    public NativeInstanceFilter() {
+        super();
+    }
+
+    static EventRequestManager requestManager = null;
+    static MethodExitRequest request = null;
+
+    private void listen() {
+        TargetAdapter adapter = new TargetAdapter() {
+            EventSet set = null;
+            ObjectReference instance = null;
+
+            public boolean eventSetReceived(EventSet set) {
+                this.set = set;
+                return false;
+            }
+
+            public boolean methodExited(MethodExitEvent event) {
+                String name = event.method().name();
+                if (instance == null && name.equals("latch")) {
+                    // Grab the instance (return value) and set up as filter
+                    System.out.println("Setting up instance filter");
+                    instance = (ObjectReference)event.returnValue();
+                    requestManager.deleteEventRequest(request);
+                    request = requestManager.createMethodExitRequest();
+                    request.addInstanceFilter(instance);
+                    request.enable();
+                } else if (instance != null && name.equals("intern")) {
+                    // If not for the filter, this will be called twice
+                    System.out.println("method exit event (String.intern())");
+                    ++unfilteredEvents;
+                }
+                set.resume();
+                return false;
+            }
+        };
+        addListener(adapter);
+    }
+
+
+    protected void runTests() throws Exception {
+        String[] args = new String[2];
+        args[0] = "-connect";
+        args[1] = "com.sun.jdi.CommandLineLaunch:main=NativeInstanceFilterTarg";
+
+        connect(args);
+        waitForVMStart();
+
+        // VM has started, but hasn't started running the test program yet.
+        requestManager = vm().eventRequestManager();
+        ReferenceType referenceType =
+            resumeToPrepareOf("NativeInstanceFilterTarg").referenceType();
+
+        request = requestManager.createMethodExitRequest();
+        request.enable();
+
+        listen();
+
+        vm().resume();
+
+        waitForVMDeath();
+
+        if (unfilteredEvents != 1) {
+            throw new Exception(
+                "Failed: Event from native frame not filtered out.");
+        }
+        System.out.println("Passed: Event filtered out.");
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/jdk/test/com/sun/jdi/NativeInstanceFilterTarg.java	Wed Jan 12 11:47:35 2011 -0500
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2010, 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.
+ */
+
+import sun.misc.Version;
+
+public class NativeInstanceFilterTarg {
+
+    public static void main(String args[]) {
+        boolean runTest = jvmSupportsJVMTI_12x();
+        String s1 = "abc";
+        String s2 = "def";
+        latch(s1);
+        s1.intern();
+        if (runTest) {
+            s2.intern(); // this is the call that generates events that ought
+                         // to be filtered out.
+        } else {
+            System.out.println("Neutering test since JVMTI 1.2 not supported");
+        }
+    }
+
+    // Used by debugger to get an instance to filter with
+    public static String latch(String s) { return s; }
+
+    public static boolean jvmSupportsJVMTI_12x() {
+        // This fix requires the JVM to support JVMTI 1.2, which doesn't
+        // happen until HSX 20.0, build 05.
+        int major = Version.jvmMajorVersion();
+        int minor = Version.jvmMinorVersion();
+        int micro = Version.jvmMicroVersion();
+        int build = Version.jvmBuildNumber();
+
+        return (major > 20 || major == 20 &&
+                   (minor > 0 || micro > 0 || build >= 5));
+    }
+}