This is the mail archive of the java-patches@gcc.gnu.org mailing list for the Java 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]

Re: Two JITs for libgcj


>>>>> "Tom" == Tom Tromey <tromey@redhat.com> writes:

Tom> Perhaps I'll just move forward with this and mark the result
Tom> "experimental"... I'll try to come up with a patch for folks to
Tom> comment on.

I wrote this last night and translated the JITs to use it.
I'm not going to check it in, this is a very rough draft.

The basic idea is that libgcj loads a jit at startup, if a system
property is specified.  The jit should declare a JNI_OnLoad function
to register itself, and then use stuff from cni.h, Class.h and the
extra things from the new jitapi.h to do its work.

Some problems:
* The API is kind of ugly.  In particular we only really need 1
  entry point
* The API is incomplete...
  - exceptions aren't mentioned at all
  - line number tables and local variable tables also aren't mentioned
  - GC issues are ignored
* I didn't really commit to moving _Jv_VTable, so there is a dumb
  #ifdef.
* You can't include both jni.h and cni.h, leading to bogus
  workarounds in the JIT code.  This is just a plain bug IMO.

One other needed cleanup is to move some of the "interpreter" linking
code out of the #ifdef and make the interpreter work more like a
fallback JIT.  This is not a big deal.

Tom

Index: gnu/java/lang/MainThread.java
===================================================================
--- gnu/java/lang/MainThread.java	(revision 112723)
+++ gnu/java/lang/MainThread.java	(working copy)
@@ -1,5 +1,5 @@
 /* gnu.java.lang.MainThread
-   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
+   Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
    Free Software Foundation, Inc.
 
 This file is part of GNU Classpath.
@@ -39,6 +39,7 @@
 
 package gnu.java.lang;
 
+import gnu.classpath.SystemProperties;
 import java.util.jar.Attributes;
 import java.util.jar.JarFile;
 
@@ -82,8 +83,18 @@
     this.is_jar = is_jar;
   }
 
+  private void loadJIT ()
+  {
+    String name = SystemProperties.getProperty("gnu.gcj.jit.library");
+    if (name == null)
+      return;
+    System.loadLibrary(name);
+  }
+
   public void run()
   {
+    loadJIT();
+
     if (is_jar)
       klass_name = getMain(klass_name);
 
Index: interpret.cc
===================================================================
--- interpret.cc	(revision 112723)
+++ interpret.cc	(working copy)
@@ -37,12 +37,17 @@
 #include <java/lang/ClassFormatError.h>
 #include <execution.h>
 #include <java/lang/reflect/Modifier.h>
+#include <gcj/jitapi.h>
 
 #ifdef INTERPRETER
 
 // Execution engine for interpreted code.
 _Jv_InterpreterEngine _Jv_soleInterpreterEngine;
 
+// JIT-related stuff.
+static _Jv_JITPrepareMethodFunctionType *jit_preparer;
+static _Jv_JITGetClosureFunctionType *jit_closure;
+
 #include <stdlib.h>
 
 using namespace gcj;
@@ -3629,46 +3634,62 @@
     return self->ncode;
 
   jboolean staticp = (self->accflags & Modifier::STATIC) != 0;
-  int arg_count = _Jv_count_arguments (self->signature, staticp);
 
-  ncode_closure *closure =
-    (ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
+  void *new_ncode;
+  if (jit_preparer)
+    {
+      // Use the JIT.
+      prepared = (*jit_preparer) (defining_class, bytecode (), code_length,
+				  max_stack, max_locals, staticp,
+				  self->signature->chars (),
+				  &defining_class->constants);
+      // FIXME: I suppose we could just have a single entry...
+      new_ncode = (*jit_closure) (prepared);
+    }
+  else
+    {
+      int arg_count = _Jv_count_arguments (self->signature, staticp);
+
+      ncode_closure *closure =
+	(ncode_closure*)_Jv_AllocBytes (sizeof (ncode_closure)
 					+ arg_count * sizeof (ffi_type*));
 
-  init_cif (self->signature,
-	    arg_count,
-	    staticp,
-	    &closure->cif,
-	    &closure->arg_types[0],
-	    NULL);
+      init_cif (self->signature,
+		arg_count,
+		staticp,
+		&closure->cif,
+		&closure->arg_types[0],
+		NULL);
 
-  ffi_closure_fun fun;
+      ffi_closure_fun fun;
 
-  args_raw_size = FFI_RAW_SIZE (&closure->cif);
+      args_raw_size = FFI_RAW_SIZE (&closure->cif);
 
-  JvAssert ((self->accflags & Modifier::NATIVE) == 0);
+      JvAssert ((self->accflags & Modifier::NATIVE) == 0);
 
-  if ((self->accflags & Modifier::SYNCHRONIZED) != 0)
-    {
-      if (staticp)
-	fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
+      if ((self->accflags & Modifier::SYNCHRONIZED) != 0)
+	{
+	  if (staticp)
+	    fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_class;
+	  else
+	    fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; 
+	}
       else
-	fun = (ffi_closure_fun)&_Jv_InterpMethod::run_synch_object; 
+	{
+	  if (staticp)
+	    fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
+	  else
+	    fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
+	}
+
+      FFI_PREP_RAW_CLOSURE (&closure->closure,
+			    &closure->cif, 
+			    fun,
+			    (void*)this);
+      new_ncode = (void *) closure;
     }
-  else
-    {
-      if (staticp)
-	fun = (ffi_closure_fun)&_Jv_InterpMethod::run_class;
-      else
-	fun = (ffi_closure_fun)&_Jv_InterpMethod::run_normal;
-    }
 
-  FFI_PREP_RAW_CLOSURE (&closure->closure,
-		        &closure->cif, 
-		        fun,
-		        (void*)this);
-
-  self->ncode = (void*)closure;
+  self->ncode = new_ncode;
   return self->ncode;
 }
 
@@ -3971,4 +3992,18 @@
 }
 #endif // DIRECT_THREADED
 
+// FIXME: should not be #if INTERPRETER here.
+void
+_Jv_JITRegister (_Jv_JITPrepareMethodFunctionType *prep,
+		 _Jv_JITGetClosureFunctionType *clos)
+{
+  // If multiple JITs are loaded, use the first.
+  JvAssert (prep && clos);
+  if (! jit_preparer)
+    {
+      jit_preparer = prep;
+      jit_closure = clos;
+    }
+}
+
 #endif // INTERPRETER
Index: gcj/jitapi.h
===================================================================
--- gcj/jitapi.h	(revision 0)
+++ gcj/jitapi.h	(revision 0)
@@ -0,0 +1,99 @@
+// gcj/jitapi.h -*- c++ -*-
+// EXPERIMENTAL - may change at any time
+// This exposes bits of API for use by loadable JIT compilers.
+
+/* 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.  */
+
+
+#ifndef __GCJ_JITAPI_H__
+#define __GCJ_JITAPI_H__
+
+extern "C" jobject _Jv_NewArray (jint type, jint size)
+  __attribute__((__malloc__));
+extern "C" jobject _Jv_NewMultiArray (jclass klass, jint dims, ...)
+  __attribute__((__malloc__));
+extern jobject _Jv_NewMultiArray (jclass type, jint dimensions, jint *sizes);
+extern "C" void *_Jv_CheckCast (jclass klass, jobject obj);
+extern "C" void *_Jv_LookupInterfaceMethod (jclass klass, _Jv_Utf8Const *name,
+					    _Jv_Utf8Const *signature);
+extern "C" void *_Jv_LookupInterfaceMethodIdx (jclass klass, jclass iface, 
+                                               int meth_idx);
+extern "C" void _Jv_CheckArrayStore (jobject array, jobject obj);
+extern "C" void _Jv_ThrowBadArrayIndex (jint bad_index)
+  __attribute__((noreturn));
+
+extern int _Jv_GetArrayOffsetOfLength (jclass element_type);
+extern void *_Jv_JITResolvePoolEntry (jclass klass, int index);
+
+class _Jv_ResolvedMethod;
+extern int _Jv_GetResolvedMethodVtableIndex (_Jv_ResolvedMethod *);
+extern _Jv_Method *_Jv_GetResolvedMethodMethod (_Jv_ResolvedMethod *);
+
+#ifdef EXTERNAL  // FIXME
+
+/* Structure of the virtual table.  */
+struct _Jv_VTable
+{
+#ifdef __ia64__
+  typedef struct { void *pc, *gp; } vtable_elt;
+#else
+  typedef void *vtable_elt;
+#endif
+  jclass clas;
+  void *gc_descr;
+
+  // This must be last, as derived classes "extend" this by
+  // adding new data members.
+  vtable_elt method[1];
+
+#ifdef __ia64__
+  void *get_method(int i) { return &method[i]; }
+  void set_method(int i, void *fptr) { method[i] = *(vtable_elt *)fptr; }
+  void *get_finalizer()
+  {
+    // We know that get_finalizer is only used for checking whether
+    // this object needs to have a finalizer registered.  So it is
+    // safe to simply return just the PC component of the vtable
+    // slot.
+    return ((vtable_elt *)(get_method(0)))->pc;
+  }
+#else
+  void *get_method(int i) { return method[i]; }
+  void set_method(int i, void *fptr) { method[i] = fptr; }
+  void *get_finalizer() { return get_method(0); }
+#endif
+
+  static size_t vtable_elt_size() { return sizeof(vtable_elt); }
+
+  // Given a method index, return byte offset from the vtable pointer.
+  static jint idx_to_offset (int index)
+  {
+    return (2 * sizeof (void *)) + (index * vtable_elt_size ());
+  }
+
+  static _Jv_VTable *new_vtable (int count);
+};
+
+#endif
+
+// Registering the JIT.
+typedef void *_Jv_JITPrepareMethodFunctionType (jclass defining,
+						unsigned char *bytecode,
+						int bytecode_len,
+						int max_stack,
+						int max_locals,
+						bool is_static,
+						const char *signature,
+						_Jv_Constants *cpool);
+typedef void *_Jv_JITGetClosureFunctionType (void *arg);
+
+extern void _Jv_JITRegister (_Jv_JITPrepareMethodFunctionType *,
+			     _Jv_JITGetClosureFunctionType *);
+
+#endif // __GCJ_JITAPI_H__
Index: gcj/Makefile.am
===================================================================
--- gcj/Makefile.am	(revision 112723)
+++ gcj/Makefile.am	(working copy)
@@ -9,7 +9,7 @@
 target_noncanonical = @target_noncanonical@
 
 gcjdir = $(gxx_include_dir)/gcj
-gcj_HEADERS = array.h cni.h field.h javaprims.h method.h
+gcj_HEADERS = array.h cni.h field.h javaprims.h method.h jitapi.h
 
 tool_include_dir := $(libdir)/gcc/$(target_noncanonical)/$(gcc_version)/include
 toolgcjdir       := $(tool_include_dir)/gcj
Index: prims.cc
===================================================================
--- prims.cc	(revision 112723)
+++ prims.cc	(working copy)
@@ -26,6 +26,7 @@
 #include <java-signal.h>
 #include <java-threads.h>
 #include <java-interp.h>
+#include <gcj/jitapi.h>
 
 #ifdef ENABLE_JVMPI
 #include <jvmpi.h>
@@ -1715,3 +1716,33 @@
 	      && _Jv_ClassNameSamePackage (self_klass->name,
 					   other_klass->name)));
 }
+
+
+
+// Wrappers for use by JITs.
+
+int
+_Jv_GetArrayOffsetOfLength (jclass element_type)
+{
+  return (int) _Jv_GetArrayElementFromElementType (NULL, element_type);
+}
+
+// A JIT can only need to resolve a pool entry to a pointer.
+// Non-pointer-valued pool entries don't need resolution.
+void *
+_Jv_JITResolvePoolEntry (jclass klass, int index)
+{
+  return _Jv_Linker::resolve_pool_entry (klass, index, false).p;
+}
+
+int
+_Jv_GetResolvedMethodVtableIndex (_Jv_ResolvedMethod *meth)
+{
+  return meth->vtable_index;
+}
+
+_Jv_Method *
+_Jv_GetResolvedMethodMethod (_Jv_ResolvedMethod *meth)
+{
+  return meth->method;
+}


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