This is the mail archive of the
java-patches@gcc.gnu.org
mailing list for the Java project.
Re: Two JITs for libgcj
- From: Tom Tromey <tromey at redhat dot com>
- To: Java Patch List <java-patches at gcc dot gnu dot org>
- Date: 18 Apr 2006 12:34:14 -0600
- Subject: Re: Two JITs for libgcj
- References: <m3mzekqheu.fsf@localhost.localdomain>
- Reply-to: tromey at redhat dot com
>>>>> "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;
+}