This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[ecj] gnu/classpath/VMStackWalker.java: first cut


This adds partial support for VMStackWalker.getCallingClassLoader().

The idea is that a call to VMStackWalker.getCallingClassLoader() gets
turned into
VMStackWalker.getCallingClassLoader(__builtin_return_address(0)) by
the compiler, so it isn't necessary to walk the stack to find our
caller.  This leads to a fairly efficient implementation.

This only works for compiled, not interpreted code, and it doesn't
work for methods invoked via reflection.  That remains to be addred.

As soon as the missing parts of VMStackWalker are done we can merge
serialization with Classpath.

Andrew.


2006-11-23  Andrew Haley  <aph@redhat.com>

	* expr.c (rewrite_arglist_getcaller): New.
	(rewrite_arglist_getclass): Fix indentation.
	(rules): Add gnu.classpath.VMStackWalker.getCallingClass() and 
	gnu.classpath.VMStackWalker.getCallingClassLoader().
	* builtins.c (initialize_builtins): Remove duplicate def'n of
	__sync_synchronize.
	Add __builtin_return_address.

2006-11-23  Andrew Haley  <aph@redhat.com>

	* Makefile.am (nat_source_files): Add gnu/classpath/natVMStackWalker.cc.
	* sources.am: Rebuild.
	* gnu/classpath/natVMStackWalker.cc: New file.
	* gnu/classpath/VMStackWalker.java: New file.
	* headers.txt: prepend 
	_Jv_Thread_t* _Jv_ThreadGetData(java::lang::Thread* thread)
	* include/java-stack.h: Add VMStackWalker namespace.
	Add friend class gnu::classpath::VMStackWalker.

Index: gcc/java/builtins.c
===================================================================
--- gcc/java/builtins.c	(revision 119120)
+++ gcc/java/builtins.c	(working copy)
@@ -566,9 +566,9 @@
 		  build_function_type (void_type_node, void_list_node),
 		  "__sync_synchronize", BUILTIN_NOTHROW);
   
-  define_builtin (BUILT_IN_SYNCHRONIZE, "__sync_synchronize",
-		  build_function_type (void_type_node, void_list_node),
-		  "__sync_synchronize", BUILTIN_NOTHROW);
+  define_builtin (BUILT_IN_RETURN_ADDRESS, "__builtin_return_address",
+		  build_function_type_list (ptr_type_node, int_type_node, NULL_TREE),
+		  "__builtin_return_address", BUILTIN_NOTHROW);
 
   build_common_builtin_nodes ();
 }
Index: gcc/java/expr.c
===================================================================
--- gcc/java/expr.c	(revision 119120)
+++ gcc/java/expr.c	(working copy)
@@ -2048,13 +2048,30 @@
   tree (*rewrite_arglist) (tree arglist);
 } rewrite_rule;
 
+/* Add __builtin_return_address(0) to the end of an arglist.  */
+
+
+static tree 
+rewrite_arglist_getcaller (tree arglist)
+{
+  tree retaddr 
+    = (build_function_call_expr 
+       (built_in_decls[BUILT_IN_RETURN_ADDRESS],
+	build_tree_list (NULL_TREE, integer_zero_node)));
+  
+  return chainon (arglist, 
+		  tree_cons (NULL_TREE, retaddr, 
+			     NULL_TREE));
+}
+
 /* Add this.class to the end of an arglist.  */
 
 static tree 
 rewrite_arglist_getclass (tree arglist)
 {
   return chainon (arglist, 
-		  tree_cons (NULL_TREE, build_class_ref (output_class), NULL_TREE));
+		  tree_cons (NULL_TREE, build_class_ref (output_class),
+			     NULL_TREE));
 }
 
 static rewrite_rule rules[] =
@@ -2064,6 +2081,14 @@
    {"java.lang.Class", "forName", "(Ljava/lang/String;)Ljava/lang/Class;",
     "(Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Class;",
     ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getclass},
+   {"gnu.classpath.VMStackWalker", "getCallingClass", "()Ljava/lang/Class;",
+    "(Lgnu/gcj/RawData;)Ljava/lang/Class;",
+    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
+   {"gnu.classpath.VMStackWalker", "getCallingClassLoader", 
+    "()Ljava/lang/ClassLoader;",
+    "(Lgnu/gcj/RawData;)Ljava/lang/ClassLoader;",
+    ACC_FINAL|ACC_PRIVATE|ACC_STATIC, rewrite_arglist_getcaller},
+
    {NULL, NULL, NULL, NULL, 0, NULL}};
 
 /* Scan the rules list for replacements for *METHOD_P and replace the
Index: libjava/include/java-stack.h
===================================================================
--- libjava/include/java-stack.h	(revision 119120)
+++ libjava/include/java-stack.h	(working copy)
@@ -30,6 +30,17 @@
 using namespace gnu::gcj::runtime;
 using namespace java::lang;
 
+extern "Java"
+{
+  namespace gnu
+  {
+    namespace classpath
+    {
+        class VMStackWalker;
+    }
+  }
+}
+
 enum _Jv_FrameType
 {
   frame_native,
@@ -130,6 +141,7 @@
   static jobjectArray GetAccessControlStack ();
 
   friend jclass _Jv_GetMethodDeclaringClass (jmethodID);
+  friend class gnu::classpath::VMStackWalker;
 };
 
 // Information about a given address.
Index: libjava/headers.txt
===================================================================
--- libjava/headers.txt	(revision 119120)
+++ libjava/headers.txt	(working copy)
@@ -15,6 +15,8 @@
 prepend java::lang::Thread* _Jv_AttachCurrentThread (jstring name, java::lang::ThreadGroup* group);
 prepend java::lang::Thread* _Jv_AttachCurrentThreadAsDaemon (jstring name, java::lang::ThreadGroup* group);
 prepend jint _Jv_DetachCurrentThread ();
+prepend struct _Jv_Thread_t;
+prepend _Jv_Thread_t* _Jv_ThreadGetData (java::lang::Thread* thread);
 friend _Jv_JNIEnv * ::_Jv_GetCurrentJNIEnv ();
 friend void ::_Jv_SetCurrentJNIEnv (_Jv_JNIEnv *env);
 friend void ::_Jv_ThreadRun (java::lang::Thread* thread);
Index: libjava/gnu/classpath/VMStackWalker.java
===================================================================
--- libjava/gnu/classpath/VMStackWalker.java	(revision 0)
+++ libjava/gnu/classpath/VMStackWalker.java	(revision 0)
@@ -0,0 +1,128 @@
+/* VMStackWalker.java -- Reference implementation of VM hooks for stack access
+   Copyright (C) 2005 Free Software Foundation
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath 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 for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING.  If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library.  Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module.  An independent module is a module which is not derived from
+or based on this library.  If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so.  If you do not wish to do so, delete this
+exception statement from your version. */
+
+package gnu.classpath;
+
+import gnu.gcj.RawData;
+
+/**
+ * This class provides access to the classes on the Java stack
+ * for reflection and security purposes.
+ *
+ * <p>
+ * This class is only available to privileged code (i.e., code loaded
+ * by the bootstrap loader).
+ *
+ * @author John Keiser
+ * @author Eric Blake <ebb9@email.byu.edu>
+ * @author Archie Cobbs
+ */
+public final class VMStackWalker
+{
+  /**
+   * Get a list of all the classes currently executing methods on the
+   * Java stack. <code>getClassContext()[0]</code> is the class associated
+   * with the currently executing method, i.e., the method that called
+   * <code>VMStackWalker.getClassContext()</code> (possibly through
+   * reflection). So you may need to pop off these stack frames from
+   * the top of the stack:
+   * <ul>
+   * <li><code>VMStackWalker.getClassContext()</code>
+   * <li><code>Method.invoke()</code>
+   * </ul>
+   *
+   * @return an array of the declaring classes of each stack frame
+   */
+  public static Class[] getClassContext()
+    throws NotImplementedException
+  {
+    return null;
+  }
+
+  /**
+   * Get the class associated with the method invoking the method
+   * invoking this method, or <code>null</code> if the stack is not
+   * that deep (e.g., invoked via JNI invocation API). This method
+   * is an optimization for the expression <code>getClassContext()[1]</code>
+   * and should return the same result.
+   *
+   * <p>
+   * VM implementers are encouraged to provide a more efficient
+   * version of this method.
+   */
+  public static Class getCallingClass()
+    throws NotImplementedException
+  {
+    Class[] ctx = getClassContext();
+    if (ctx.length < 3)
+      return null;
+    return ctx[2];
+  }
+
+  private static native Class getCallingClass(RawData p);
+
+  private static native ClassLoader getCallingClassLoader(RawData p);
+
+  /**
+   * Get the class loader associated with the Class returned by
+   * <code>getCallingClass()</code>, or <code>null</code> if no such class
+   * exists or it is the boot loader. This method is an optimization for the
+   * expression <code>VMStackWalker.getClassLoader(getClassContext()[1])</code>
+   * and should return the same result.
+   *
+   * <p>
+   * VM implementers are encouraged to provide a more efficient
+   * version of this method.
+   */
+  public static ClassLoader getCallingClassLoader()
+    throws NotImplementedException
+  {
+    Class[] ctx = getClassContext();
+    if (ctx.length < 3)
+      return null;
+    return getClassLoader(ctx[2]);
+  }
+
+  /**
+   * Retrieve the class's ClassLoader, or <code>null</code> if loaded
+   * by the bootstrap loader. I.e., this should return the same thing
+   * as {@link java.lang.VMClass#getClassLoader}. This duplicate version
+   * is here to work around access permissions.
+   */
+  public static native ClassLoader getClassLoader(Class cl);
+}
+
Index: libjava/gnu/classpath/natVMStackWalker.cc
===================================================================
--- libjava/gnu/classpath/natVMStackWalker.cc	(revision 0)
+++ libjava/gnu/classpath/natVMStackWalker.cc	(revision 0)
@@ -0,0 +1,58 @@
+// natVMStackWalker.cc
+
+/* Copyright (C) 2006  Free Software Foundation
+
+   This file is part of libgcj.
+
+This software is copyrighted work licensed under the terms of the
+Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
+details.  */
+
+#include <config.h>
+#include <platform.h>
+
+#include <gcj/cni.h>
+#include <jvm.h>
+#include <java-stack.h>
+#include <gnu/classpath/VMStackWalker.h>
+#include <gnu/gcj/RawData.h>
+#include <java/lang/ClassLoader.h>
+
+jclass
+gnu::classpath::VMStackWalker::getCallingClass(::gnu::gcj::RawData *pc)
+{
+  // FIXME: Security check here?
+
+  void *f = _Unwind_FindEnclosingFunction (pc);
+
+  // FIXME: it might well be a good idea to cache pc values here in
+  // order to avoid repeated invocations of
+  // _Unwind_FindEnclosingFunction, which is quite expensive.  On the
+  // other hand, which not simply write a caching version of
+  // _Unwind_FindEnclosingFunction itself?  That would probably be
+  // worthwhile.
+
+  _Jv_StackTrace::UpdateNCodeMap ();
+  jclass klass = (jclass) _Jv_StackTrace::ncodeMap->get ((jobject) f);
+
+  // FIXME: If klass is null at this point, we need to use the
+  // unwinder machinery to scan the stack to find the real caller.
+  JvAssert (klass);
+
+  return klass;
+}
+
+::java::lang::ClassLoader *
+gnu::classpath::VMStackWalker::getClassLoader(::java::lang::Class *c)
+{
+  // FIXME: Security check here?
+  return c->getClassLoaderInternal ();
+}
+
+::java::lang::ClassLoader *
+gnu::classpath::VMStackWalker::getCallingClassLoader(::gnu::gcj::RawData *pc)
+{
+  // FIXME: Security check here?
+  return getCallingClass (pc)->getClassLoaderInternal ();
+}
+
Index: libjava/Makefile.am
===================================================================
--- libjava/Makefile.am	(revision 119120)
+++ libjava/Makefile.am	(working copy)
@@ -714,11 +714,12 @@
 
 ## This lists all the C++ source files in subdirectories.
 nat_source_files = \
-gnu/classpath/natSystemProperties.cc \
-gnu/classpath/natConfiguration.cc \
 gnu/classpath/jdwp/natVMFrame.cc \
 gnu/classpath/jdwp/natVMMethod.cc \
 gnu/classpath/jdwp/natVMVirtualMachine.cc \
+gnu/classpath/natConfiguration.cc \
+gnu/classpath/natSystemProperties.cc \
+gnu/classpath/natVMStackWalker.cc \
 gnu/gcj/natCore.cc \
 gnu/gcj/convert/JIS0208_to_Unicode.cc \
 gnu/gcj/convert/JIS0212_to_Unicode.cc \


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]